jkwebsec/NexL-CodingBlocks-Assignments-2
GitHub: jkwebsec/NexL-CodingBlocks-Assignments-2
面向网络安全威胁情报的 AI 语义搜索引擎,利用向量检索取代关键词匹配,解决安全领域术语差异导致的检索遗漏问题。
Stars: 0 | Forks: 0
# NexL
### 面向网络安全情报的 AI 驱动语义搜索引擎
*因为威胁情报没时间去猜关键词。*
[](https://www.python.org/)
[](https://www.sbert.net/)
[](https://faiss.ai/)
[](https://gradio.app/)
[](https://www.kaggle.com/)
## 简介
网络安全分析师每天都要处理海量的威胁情报——CVE、MITRE ATT&CK 技术、事件报告、红队发现、供应商公告。常见的工作流程是关键词搜索:你输入一个词,就会得到包含该词的文档。问题在于?威胁行为者命名技术的方式与你的数据库并不相同。
**NexL** 完全围绕一个不同的理念构建。它不是在匹配字符串,而是理解*含义*。当你询问“攻击者如何绕过端点安全?”时,NexL 不会去寻找这些精确的词——它理解这个概念,并呈现出语义上最相关的文档,无论这些文档使用了“绕过”、“逃避”、“hook”、“syscall”等词,还是完全没有使用这些词。
这个名字来源于*下一层级*情报层的概念——介于原始搜索和完整的 LLM 聊天之间,专为安全工作的操作节奏而设计。
## 问题陈述
传统的基于关键词的搜索在网络安全领域失效的原因是可以预见的:该领域充斥着因供应商、框架和地区而异的技术术语。一篇关于“进程镂空”的报告和一篇关于“向挂起进程注入代码”的报告描述的是同一件事——而关键词搜索返回的重叠结果为零。
这就是 NexL 要解决的问题。
## 工作原理——架构概览
```
flowchart TD
A["📄 Cybersecurity Documents\n8 seeded entries + any PDF"] --> B["Text Extraction\nPDF parsed via pypdf\nContent columns flattened"]
B --> C["Sentence Transformer\nall-MiniLM-L6-v2\nConverts text → 384-dim vector"]
C --> D["L2 Normalization\nfaiss.normalize_L2\nPrepares for cosine similarity"]
D --> E["FAISS Index\nIndexFlatIP — Inner Product\nAll vectors stored in-memory"]
F["🔍 User Query\nFree-text or PDF-augmented"] --> G["Query Encoding\nSame model, same dimension"]
G --> H["L2 Normalization\nQuery vector normalized"]
H --> I["FAISS Search\ntop_k nearest neighbors\nby Inner Product = Cosine Sim"]
E --> I
I --> J["Ranked Results\nTitle / Category / Score / Content"]
J --> K["Gradio UI\nMarkdown output with relevance color codes"]
style A fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
style B fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style C fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style D fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style E fill:#1e1a4a,stroke:#a78bfa,color:#ede9fe
style F fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
style G fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style H fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style I fill:#1e293b,stroke:#facc15,color:#fef9c3
style J fill:#14532d,stroke:#4ade80,color:#dcfce7
style K fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
```
## 技术栈
| 组件 | 库 / 工具 | 选择原因 |
|-----------|---------------|----------------|
| **Embeddings** | `sentence-transformers` — `all-MiniLM-L6-v2` | 384维向量,在 CPU 上运行速度快,语义准确性高 |
| **向量存储** | `faiss-cpu` — `IndexFlatIP` | 内存级,零基础设施,支持此规模下的精确搜索 |
| **PDF 解析** | `pypdf` | 轻量级,可处理大多数威胁情报 PDF 格式 |
| **UI 层** | `gradio` | 无需编写一行 HTML 即可实现浏览器可访问的演示 |
| **数据处理** | `pandas`, `numpy` | 标准语料库管理和数组操作 |
| **平台** | Kaggle (Python 3.12, CPU) | 无需本地设置,一键复现 |
## 核心概念:为什么选择语义而非关键词
这是 NexL 存在的核心,也是它与文档上的 `Ctrl+F` 的区别所在。
```
flowchart LR
subgraph KW["Keyword Search — Old Way"]
direction TB
Q1["Query: EDR bypass"] --> M1{"Exact string\nmatch in text?"}
M1 -->|"No match"| X1["❌ No results\neven if document\ndescribes the same thing"]
M1 -->|"Match"| Y1["✅ Returns document"]
end
subgraph SM["Semantic Search — NexL"]
direction TB
Q2["Query: EDR bypass"] --> E2["Encode to vector\n384 dimensions"]
E2 --> S2["Cosine similarity\nagainst all doc vectors"]
S2 --> R2["✅ Returns documents about\nsyscalls, hooking, injection,\nprocess hollowing — all of it"]
end
style KW fill:#450a0a,stroke:#f87171,color:#fef2f2
style SM fill:#14532d,stroke:#4ade80,color:#dcfce7
style X1 fill:#450a0a,stroke:#f87171,color:#fef2f2
style Y1 fill:#14532d,stroke:#4ade80,color:#dcfce7
style R2 fill:#14532d,stroke:#4ade80,color:#dcfce7
```
当查询和文档都被表示为同一个高维空间中的向量时,该空间中的接近度就等同于概念上的相似性。讨论同一*想法*的两份文档会聚集在一起——即使它们使用的词汇完全不同。
## 查询处理流水线
当你点击搜索的那一刻实际上发生了什么:
```
flowchart TD
IN["User types a query\n(or uploads a PDF)"] --> PDF{"PDF\nattached?"}
PDF -->|"Yes"| EX["pypdf extracts text\nfrom all pages"]
EX --> TR{"Text > 4000\nchars?"}
TR -->|"Yes"| CUT["Smart truncation\nFirst 2000 + Last 2000 chars"]
TR -->|"No"| FULL["Use full text"]
CUT --> MERGE["Append PDF text\nto original query"]
FULL --> MERGE
PDF -->|"No"| VAL{"Query\n≥ 5 chars?"}
MERGE --> VAL
VAL -->|"No"| WARN["⚠️ Warning message\nReturned to user"]
VAL -->|"Yes"| ENC["Encode query\nall-MiniLM-L6-v2"]
ENC --> NORM["L2 Normalize\nfaiss.normalize_L2"]
NORM --> SEARCH["FAISS IndexFlatIP.search\ntop_k = min(5, index.ntotal)"]
SEARCH --> SCORE["Cosine similarity scores\n0.0 → 1.0"]
SCORE --> FORMAT["Format output\n🟢 >60% | 🟡 >40% | 🔴 below"]
FORMAT --> OUT["Markdown rendered\nin Gradio UI"]
style IN fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
style EX fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style CUT fill:#713f12,stroke:#fbbf24,color:#fef3c7
style MERGE fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style WARN fill:#450a0a,stroke:#f87171,color:#fef2f2
style ENC fill:#1e1a4a,stroke:#a78bfa,color:#ede9fe
style NORM fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style SEARCH fill:#1e293b,stroke:#facc15,color:#fef9c3
style SCORE fill:#1e293b,stroke:#60a5fa,color:#eff6ff
style FORMAT fill:#1e293b,stroke:#4ade80,color:#dcfce7
style OUT fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
```
## 知识库
NexL 内置了 **8 篇网络安全文档**,涵盖了最常查询的威胁类别。这些不是玩具示例——每一条目都是对真实技术或漏洞的密集且准确的描述。
| # | 标题 | 类别 |
|---|-------|----------|
| 1 | 使用直接 Syscalls 绕过 EDR | EDR Bypass |
| 2 | Log4Shell CVE-2021-44228 分析 | Vulnerability |
| 3 | Living Off The Land Binaries (LOLBins) | Defense Evasion |
| 4 | 进程注入技术 | Defense Evasion |
| 5 | 2024年勒索软件初始访问向量 | Ransomware |
| 6 | MFA 疲劳攻击 | Initial Access |
| 7 | SQL 注入 (SQLi) | Web Exploitation |
| 8 | 鱼叉式网络钓鱼与网络钓鱼 | Social Engineering |
语料库是**有意设计为可扩展的**——在查询时上传 PDF 可以动态扩展搜索上下文,而无需触及索引。正式的 v2 版本将允许分析师将新文档永久添加到 FAISS 索引中。
## 语义模型——`all-MiniLM-L6-v2`
这个模型不是随意挑选的。它是针对本项目的限制条件经过深思熟虑后选择的:
```
Model: all-MiniLM-L6-v2
Architecture: BERT (6-layer MiniLM, distilled)
Output dimensions: 384
Avg encoding speed: ~14,200 sentences/sec (CPU)
Model size: ~80MB
Semantic accuracy: Strong on short-to-medium paragraphs
Training data: 1B+ sentence pairs
```
在 Kaggle 免费的 CPU 层级上,384 维模型在语义质量和推理速度之间达到了最佳平衡。可以使用更大的模型(768 维,1024 维),但会增加对于演示级工具而言非常明显的延迟。
**为什么使用余弦相似度?**
余弦相似度测量的是两个向量之间的*角度*,而不是它们的大小。这对文本来说很重要,因为探讨同一主题的短文档和长文档应该获得同样高的分数——余弦忽略了长度偏差。L2 归一化加上内积在 FAISS 中高效地实现了这一点。
## 相关性评分——颜色的含义
每个结果都会返回一个相似度得分和一个颜色指示器:
| 颜色 | 得分范围 | 解释 |
|-------|------------|----------------|
| 🟢 绿色 | > 60% | 强语义匹配——高度相关 |
| 🟡 黄色 | 40% – 60% | 中等相关——相关概念 |
| 🔴 红色 | < 40% | 弱匹配——仅有表面联系 |
这些阈值是针对 8 篇文档的语料库进行调优的。如果使用更大的索引,你需要重新校准——相关性的衰减与数据集中存在多少语义变化有关。
## PDF 集成
NexL 更实用的功能之一是能够上传原始威胁情报 PDF 并将其用作搜索上下文。
```
flowchart LR
PDF["Analyst receives\na threat report PDF"] --> UP["Uploads to Gradio\nFile picker"]
UP --> PARSE["pypdf reads\nall pages sequentially"]
PARSE --> TEXT["Raw text extracted\nfrom each page object"]
TEXT --> CHECK{"> 4000 chars?"}
CHECK -->|"Yes"| TRUNC["Truncate intelligently\nHead + Tail preserved\nCore context retained"]
CHECK -->|"No"| USE["Use as-is"]
TRUNC --> AUG["Concatenate with\nuser's text query"]
USE --> AUG
AUG --> FAISS["Single combined embedding\nsearched against index"]
FAISS --> RESULTS["Results surface documents\nrelated to the PDF's content"]
style PDF fill:#0f172a,stroke:#38bdf8,color:#e2e8f0
style PARSE fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style CHECK fill:#1e293b,stroke:#facc15,color:#fef9c3
style TRUNC fill:#713f12,stroke:#fbbf24,color:#fef3c7
style AUG fill:#1e293b,stroke:#818cf8,color:#e2e8f0
style FAISS fill:#1e1a4a,stroke:#a78bfa,color:#ede9fe
style RESULTS fill:#14532d,stroke:#4ade80,color:#dcfce7
```
这让分析师可以放入供应商公告或新的 MITRE ATT&CK 技术文档,并立即在现有知识库中找到与其相关的所有内容——而无需手动阅读两者。
## Gradio 界面
Gradio UI 保持界面紧凑。两个输入框。一个按钮。几秒钟内得出结果。
```
+--------------------------------------------------+
| 🛡️ NexL |
| AI-Powered Semantic Search for Cybersecurity |
+--------------------------------------------------+
| Search Query |
| ┌────────────────────────────────────────────┐ |
| │ e.g. 'How do hackers bypass endpoint │ |
| │ security?' │ |
| └────────────────────────────────────────────┘ |
| |
| Upload Threat Intel PDF (Optional) |
| ┌──────────────┐ |
| │ Drop PDF │ |
| └──────────────┘ |
| |
| [ 🔍 Search ] [ 🗑️ Clear ] |
| |
| ── Results ──────────────────────────────────── |
| **EDR Bypass using Direct Syscalls** `EDR` |
| Relevance: 🟢 78.4% |
| Many modern EDRs hook user-mode APIs... |
| ───────────────────────────────────────────── |
+--------------------------------------------------+
```
- **无需专业知识**即可使用该工具
- **无需 CSV 或结构化输入**——只需使用自然语言
- **PDF 增强查询**在后台静默处理
- **公共链接**通过 `demo.launch(share=True)` 自动生成
- 直接在 Kaggle 上运行——启用 Internet 访问即可获取可共享的 URL
## 挑战与设计决策
## 限制
| 限制 | 影响 | v2 中的修复方案 |
|------------|--------|-----------|
| FAISS 索引仅在内存中 | 重启会清空所有内容 | 使用 `faiss.write_index` 持久化索引 |
| 仅 8 篇内置文档 | 存在小众技术的覆盖盲区 | 添加流水线以摄取 MITRE ATT&CK STIX 数据 |
| PDF 使用单一组合 embedding | 长 PDF 会丢失中间部分的上下文 | 将 PDF 切分为 512-token 窗口,并分别对每个块进行索引 |
| 没有重新排序 | Top-k 顺序仅由原始余弦决定 | 对排名前 5 的结果添加 cross-encoder 重排步骤 |
| 没有 MITRE ID 映射 | 结果未链接到 ATT&CK ID | 使用结构化的 MITRE 元数据丰富每个文档 |
## 未来改进
| 优先级 | 改进项 | 解锁的功能 |
|----------|------------|----------------|
| **高** | **分块 PDF 索引**——将文档切分为重叠的 512-token 窗口 | 从全长威胁报告中实现准确检索 |
| **高** | **持久化 FAISS 索引**——在会话之间保存/加载到磁盘 | 支持跨 Kaggle 重启的有状态知识库 |
| **中** | **MITRE ATT&CK 摄取**——从 ATT&CK 仓库自动加载 STIX JSON | 索引中包含数千条真实的技术条目 |
| **中** | **Cross-encoder 重排序**——使用第二个模型对 top-k 结果重新排序 | 在结果列表顶部实现更高的精度 |
| **长期** | **FastAPI 后端 + 独立 Web 应用**——与 Gradio 解耦 | 可生产部署的威胁情报搜索工具 |
| **长期** | **查询扩展**——从查询中自动建议相关的 MITRE 技术 ID | 弥合分析师意图与正式分类法之间的差距 |
## 如何运行
```
# 无需安装脚本 — 所有依赖项在 cell 1 中通过 pip 安装
# sentence-transformers, faiss-cpu, gradio, pypdf, pandas, numpy
```
**步骤:**
1. 在 Kaggle 上打开 notebook
2. 无需附加数据集——语料库直接在代码中植入
3. 将加速器设置为 **None**——CPU 已经绰绰有余
4. 按顺序运行所有单元格(首次运行下载模型大约需要 60 秒)
## 结论
NexL 是一个小型项目,有着清晰的论点:对威胁情报的语义理解不是奢侈品,而是必需品。关键词搜索从来就不是为这样一个领域设计的:在这里,同一种攻击会因为撰写人的不同而有十二个不同的名字。
架构是刻意保持极简的——一个 6 层 transformer、一个内存级向量索引和一个 Gradio 包装器——因为重点是干净利落地证明这个概念,而不是过度工程化。所有重要的东西都可见于同一个 notebook 中。
```
all-MiniLM-L6-v2 | 384-dim vectors | FAISS IndexFlatIP | 8 seeded docs | ~60s cold start
```
本项目建立的是基础层。同样的架构,加上分块摄取和真实的语料库,就是分析师真正会使用的合法工具。
## 作者
**JK**
机器学习与网络安全爱好者
*于 Kaggle 构建,2026 年 7 月*
*如果你觉得这个项目有用,请在仓库中留下一颗星。*
标签:Python, 人工智能, 向量检索, 威胁情报, 开发者工具, 无后门, 用户模式Hook绕过, 语义搜索, 逆向工具