kidoz/go-vulners
GitHub: kidoz/go-vulners
Vulners 漏洞数据库 API 的 Go 客户端库,提供漏洞搜索、多平台资产审计、SBOM 分析及自动化扫描任务管理能力。
Stars: 0 | Forks: 0
# go-vulners
一个用于 [Vulners](https://vulners.com) 漏洞数据库 API 的 Go 客户端库。
[](https://github.com/kidoz/go-vulners/releases/latest)
[](https://go.dev)
[](https://pkg.go.dev/github.com/kidoz/go-vulners)
[](https://goreportcard.com/report/github.com/kidoz/go-vulners)
## 功能
- 用于 Vulners API v3/v4 搜索、审计、归档、报告、告警和 STIX endpoint 的强类型客户端
- 搜索漏洞、exploit 和安全公告
- 审计 Linux 软件包、Windows KB、软件 CPE、原始软件描述以及 SBOM 文件
- 集成 VScanner 用于漏洞扫描
- 内置速率限制及动态调整
- 带有指数退避的自动重试
- 支持用于取消和超时的 Context
- 除 Go 标准库外无其他运行时依赖
## 安装
```
go get github.com/kidoz/go-vulners
```
需要 Go 1.21 或更高版本。
## 快速开始
```
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/kidoz/go-vulners"
)
func main() {
// Create client with API key
client, err := vulners.NewClient("your-api-key")
if err != nil {
log.Fatal(err)
}
// Search for vulnerabilities
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
results, err := client.Search().SearchBulletins(ctx, "log4j", vulners.WithLimit(10))
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d results\n", results.Total)
for _, b := range results.Bulletins {
fmt.Printf(" - %s: %s\n", b.ID, b.Title)
}
}
```
## 配置选项
在带有“快速开始”中所示导入的函数内部,使用 functional options 配置客户端:
```
client, err := vulners.NewClient("your-api-key",
// Custom timeout (default: 30s)
vulners.WithTimeout(60*time.Second),
// Custom retry count (default: 3)
vulners.WithRetries(5),
// Custom rate limit (default: 5 req/s, burst 10)
vulners.WithRateLimit(10.0, 20),
// Custom User-Agent
vulners.WithUserAgent("my-app/1.0"),
// HTTP proxy
vulners.WithProxy("http://proxy.example.com:8080"),
// Custom base URL (for testing)
vulners.WithBaseURL("https://custom.vulners.com"),
)
if err != nil {
log.Fatal(err)
}
_ = client // Use the configured client to access API services.
```
## API 服务
以下服务示例是独立的函数体片段。它们假定具有“快速开始”中所示的导入、已初始化的 `client` 和 `ctx`;SBOM 示例还需要 `os`。
### 搜索服务
```
// Search bulletins with Lucene query syntax
results, err := client.Search().SearchBulletins(ctx, "CVE-2021-44228",
vulners.WithLimit(20),
vulners.WithOffset(0),
vulners.WithFields("id", "title", "cvss", "published"),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d bulletins\n", results.Total)
// Search for exploits only
exploits, err := client.Search().SearchExploits(ctx, "apache")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d exploits\n", exploits.Total)
// Get all matching exploits with pagination
allExploits, err := client.Search().SearchExploitsAll(ctx, "apache")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d exploits\n", len(allExploits))
// Get bulletin by ID
bulletin, err := client.Search().GetBulletin(ctx, "CVE-2021-44228")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Bulletin: %s\n", bulletin.Title)
// Get multiple bulletins
bulletins, err := client.Search().GetMultipleBulletins(ctx,
[]string{"CVE-2021-44228", "CVE-2021-45046"},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d bulletins\n", len(bulletins))
// Fetch bulletins and their grouped references in one request
withReferences, err := client.Search().GetMultipleBulletinsWithReferences(ctx,
[]string{"CVE-2021-44228", "CVE-2021-45046"},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d reference groups\n", len(withReferences.References))
// Search vulnerabilities associated with web paths
webVulns, err := client.Search().GetWebVulnerabilities(ctx,
[]string{"/admin", "/login"}, nil,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Matched %d paths\n", len(webVulns))
// Get all results with pagination
allBulletins, err := client.Search().SearchBulletinsAll(ctx, "type:cve",
vulners.WithLimit(1000), // max results
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d bulletins\n", len(allBulletins))
```
### 审计服务
```
// Audit Linux packages with the modern v4 endpoint
packages := []string{"glibc-common-2.17-157.el7_3.5.x86_64"}
linuxResult, err := client.Audit().LinuxAuditV4(ctx, "centos", "7", packages,
vulners.WithOSArch("x86_64"),
vulners.WithIncludeCandidates(true),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Analyzed %d packages\n", linuxResult.TotalPackages)
// Audit Windows KBs
kbList := []string{"KB5009586", "KB5009624"}
kbResult, err := client.Audit().KBAudit(ctx, "Windows Server 2012 R2", kbList)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d Windows vulnerabilities\n", len(kbResult.Vulnerabilities))
// Audit software CPEs
software := []vulners.AuditItem{
{Part: "a", Product: "apache", Version: "2.4.49"},
}
softwareResult, err := client.Audit().Software(ctx, software)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Audited %d software items\n", len(softwareResult.Items))
// Resolve free-form software descriptions and audit the matched CPEs
smartResult, err := client.Audit().SmartAudit(ctx,
[]string{"Adobe Reader 5.3", "OpenSSL 1.0.1"},
vulners.WithAuditCatalog("official"),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Smart Audit resolved %d items\n", len(smartResult.Items))
// Audit libraries using Package URLs (PURLs)
libraryResult, err := client.Audit().LibraryAudit(ctx,
[]string{"pkg:golang/golang.org/x/text@v0.3.0"},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Analyzed %d library packages\n", libraryResult.TotalPackages)
// Find package and CPE definitions affected by CVEs
cveResult, err := client.Audit().CVEAudit(ctx, "CVE-2021-44228")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Audited %s\n", cveResult.CVE)
cveResults, err := client.Audit().CVEBatchAudit(ctx,
[]string{"CVE-2021-44228", "CVE-2021-45046"},
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Audited %d CVEs\n", len(cveResults))
// Audit an SBOM file (SPDX or CycloneDX JSON)
f, err := os.Open("sbom.spdx.json")
if err != nil {
log.Fatal(err)
}
defer func() { _ = f.Close() }()
sbomResult, err := client.Audit().SBOMAudit(ctx, f)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Analyzed %d packages\n", len(sbomResult.Packages))
```
### 归档服务
```
// Fetch entire collection
bulletins, err := client.Archive().FetchCollection(ctx, vulners.CollectionCVE)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d CVEs\n", len(bulletins))
// Fetch updates since timestamp
since := time.Now().Add(-24 * time.Hour)
updates, err := client.Archive().FetchCollectionUpdate(ctx, vulners.CollectionCVE, since)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fetched %d CVE updates\n", len(updates))
```
### 其他服务
```
// Webhooks
webhooks, err := client.Webhook().List(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d webhooks\n", len(webhooks))
webhook, err := client.Webhook().Add(ctx, "type:cve AND cvss.score:[9 TO 10]")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created webhook %s\n", webhook.ID)
// Subscriptions
subs, err := client.Subscription().List(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d subscriptions\n", len(subs))
// STIX bundles
bundle, err := client.Stix().MakeBundleByID(ctx, "CVE-2021-44228")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created bundle %s\n", bundle.ID)
// Reports
summary, err := client.Report().VulnsSummaryReport(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d vulnerabilities\n", summary.Total)
// Misc
cpes, err := client.Misc().SearchCPE(ctx, "chrome", "google")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d CPEs\n", len(cpes.CPEs))
suggestions, err := client.Misc().QueryAutocomplete(ctx, "log4")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d suggestions\n", len(suggestions))
```
## VScanner 客户端
如需进行漏洞扫描,请导入 `github.com/kidoz/go-vulners/vscanner`。以下是一个函数体片段,假定已初始化 `ctx` 并且导入了 `fmt` 和 `log`:
```
client, err := vscanner.NewClient("your-api-key")
if err != nil {
log.Fatal(err)
}
// Licenses (a license id is required to create a project)
licenses, err := client.GetLicenses(ctx)
if err != nil {
log.Fatal(err)
}
if len(licenses) == 0 {
log.Fatal("no VScanner licenses available")
}
// List projects
projects, err := client.Project().List(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d projects\n", len(projects))
// Create a project
project, err := client.Project().Create(ctx, &vscanner.ProjectRequest{
Name: "My Project",
LicenseID: licenses[0].ID,
Notification: vscanner.DisabledNotification(),
})
if err != nil {
log.Fatal(err)
}
// Create and run a task (schedule is a crontab string)
task, err := client.Task().Create(ctx, project.ID, &vscanner.TaskRequest{
Name: "Scan Task",
Networks: []string{"192.168.1.0/24"},
Ports: []string{"1-1000"},
Schedule: "0 2 * * *",
Timing: "normal",
Enabled: true,
})
if err != nil {
log.Fatal(err)
}
task, err = client.Task().Start(ctx, project.ID, task.ID)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Started task %s\n", task.ID)
// Get results and project statistics
results, err := client.Result().List(ctx, project.ID)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d results\n", len(results))
stats, err := client.Project().GetStatistics(ctx, project.ID, vscanner.StatTotalHosts)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Total hosts: %s\n", stats[vscanner.StatTotalHosts])
```
## 错误处理
给定一个已初始化的 `client` 和 `ctx`,使用 `errors` 检查 sentinel 错误和结构化 API 错误:
```
result, err := client.Search().GetBulletin(ctx, "NONEXISTENT-CVE")
if err != nil {
// Check for specific error types
if errors.Is(err, vulners.ErrNotFound) {
fmt.Println("Bulletin not found")
} else if errors.Is(err, vulners.ErrRateLimited) {
fmt.Println("Rate limit exceeded, retry later")
} else if errors.Is(err, vulners.ErrUnauthorized) {
fmt.Println("Invalid API key")
} else {
// Check for API errors with status codes
var apiErr *vulners.APIError
if errors.As(err, &apiErr) {
fmt.Printf("API error %d: %s\n", apiErr.StatusCode, apiErr.Message)
}
}
} else {
fmt.Printf("Bulletin: %s - %s\n", result.ID, result.Title)
}
```
## 速率限制
客户端包含内置的速率限制,具有以下特性:
- 默认为 5 个请求/秒,突发为 10
- 根据 `X-Vulners-Ratelimit-Reqlimit` 响应头自动调整
- 支持在速率限制等待期间取消 Context
## 测试
```
# 运行 unit tests
go test ./...
# 运行 integration tests(需要 API key)
VULNERS_API_KEY=your-key go test -tags=integration -v ./...
```
## 许可证
MIT 许可证 - 详情请参阅 [LICENSE](LICENSE)。
## 贡献
欢迎贡献!请 open 一个 issue 或提交一个 pull request。
## 链接
- [Vulners API 文档](https://docs.vulners.com/docs/api/)
- [Vulners 网站](https://vulners.com)
标签:API客户端, EVTX分析, Go, Ruby工具, SBOM, 日志审计, 漏洞查询, 硬件无关