abidranesh/AI-powered_cyber_risk_assistant
GitHub: abidranesh/AI-powered_cyber_risk_assistant
一款将资产、漏洞、威胁情报等多源 CSV 数据与实时 KEV 目录、NIST 控制库及 LLM 结合,自动计算加权风险评分并生成分析师简报的 AI 网络风险评分工具。
Stars: 0 | Forks: 0
# AI 驱动的网络风险助手
一款为 TawasolPay 构建的风险评分与分析工具。它从 CSV 文件中读取资产、漏洞和威胁情报数据,为每个漏洞计算加权风险评分,交叉比对实时的 CISA KEV 目录,通过语义搜索检索最相关的 NIST SP 800-53 控制,然后要求 LLM 为前 5 大风险分别撰写一份简短的分析师简报。它同时包含一个 CLI pipeline 和一个带有浏览器仪表板的 FastAPI 后端。
## 如何在本地运行
**安装依赖**
```
pip install -r requirements.txt
```
首次运行时,FastEmbed 会下载 `BAAI/bge-small-en-v1.5` embedding 模型(约 50MB)并在本地缓存。这是一次性的操作。
**设置你的 API key**
在项目根目录下创建一个 `.env` 文件:
```
GROQ_API_KEY=your_key_here
```
在 https://console.groq.com 获取免费 key。免费额度对于开发来说绰绰有余——相比于使用 Gemini 可能遇到的限制,Groq 的速率限制非常慷慨。
**运行 CLI pipeline**
```
python main.py
```
这会从 `chroma_db/` 加载预构建的 NIST 向量数据库,从 `data/` 读取 CSV 文件,通过 HTTP 实时获取 CISA KEV 目录,计算风险评分,通过语义搜索检索 NIST 控制,通过 Groq 生成 LLM 摘要,并将输出写入 `risk_report.md`。前 5 大风险也会以格式化表格的形式打印到终端。
**运行 API 服务器和仪表板**
```
uvicorn api_server:app --reload --port 8000
```
然后在浏览器中打开 `http://localhost:8000`。`index.html` 仪表板会自动提供服务。API 会在启动时的后台线程中加载 NIST 向量数据库,因此对 `/api/risks` 的首次请求不会被阻塞——你会立即获得风险评分,而 NIST/LLM 的补充内容会在向量数据库准备就绪后填充进来。
**健康检查**
```
GET http://localhost:8000/health
```
返回风险引擎、RAG pipeline 和 Groq key 是否全部就绪。
**重建向量数据库**
`chroma_db/` 目录已经提交到仓库中,因此你无需重建它。如果你删除了它,`main.py` 会在下次运行时自动从 `data/nist_controls.csv` 重建。构建过程会对 embedding 请求进行批量处理,并在批次之间设置短暂延迟,以保持在速率限制之内(这最初是为 Gemini 的免费额度编写的——在本地运行 FastEmbed 实际上没有任何限制,但批处理逻辑仍然保留着,并无害处)。
## 项目结构
```
main.py CLI: score → NIST retrieval → LLM → risk_report.md
api_server.py FastAPI backend, port 8000, serves index.html + /api/risks
risk_engine.py DataLoader, ThreatIntelProcessor, RiskScorer classes
rag_pipeline.py Build/load Chroma vector store, retrieve NIST controls
llm_summariser.py LangChain LCEL chain backed by Groq (llama-3.1-8b-instant)
index.html Browser dashboard
data/
assets.csv Asset inventory: type, exposure, criticality, EDR status
vulnerabilities.csv CVEs per asset with CVSS, patch status, exploit availability
threat_intelligence.csv Threat actor campaigns mapped to CVE IDs
business_services.csv Services with compliance scope, business impact, RTO
nist_controls.csv NIST SP 800-53 rev5 catalog (~2,600 controls)
remediation_guidance.csv Finding-type-to-action lookup table
chroma_db/ Persisted ChromaDB vector store (committed; no rebuild needed)
docs/ Sample generated reports
```
## 开发过程中的变动
第一个版本直接调用 Gemini 的 API——仅仅使用了 SDK,没有抽象层。对于小型项目来说这没问题,但当我需要按顺序执行 prompt template、embedding 调用和向量数据库检索时,这些胶水代码变得混乱,并且与单一提供商紧密耦合。引入 LangChain 解决了这个问题。PromptTemplate 和 LCEL chaining 以一种可读的 pipeline 处理 prompt 构建和模型调用,Chroma wrapper 抽象了向量数据库操作,现在替换组件只需修改一行代码,而无需重写。
这种替换在引入 LangChain 后几乎立即发生了。我最初在 embedding 和 LLM 调用中都使用 Gemini,但其免费额度的速率限制让测试变得非常痛苦——仅 embedding 步骤在对约 2,600 个 NIST 控制进行批量索引时,就不断触发 429 错误并迫使进行长时间等待。我将 LLM 切换到了 Groq (llama-3.1-8b-instant),它的免费配额更高,推理速度也更快。对于 embedding,我切换到了 FastEmbed,它完全在进程内运行 `BAAI/bge-small-en-v1.5` 模型。无需 API key,没有配额限制,也没有单次请求成本。NIST 目录足够庞大,从 embedding 步骤中消除速率限制的担忧带来了实质性的改变。
## 补充说明问题
### 我 embedding 了哪些数据,哪些作为结构化记录进行查询?
进入向量数据库的唯一数据是 `nist_controls.csv`——NIST SP 800-53 rev5 控制目录。每一行都是几段密集的策略文本:控制声明、补充指南和讨论文本。你无法对此进行精确匹配查找。面对类似“与勒索软件活动相关的、互联网暴露的 VPN 设备上未经身份验证的 RCE”这样的风险上下文,没有可以过滤的列——你需要语义搜索来找出 SI-2(缺陷修复)或 RA-5(漏洞监控和扫描)才是正确的控制。数据的文本性质,加上需要将其与自由格式的漏洞描述进行匹配,正是 embedding 的设计初衷。
其他所有内容——资产、漏洞、威胁情报、业务服务——都保留为 CSV 格式,并通过 pandas 合并和条件逻辑进行查询。这些是具有明确定义外键的表格记录:`asset_id`、`business_service`、`matched_cve_or_control`。你对它们提出的问题是精确的:这个 CVE 是否出现在 KEV 目录中?这个资产是否暴露在互联网上?这个威胁参与者的活动是否与这个 CVE 匹配?LangChain 在这里发挥不了作用。对于具有已知键的结构化数据,连接(join)和集合查找(set lookup)才是正确的工具。
### 哪里会出问题?
**1. 合成 CVE ID 静默地无法获得 KEV 评分。**
漏洞 CSV 使用诸如 `CVE-SYN-2026-0001` 之类的标识符,这些标识符在真实的 CISA KEV 订阅源中并不存在。评分逻辑在每次运行时都会获取实时的 KEV 目录并检查匹配——但对于合成 ID,这些检查将始终返回 False。`in_kev` 标志保持为 False,且 `cisa_kev_ransomware_score`(+10 分)永远不会触发,也没有任何警告。在生产环境中,只有当漏洞 CSV 包含真实的 CVE ID 时才能正确体现这一点,而目前没有验证步骤来检查是否有任何 CVE 实际匹配了 KEV,或者标记出可疑的空结果。一个简单的检查——如果 N 个 CVE 中有零个匹配到实时 KEV,则记录警告——就能使这种失败变得可见,而不是静默的。
**2. 无论匹配度如何,NIST 检索都会返回结果。**
`retrieve_nist_control` 总是返回 top-1 向量相似度结果,即使评分很低也是如此。这里没有相关性阈值——如果查询含糊不清,或者漏洞在 NIST 目录中没有相近的对应项,该函数仍然会返回一个控制,而 LLM 依然会基于此写出一篇听起来很自信的 3-4 句分析。微弱的语义匹配会产生听起来合理但可能错误的修复建议。修复方法很简单:使用 `similarity_search_with_score` 而不是 `similarity_search`,并在最佳匹配低于定义的距离阈值时跳过 LLM 的补充处理。目前,这种检查在 pipeline 的任何地方都不存在。
**3. 多行为者威胁情报会合并为每个 CVE 一条记录。**
`ThreatIntelProcessor.aggregate_by_cve` 按 CVE 对威胁情报进行分组,并且每个 CVE 仅保留单行置信度最高的记录。如果两个不同的威胁参与者都在积极利用同一个漏洞——这对于任何广泛发布的 CVE 来说都是现实的——那么合并后的风险记录中只会包含一个参与者。风险评分只会获得一次 `threat_actor_present_score`(+15 分),但实际的威胁情况要严重得多。评分没有考虑到多个已确认的参与者,并且即使存在多个参与者,LLM 的简报中也只会提到一个威胁参与者。保留每个 CVE 的所有匹配参与者(作为列表),并针对每个额外确认的参与者增加少量评分,将使其更加准确。
### 我会改变什么?
最大的缺陷在于一切都是基于静态 CSV 快照运行的。在一个真实的组织中,数据不是静止不动的——每天都有新的 CVE 发布,资产不断出现和消失,威胁情报持续更新,CISA 每隔一两周就会添加新的 KEV 条目。现在,风险评分改变的唯一方式是有人手动重新运行脚本。系统应该监控有意义的变化并自动重新评分:一个计划任务或事件驱动的触发器,用于检测 KEV 订阅源何时出现新条目、漏洞扫描器何时导出新的结果,或者威胁情报何时更新。一种轻量级的方法是在每次运行时对输入的 CSV 行进行哈希处理,仅针对实际发生变化的记录重新生成 LLM 摘要,从而避免不必要的 API 调用。然后,报告层可以显示“自上次运行以来已更改”的指示器,以便分析师立即看到新内容,而不必将两份报告并排进行比较。如果没有这一点,该系统只是一个快照工具,而不是一个监控工具——它对于特定时间点的报告很有用,但对于捕捉刚刚新出现的威胁参与者或刚刚发布的 KEV 条目,则是不值得信赖的。
标签:AES-256, AI辅助, AV绕过, FastAPI, 向量检索, 安全合规, 漏洞评估, 网络代理, 逆向工具