cerberauth/reportx
GitHub: cerberauth/reportx
一个 Go 库,用于将各类 DAST 工具的原始扫描发现转换为标准化的多格式安全报告,并提供去重、CWE 增强和 CVSS 评分能力。
Stars: 0 | Forks: 0
# reportx
一个 Go 库,用于将原始 DAST 工具的发现结果转换为标准化的报告输出。
可将其导入 OWASP ZAP 封装器、Nuclei 后处理器或自定义扫描器中。
## 安装
```
go get github.com/cerberauth/reportx
```
## 快速开始
```
package main
import (
"log"
"os"
"github.com/cerberauth/reportx"
"github.com/cerberauth/reportx/format"
)
func main() {
findings := []reportx.Finding{
{
Title: "SQL Injection",
Severity: reportx.SeverityCritical,
CWEID: "CWE-89",
URL: "https://api.example.com/users",
Parameter: "id",
Description: "User-controlled input passed to SQL query.",
Remediation: "Use parameterized queries.",
Status: reportx.StatusActive,
},
}
report, err := reportx.NewBuilder().
Tool("MyScanner", "1.0.0").
Target("https://api.example.com").
Title("Nightly scan").
Findings(findings).
Enrich(). // auto-fill CWEName + OwaspTop10
Deduplicate(). // compute + apply fingerprints
Build()
if err != nil {
log.Fatal(err)
}
data, err := format.NewSARIFFormatter().Format(report)
if err != nil {
log.Fatal(err)
}
os.Stdout.Write(data)
}
```
## 格式化器
| 格式 | MediaType | FileExtension | 最适用场景 |
|--------|-----------|---------------|---------------|
| JSON | `application/json` | `.json` | REST API、仪表盘 |
| JSONL | `application/x-ndjson` | `.jsonl` | 流式 pipeline、`jq` |
| SARIF | `application/sarif+json` | `.sarif.json` | GitHub 代码扫描、IDE |
| Markdown | `text/markdown` | `.md` | PR 评论、维基 |
| HTML | `text/html` | `.html` | 独立报告、电子邮件 |
### JSON
```
data, err := format.NewJSONFormatter().Format(report)
// Writes: { "metadata": {...}, "findings": [...] }
```
### JSONL
```
data, err := format.NewJSONLFormatter().Format(report)
// One JSON object per line — pipe to jq or a SIEM
```
### SARIF
```
data, err := format.NewSARIFFormatter().Format(report)
// Valid SARIF 2.1.0 — upload to GitHub Code Scanning
```
### Markdown
```
data, err := format.NewMarkdownFormatter().Format(report)
// Post as a PR comment or embed in a wiki page
```
### HTML
```
data, err := format.NewHTMLFormatter().Format(report)
// Self-contained HTML file — no external CSS or JS
// Includes print stylesheet for clean PDF export
```
### 写入文件
```
err := report.WriteToFile("report.sarif.json", format.NewSARIFFormatter())
```
### 写入任意 io.Writer
```
err := report.WriteTo(os.Stdout, format.NewJSONFormatter())
```
## CVSS 评分
`score` 子包根据向量字符串计算 CVSS 基础分数。
### CVSS 3.1
```
import "github.com/cerberauth/reportx/score"
s, err := score.CalculateV31("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
// s = 9.8
severity := score.Label(s) // reportx.SeverityCritical
```
### CVSS 4.0
```
s, err := score.CalculateV40("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H")
// s = 10.0
```
## 去重
`Builder.Deduplicate()` 会为每个发现结果计算稳定的 SHA-256 指纹并丢弃重复项,默认保留按索引排序时的首次出现项。
**指纹输入**(全部归一化为小写):
- `CWEID` — 例如 `cwe-89`
- `URL` — scheme + host + path,不包含查询字符串或 fragment,无尾随斜杠
- `Parameter` — 去除首尾空格
只要两个发现结果具有相同的 CWE、endpoint 和 parameter,无论其 title、description 或 evidence 如何,均视为重复项。
如果你的扫描器已经进行了去重,或者你故意希望每个 endpoint 有多个发现结果,可以选择**禁用此功能**:
```
report, err := reportx.NewBuilder().
Findings(findings).
// no .Deduplicate() call
Build()
```
## CWE 增强
`Builder.Enrich()` 从内嵌的 CWE 数据库中填充 `Finding.CWEName` 和 `Finding.OwaspTop10`(无需网络调用)。它涵盖了 20 种常见的 Web 漏洞,包括 CWE-89、CWE-79、CWE-22、CWE-352、CWE-918 等。
当 `Finding.CWEID` 为空或未知时,增强操作不会执行任何动作——它绝不会因为数据缺失而返回错误。
你也可以直接对发现结果进行增强:
```
import "github.com/cerberauth/reportx/enrich"
enriched := enrich.EnrichAll(findings) // returns new slice, original unchanged
```
## 证据
使用 `evidence` 子包将证据附加到任何发现结果中。内置两种类型:
```
import "github.com/cerberauth/reportx/evidence"
// HTTP request/response
finding.Evidence = &evidence.HTTPEvidence{
RequestMethod: "POST",
RequestURL: "https://api.example.com/login",
ResponseStatus: 500,
RequestBody: []byte(`{"username":"' OR 1=1--"}`),
ResponseBody: []byte("SQLite error: syntax error"),
}
// Any non-HTTP data
finding.Evidence = &evidence.CustomEvidence{
Data: map[string]any{
"payload": `{"__proto__":{"admin":true}}`,
"timing": "4.2s",
},
}
```
如果结构化字段不可用,`HTTPEvidence` 也接受原始字符串:
```
finding.Evidence = &evidence.HTTPEvidence{
RawRequest: "GET /users?id=1' HTTP/1.1\r\nHost: api.example.com",
RawResponse: "HTTP/1.1 500 Internal Server Error\r\n\r\nSQLite error: syntax error",
}
```
在任何 struct 上实现 `IsEmpty() bool` 方法,即可将其作为自定义证据类型使用。
## 扩展 reportx
实现 `format.Formatter` 接口即可添加自定义输出格式:
```
package myformat
import "github.com/cerberauth/reportx"
type CSVFormatter struct{}
func (f *CSVFormatter) Format(r *reportx.Report) ([]byte, error) {
var buf bytes.Buffer
buf.WriteString("id,title,severity,url,cwe\n")
for _, finding := range r.Findings {
fmt.Fprintf(&buf, "%s,%s,%s,%s,%s\n",
finding.ID, finding.Title, finding.Severity,
finding.URL, finding.CWEID,
)
}
return buf.Bytes(), nil
}
func (f *CSVFormatter) MediaType() string { return "text/csv" }
func (f *CSVFormatter) FileExtension() string { return ".csv" }
```
将其与任何 `Report` 结合使用:
```
data, err := new(myformat.CSVFormatter).Format(report)
```
或者直接写入文件:
```
err := report.WriteToFile("findings.csv", new(myformat.CSVFormatter))
```
## 许可证
参见 [LICENSE](LICENSE)。
标签:DAST, EVTX分析, Go库, SARIF, 安全工具链, 恶意软件分析, 日志审计, 漏洞报告, 聊天机器人