
开源地址:👉GitCode(国内友好)👈、👉GitHub👈
体验地址:小程序搜索CVE漏洞检索工具

初衷
转岗到网络安全后,我发现手机上没有专门用于漏洞信息查询的工具,至少在微信小程序这块没有。于是迸发了做一个的念头,也方便自己日常使用。
漏洞信息更新
首先,要感谢国家信息安全漏洞库免费的数据公开,给广大的网络安全工作人员提供了漏洞查询服务👍。
这里我们也是通过国家信息安全漏洞库平台提供的数据服务,构建自己的漏洞信息库。
历史数据导入


上图是我从官网下载的 XML 数据,我的笔记本配置如下:
| 项目 | 值 |
|---|---|
| 处理器 | 11th Gen Intel® Core™ i5-11300H @ 3.10GHz (3.11 GHz) |
| 机带 RAM | 16.0 GB (15.8 GB 可用) |

对这251 MB 数据进行解析入库,资源占用很夸张,耗时 1358.14 秒(约23分钟),最终的 SQLite 数据文件有 180 MB。

增量数据更新
官网可以查看最新收录的漏洞信息。

获取清单的 fetch 代码如下:
js
fetch("https://www.cnnvd.org.cn/web/homePage/cnnvdVulList", {
"headers": {
"accept": "application/json, text/plain, */*",
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,es;q=0.7",
"content-type": "application/json;charset=UTF-8",
"sec-ch-ua": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": "\"Windows\"",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin"
},
"referrer": "https://www.cnnvd.org.cn/home/loophole",
"body": "{\"pageIndex\":1,\"pageSize\":50,\"keyword\":\"\",\"hazardLevel\":\"\",\"vulType\":\"\",\"vendor\":\"\",\"product\":\"\",\"dateType\":\"\"}",
"method": "POST",
"mode": "cors",
"credentials": "omit"
});
我们的思路:
- 每日凌晨6点开始执行刷新任务;
- 获取前N日(默认为3)的最新漏洞信息;
- 将未入库的漏洞信息保存起来。
完整的数据获取代码:
js
/**
*
* 从官网获取指定条件的漏洞信息并入库
* @param {Object} conditions 查询条件
* {
"pageIndex": 1,
"pageSize": 10,
"keyword": "",
"hazardLevel": "",
"vulType": "",
"vendor": "",
"product": "",
"dateType": "",
"beginpublishTime": "",
"endpublishTime": ""
}
* @param {Number} pageIndex 页码
* @param {Boolean} forceUpdate 强制刷新
*/
export const fetchVulnList = async (conditions, pageIndex=1, forceUpdate=false)=>{
logger.debug(`获取条件 ${JSON.stringify(conditions)} 的漏洞信息...`)
const method = 'POST'
const pageSize = 50
const today = date()
/**
* 返回结果示例
{
id: "d0a2ae627d4248e3bd1da952b93b8e5e",
vulName: "WordPress plugin MTCaptcha 跨站请求伪造漏洞",
cnnvdCode: "CNNVD-202601-1335",
cveCode: "CVE-2025-13520",
hazardLevel: 3,
createTime: "2026-01-08",
publishTime: "2026-01-07",
updateTime: "2026-01-08",
typeName: null,
vulType: "0",
}
*/
const resp = await fetch({
url: `https://www.cnnvd.org.cn/web/homePage/cnnvdVulList`,
body: JSON.stringify(Object.assign({}, conditions, { pageIndex, pageSize })),
headers,
method
})
if(resp.status != 200){
logger.error(`获取漏洞列表失败`, resp.statusText)
return
}
const body = await resp.json()
for(const bean of body.data.records){
let cnnvdId = bean['cnnvdCode']
const isExist = existCheck(cnnvdId, true)
if(!forceUpdate && isExist){
logger.debug(`${cnnvdId} 已存在,跳过...`)
continue
}
/**@type {import("../beans").VulnerabilityType} */
const vul = { cnnvdId }
vul.cveId = bean['cveCode']
vul.name = bean['vulName']
vul.published = bean['publishTime']
vul.severity = LEVELS[bean['hazardLevel']]
vul.updated = today
//额外获取的数据
const detailResp = await fetch({
url:`https://www.cnnvd.org.cn/web/cnnvdVul/getCnnnvdDetailOnDatasource`,
body: JSON.stringify({
"id": bean.id,
"vulType": bean.vulType,
"cnnvdCode": bean['cnnvdCode']
}),
headers,
method
})
if(detailResp.status == 200){
const detailBody = await detailResp.json()
let { cnnvdDetail } = detailBody.data
vul.desc = cnnvdDetail.vulDesc
vul.type = cnnvdDetail.vulType
//厂商
vul.vendor = cnnvdDetail.affectedVendor
vul.source = cnnvdDetail.referUrl
vul.solution = cnnvdDetail.patch
}
logger.debug(`${!isExist?"新增":"更新"} ${vul.cveId}\t${vul.cnnvdId}\t${vul.published}\t${vul.name}`)
if(isExist){
//更新重要字段即可
exec(
`UPDATE ${VULN} SET vendor=?,source=?,solution=?,${SEVERITY}=? WHERE ${CNNVD_ID}=?`,
vul.vendor,
vul.source,
vul.solution,
vul.severity,
vul.cnnvdId
)
}
else
insertNew(VULN, vul)
}
if(body.data.total > pageIndex * pageSize){
logger.debug(`即将开始获取第${pageIndex+1}页(总数据量 ${body.data.total})`)
//继续下一页
await Bun.sleep(5000)
await fetchVulnList(conditions, pageIndex + 1)
}
}
如何调用?
js
/**
* 从官网获取指定日期发布的漏洞信息并入库
* @param {String} day
*/
export const fetchSpecialDays = async (day=addDay(-1), endTime)=>{
logger.debug(`获取 ${day}${endTime?`(至${endTime})`:""} 发布的漏洞信息...`)
await fetchVulnList({
beginTime: day,
dateType: "publishTime",
endTime: endTime || day,
})
}
export const fetchPreDays = async (step=3)=>{
await fetchVulnList({
beginTime: addDay(-1 * step),
dateType: "publishTime",
endTime: date(),
})
}
/**
* 刷新指定ID的漏洞数据
* @param {String} keyword
*/
export const fetchSpecialId = async keyword =>{
await fetchVulnList({ keyword }, 1, true)
}