shlin168/go-nvd
GitHub: shlin168/go-nvd
go-nvd 是一个将 NVD 的 CVE/CPE 数据转储到本地数据库并提供与官方 API 规范兼容的查询服务的 Go 工具,旨在解决 NVD API 速率限制下无法支持高并发查询的问题。
Stars: 13 | Forks: 2
# go-nvd
[](https://github.com/shlin168/go-nvd/actions/workflows/go.yml)
NVD 官方提供了 [CPE](https://nvd.nist.gov/developers/products) 和 [CVE](https://nvd.nist.gov/developers/vulnerabilities) 的 API,两者都有[速率限制](https://nvd.nist.gov/general/news/API-Key-Announcement)。
为了支持高并发查询,`go-nvd` 提供了将 NVD 数据转储到自有数据库并在其上运行 API 服务器的命令,提供与 NVD 相同的 API 规范和部分参数。
**支持的数据库:**
- MongoDB
```
API DB (nvd)
┌────────────────┐ ┌───────────┐
http │ ┌────────────┐ │ │ ┌───────┐ │ nvdetl
req ———▶ │ │ (get) cve │-│- - - —▶ │ │ cve │ │ (command) ┌───────┐
│ └────────────┘ │ │ └───────┘ │ ◀────────── │ NVD │
http │ ┌────────────┐ │ │ ┌───────┐ │ └───────┘
rsp ◀─── │ │ (get) cpe │-│- - - —▶ │ │ cpe │ │
│ └────────────┘ │ │ └───────┘ │
└────────────────┘ └───────────┘
- - —▶ read
—————▶ write / data flow
```
要使用 Docker 进行尝试,请查看 [playground](#playground) 部分。
## 注意事项
与官方 NVD API 相比,`go-nvd` 库具有一些显著的特点:
- **仅支持部分查询参数:**
- **CVE**:`cveId`、`cpeName`、`keywordSearch`(`keywordExactMatch`)、`resultsPerPage`(默认值:`2000`)和 `startIndex`
- **CPE**:`cpeName`、`cpeMatchString`、`keywordSearch`(`keywordExactMatch`)、`resultsPerPage`(默认值:`10000`)和 `startIndex`
- **强制查询参数:** 在查询字符串中必须至少提供一个查询参数,而官方 NVD API 在未提供参数时会返回所有 CVE/CPE。
- **CVE**:必须提供 `cveId`、`cpeName` 或 `keywordSearch` 之一,否则会引发 `400` 错误
- **CPE**:必须提供 `cpeName`、`cpeMatchString` 或 `keywordSearch` 之一,否则会引发 `400` 错误
- **不同的 CPE 版本匹配逻辑**,可能会导致不同的结果:
- 例如,当查询版本介于 `apache:http_server:2.0.0` 和 `apache:http_server:2.0.44` 之间时,应该返回 `CVE-2003-0132`。但是,它应该与部分版本 `apache:http_server:2.0` 匹配吗?NVD 不会返回它,而本仓库将 `2.0` 视为 `2.0.0` 并返回 `CVE-2003-0132`。
## 数据库
详情请查看 [db.md](docs/db.md)。
## ETL
详情请查看 [nvd.md](docs/nvd.md):
- [`nvdetl`](docs/nvd.md#usage):如何使用该命令将数据转储到数据库
- [从头开始 ETL](docs/nvd.md#etl-from-the-start):如何按正确的顺序将所有数据从 NVD 转储到数据库
## API
**就绪端点:** `nvd/v1/readiness`
### GET: `/nvd/v1/cve`
此 API 模拟了 [NVD CVE API](https://nvd.nist.gov/developers/vulnerabilities),实现了查询字符串中 `cveId`、`cpeName`、`keywordSearch`(`keywordExactMatch`)、`resultsPerPage`(默认值:`2000`)和 `startIndex` 的逻辑。响应格式与官方 NVD API 相同。
**查询示例:**
- 通过 `cveId` 查询:`/nvd/v1/cve?cveId=CVE-2006-3240`
- 通过 `cpeName` 查询:`/nvd/v1/cve?cpeName=cpe:2.3:a:dotproject:dotproject:*:*:*:*:*:*:*:*`
- 通过 `keywordSearch` 查询:`/nvd/v1/cve?keywordSearch=Java Oracle`
- 精确匹配:`/nvd/v1/cve?keywordSearch=Java Oracle&keywordExactMatch`
**响应格式(200 - 找到):** 与 [NVD](https://csrc.nist.gov/schema/nvd/api/2.0/cve_api_json_2.0.schema) 格式相同
```
{
"resultsPerPage": 1,
"startIndex": 0,
"totalResults": 1,
"format": "NVD_CVE",
"version": "2.0",
"timestamp": "2022-12-28T15:01:34.530",
"vulnerabilities": [...], // CVE list
}
```
**响应格式(200 - 未找到):**
```
{
"resultsPerPage": 0,
"startIndex": 0,
"totalResults": 0,
"format": "NVD_CVE",
"version": "2.0",
"timestamp": "2022-12-28T15:01:34.530",
"vulnerabilities": [], // CVE list
}
```
### GET: `/nvd/v1/cpe`
此 API 模拟了 [NVD CPE API](https://nvd.nist.gov/developers/products),实现了查询字符串中 `cpeName`、`cpeMatchString`、`keywordSearch`(`keywordExactMatch`)、`resultsPerPage`(默认值:`10000`)和 `startIndex` 的逻辑。响应格式与官方 NVD API 相同。
**查询示例:**
- 通过 `cpeName` 查询:`/nvd/v1/cpe?cpeName=cpe:2.3:a:dotproject:dotproject:*:*:*:*:*:*:*:*`
- 通过 `cpeMatchString` 查询:`/nvd/v1/cpe?cpeMatchString=cpe:2.3:o:microsoft:windows_10`
- 通过 `keywordSearch` 查询:`/nvd/v1/cpe?keywordSearch=Java Oracle`
- 精确匹配:`/nvd/v1/cpe?keywordSearch=Java Oracle&keywordExactMatch`
**响应格式(200 - 找到):** 与 [NVD](https://csrc.nist.gov/schema/nvd/api/2.0/cpe_api_json_2.0.schema) 格式相同
```
{
"resultsPerPage": 1,
"startIndex": 0,
"totalResults": 1,
"format": "NVD_CPE",
"version": "2.0",
"timestamp": "2022-12-28T15:01:34.530",
"products": [...], // CPE list
}
```
**响应格式(200 - 未找到):**
```
{
"resultsPerPage": 0,
"startIndex": 0,
"totalResults": 0,
"format": "NVD_CPE",
"version": "2.0",
"timestamp": "2022-12-28T15:01:34.530",
"products": [], // CPE list
}
```
## 指标
### 服务器
#### HTTP 请求
- `http_request_total{api=...,code=...}`(计数器):每个 HTTP 状态码的请求数
- `api` 包括:
- `/nvd/v1/cve`
- `/nvd/v1/cpe`
- `http_request_duration_seconds`(直方图):请求延迟的直方图
#### 服务
- `get_request_total{api=...,status=...}`(计数器):获取扫描报告和状态的请求数
- `api` 包括:
- `/cve`
- `/cpe`
- `status` 包括:
- `found`
- `not_found`
- `error`
# Playground
### 1. 构建 `nvd-tools` 镜像
```
cd go-nvd
GOOS=linux go build -o service/build/bin/ ./...
cd service/build
docker build -t nvd-tools .
```
### 2. 以 MongoDB 作为后端数据库启动
查看 [端点](./docs/service.md#endpoints) 了解所有暴露的端口。
#### MongoDB
```
cd service/test
docker-compose -f docker-compose-mongo.yaml up -d
```
### 3. 将示例数据转储到数据库
查看 [用法](./docs/nvd.md#usage) 了解 `nvdetl` 命令的用法:
- `-apikey`:如果提供,则使用 API key 查询 NVD
- `-wait`:每次向 NVD 发送 API 请求之间的休眠时间
#### MongoDB
```
# 导出 lastModified 在 2023-03-01 和 2023-03-02 之间的 CVE
docker run --rm --network go-nvd --entrypoint nvdetl nvd-tools \
-db-type mongo -db-user admin -db-pwd admin -db-endpoint mongo:27017 \
-sdate 2023-03-01 -edate 2023-03-02 -batch 100 -type cve
# 导出 lastModified 在 2023-03-01 和 2023-03-02 之间的 CPE
docker run --rm --network go-nvd --entrypoint nvdetl nvd-tools \
-db-type mongo -db-user admin -db-pwd admin -db-endpoint mongo:27017 \
-sdate 2023-03-01 -edate 2023-03-02 -batch 100 -type cpe
```
### 4. 测试 API 端点
#### CVE API
```
curl 'http://localhost:8080/nvd/v1/cve?cveId=CVE-2022-26579'
```
#### CPE API
```
curl 'http://localhost:8080/nvd/v1/cpe?cpeName=cpe:2.3:a:luya:yii-helpers:1.0.0:*:*:*:*:*:*:*'
```
标签:API服务, CVE, EVTX分析, Go, MongoDB, NVD, Ruby工具, 数字签名, 数据同步, 日志审计, 自定义请求头, 请求拦截