轻量级 IOC 管理方案:Streamlit 驱动的恶意IP情报平台
一个基于 Streamlit + SQLite 的轻量级 IOC 管理工具,支持多格式情报导入、自动风险评分、可视化分析与去重管理。
一、背景:为什么需要自建 IOC 管理工具
在日常渗透测试和安全运维中,威胁情报的积累速度往往超出预期。一个中等规模的红蓝对抗项目,几周内就能沉淀出数百条恶意IP、域名和病毒家族信息。如果这些数据散落在 TXT 文件、Excel 表格和聊天记录里,真正需要查询时会陷入困境。
市面上的威胁情报平台(TIP)功能完善,但对个人或小团队而言,部署门槛高、成本不菲。更关键的是,安全人员经常需要对情报做二次标注------补充归属地、对照病毒家族、记录自己遇到该 IOC 的攻击场景------这些个性化需求在通用平台上很难满足。
因此,我动手构建了一个轻量级的恶意IP信息管理系统:全离线运行、SQLite 存储、支持多格式导入与自动解析、内置风险评分引擎。这篇文章从技术选型、架构设计、核心算法到实战用法,完整复盘整个项目的设计思路。
二、技术选型与架构概览
2.1 技术栈
| 组件 | 技术选型 | 理由 |
|---|---|---|
| 前端框架 | Streamlit | 纯 Python 即可构建交互式 Web UI,适合数据应用 |
| 数据库 | SQLite | 零配置、单文件部署、适合本地工具 |
| 可视化 | Plotly | 交互式图表,与 Streamlit 深度集成 |
| 数据处理 | Pandas | DataFrame 统一处理查询结果和导入数据 |
| 去重签名 | SHA256 | 基于多字段拼接生成唯一签名 |
2.2 整体架构
#mermaid-svg-ZKksIlbTaY40og9n{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZKksIlbTaY40og9n .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZKksIlbTaY40og9n .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZKksIlbTaY40og9n .error-icon{fill:#552222;}#mermaid-svg-ZKksIlbTaY40og9n .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZKksIlbTaY40og9n .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZKksIlbTaY40og9n .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZKksIlbTaY40og9n .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZKksIlbTaY40og9n .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZKksIlbTaY40og9n .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZKksIlbTaY40og9n .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZKksIlbTaY40og9n .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZKksIlbTaY40og9n .marker.cross{stroke:#333333;}#mermaid-svg-ZKksIlbTaY40og9n svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZKksIlbTaY40og9n p{margin:0;}#mermaid-svg-ZKksIlbTaY40og9n .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZKksIlbTaY40og9n .cluster-label text{fill:#333;}#mermaid-svg-ZKksIlbTaY40og9n .cluster-label span{color:#333;}#mermaid-svg-ZKksIlbTaY40og9n .cluster-label span p{background-color:transparent;}#mermaid-svg-ZKksIlbTaY40og9n .label text,#mermaid-svg-ZKksIlbTaY40og9n span{fill:#333;color:#333;}#mermaid-svg-ZKksIlbTaY40og9n .node rect,#mermaid-svg-ZKksIlbTaY40og9n .node circle,#mermaid-svg-ZKksIlbTaY40og9n .node ellipse,#mermaid-svg-ZKksIlbTaY40og9n .node polygon,#mermaid-svg-ZKksIlbTaY40og9n .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZKksIlbTaY40og9n .rough-node .label text,#mermaid-svg-ZKksIlbTaY40og9n .node .label text,#mermaid-svg-ZKksIlbTaY40og9n .image-shape .label,#mermaid-svg-ZKksIlbTaY40og9n .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZKksIlbTaY40og9n .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZKksIlbTaY40og9n .rough-node .label,#mermaid-svg-ZKksIlbTaY40og9n .node .label,#mermaid-svg-ZKksIlbTaY40og9n .image-shape .label,#mermaid-svg-ZKksIlbTaY40og9n .icon-shape .label{text-align:center;}#mermaid-svg-ZKksIlbTaY40og9n .node.clickable{cursor:pointer;}#mermaid-svg-ZKksIlbTaY40og9n .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZKksIlbTaY40og9n .arrowheadPath{fill:#333333;}#mermaid-svg-ZKksIlbTaY40og9n .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZKksIlbTaY40og9n .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZKksIlbTaY40og9n .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZKksIlbTaY40og9n .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZKksIlbTaY40og9n .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZKksIlbTaY40og9n .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZKksIlbTaY40og9n .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZKksIlbTaY40og9n .cluster text{fill:#333;}#mermaid-svg-ZKksIlbTaY40og9n .cluster span{color:#333;}#mermaid-svg-ZKksIlbTaY40og9n div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZKksIlbTaY40og9n .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZKksIlbTaY40og9n rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZKksIlbTaY40og9n .icon-shape,#mermaid-svg-ZKksIlbTaY40og9n .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZKksIlbTaY40og9n .icon-shape p,#mermaid-svg-ZKksIlbTaY40og9n .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZKksIlbTaY40og9n .icon-shape .label rect,#mermaid-svg-ZKksIlbTaY40og9n .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZKksIlbTaY40og9n .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZKksIlbTaY40og9n .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZKksIlbTaY40og9n :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 引擎层
Streamlit Web UI
仪表盘
情报列表
导入数据
手工录入/编辑
解析引擎
txt_parser · dataframe_parser
评分引擎
compute_risk_score · risk_level
标签引擎
infer_tags
数据访问层
insert_or_update · query_records · delete
SQLite
threat_ioc.db
系统采用单文件部署 模式:app.py + threat_ioc.db 两个文件即可运行,不需要数据库安装、不需要 Web 服务器配置。
三、数据模型设计
3.1 核心表结构
sql
CREATE TABLE ioc_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip TEXT NOT NULL,
domain TEXT DEFAULT '',
location TEXT DEFAULT '',
threat_type TEXT DEFAULT '',
family TEXT DEFAULT '',
description TEXT DEFAULT '',
risk_score INTEGER DEFAULT 0,
risk_level TEXT DEFAULT '低危',
tags TEXT DEFAULT '',
status TEXT DEFAULT 'active',
source_file TEXT DEFAULT '',
source_line INTEGER DEFAULT 0,
first_seen TEXT DEFAULT '',
last_seen TEXT DEFAULT '',
created_at TEXT DEFAULT '',
updated_at TEXT DEFAULT '',
signature TEXT UNIQUE
);
3.2 关键设计决策
(1)signature 唯一约束的权衡
每条记录以 SHA256 对 {IP, 域名, 归属地, 威胁类型, 病毒家族, 攻击描述} 六字段拼接产生的签名作为唯一键。这避免了导入重复数据时的手动去重,但也意味着:如果同一个 IP 出现了新的攻击行为,更新描述后签名会变化,从而被识别为新记录而不是更新旧记录。
这实际上是一个有意的取舍------同一 IP 的不同攻击行为(如从僵尸网络转为后门)本质上就是两条不同的威胁情报,应当区分对待。
(2)标签字段的冗余存储
tags 以逗号分隔字符串存储,违反数据库范式。但在这个场景下,标签主要用于筛选和展示,不参与复杂的关联查询。反范式化后,前端直接以字符串形式读取和过滤,避免了额外的关联表开销。这对单用户工具而言是合理的工程权衡。
(3)来源追溯
source_file 和 source_line 两个字段记录了每条 IOC 的原始来源,当需要回溯某条情报的上下文时,可以直接定位到原始文件的对应位置。这在批量导入数百条数据后尤为有用。
四、核心引擎实现
4.1 多格式解析引擎
系统需要同时支持三种输入格式:结构化文本(TXT)、CSV、Excel(XLSX)。
TXT 格式解析采用正则 + 状态机模式:
IP地址: 192.168.1.100
关联域名: malicious.example.com
归属地: 中国/广东/深圳
威胁类型: 后门
病毒家族: AsyncRAT
攻击描述: 该样本通过钓鱼邮件传播,安装后建立与C2的加密通道,
执行键盘记录和屏幕监控。
解析器逐个匹配 字段名: 值 模式,遇到新的 IP地址: 即视为新记录的开始;非字段行的文本自动追加到当前字段的值中,实现多行攻击描述的自动合并。状态机维护当前的"活跃字段",解决了攻击描述跨行续写的实际问题。
CSV/XLSX 格式 采用更灵活的列名匹配:通过 find_col() 函数按候选词列表(如 ["IP地址", "ip", "IP"])模糊匹配列名,对列顺序不敏感。这意味着不同来源的情报文件即使列名略有差异,也能正确导入。
4.2 风险评估算法
风险评估是系统的核心差异化功能:不依赖外部API,完全基于本地规则。
算法从四个维度加权评分:
| 维度 | 评分逻辑 | 最高分值 |
|---|---|---|
| 威胁类型 | 僵尸网络 +30,窃密 +35,后门 +25,挖矿 +20 | 35 |
| 病毒家族 | 命中已知高危家族列表(Mirai、AsyncRAT、DCRat 等) | +15 |
| 行为特征 | DDoS、IoT漏洞利用、键盘记录、密码窃取等关键词匹配 | +15 |
| 动态DNS | 域名包含 duckdns/no-ip/ddns 等 | +5 |
最终分数封顶 100。风险等级的映射:
- 80~100:严重
- 60~79:高危
- 30~59:中危
- 0~29:低危
这里值得注意的细节:风险评分在导入时计算并固化存储,不在查询时动态计算。这保证了对同一 IOC 在不同时间段的评估一致性。如果威胁情报环境变化导致评分规则调整,可以通过手工编辑页面逐一更新评分。
4.3 智能标签推断
标签系统同时处理三类来源:
- 用户显式指定的标签 :从 CSV 的
tags列直接读取 - 威胁类型与家族:自动转为标签(如"后门"→标签"后门")
- 描述文本推理:关键字匹配自动打标
第三类的推理规则覆盖六种常见威胁场景:
python
# DDoS / 僵尸网络
if any(x in desc for x in ["ddos", "分布式拒绝服务", "僵尸网络", "botnet"]):
tags.add("DDoS")
# IoT 设备
if any(x in desc for x in ["telnet", "ssh", "iot", "路由器", "摄像头"]):
tags.add("IoT")
# 远程访问木马
if any(x in desc for x in ["键盘记录", "屏幕监控", "远程控制", "shell"]):
tags.add("RAT")
# 窃密木马
if any(x in desc for x in ["窃密", "密码窃取", "cookie", "凭证"]):
tags.add("Stealer")
# 加载器
if any(x in desc for x in ["加载器", "loader", "下载并执行"]):
tags.add("Loader")
# 挖矿
if any(x in desc for x in ["挖矿", "xmr", "xmrig", "monero"]):
tags.add("Miner")
# 动态DNS
if any(x in domain for x in ["duckdns", "no-ip", "ddns"]):
tags.add("DynamicDNS")
标签自动补齐大幅减少了手工标注的工作量,且同类 IOC 的标签风格统一,后续筛选时不会遗漏。
五、功能模块详解
5.1 仪表盘
打开系统后首先看到的是仪表盘:四个核心指标卡片(总记录数、高危/严重数量、后门类数量、僵尸网络类数量)加四张统计图表。
图表方面:
- 威胁类型分布:柱状图展示各威胁类型的 IOC 数量,一眼看出哪类威胁最活跃
- Top 病毒家族:饼图展示排名前 10 的活跃家族
- 风险等级分布:按严重/高危/中危/低危分色展示
- 记录状态分布:active / blacklist / whitelist 等状态分布
所有图表均使用 Plotly 的 plotly_dark 模板,与深色主题 UI 风格统一。图表可交互------悬停显示数值、点击图例筛选、拖拽缩放,这些都是 Plotly 自带的能力,不需要额外代码。

5.2 情报列表
这是日常使用频率最高的页面。支持六维联合筛选:
- 关键词搜索:同时命中 IP、域名、归属地、威胁类型、家族、描述、标签
- 威胁类型筛选:下拉框自动从数据库去重取值
- 病毒家族筛选:同上
- 状态筛选:active / blacklist / whitelist / review / inactive
- 风险等级筛选:低危 / 中危 / 高危 / 严重
- 归属地关键词:按国家/地区模糊筛选
查询结果以 DataFrame 表格展示,支持导出当前结果为 CSV。点击某条记录可展开详情面板:左侧显示基础信息(IP、域名、归属地等),右侧显示来源追溯和时间戳。最底部有完整的 JSON 视图,方便复制到其他工具。
批量删除功能通过多选框勾选记录 ID 完成,比逐条删除的效率高得多。

5.3 数据导入
提供两种导入路径:
粘贴文本导入:直接将 TXT 内容粘贴到大文本框,点击"解析并导入"。适合从聊天记录、报告截取的少量 IOC。
文件上传导入 :支持 txt / csv / xlsx / xls 四种格式。上传后先预览解析结果,确认无误再写入数据库。导入采用 INSERT OR UPDATE 逻辑------新签名直接插入,已存在的签名更新 last_seen 时间戳。系统会明确告知"新增 X 条,更新 Y 条",避免静默覆盖。
5.4 手工录入与编辑
除了批量导入,系统也支持逐条手工录入。编辑页面同时承载"新增"和"修改"两个功能。修改模式下,所有字段预填当前值,保存时重新计算签名并检查冲突。删除操作支持单条删除(从编辑页面)和批量删除(从列表页面)。
六、生产环境使用建议
6.1 部署
bash
pip install streamlit pandas plotly openpyxl
streamlit run app.py
启动后浏览器访问 http://localhost:8501。如需远程访问,加 --server.address 0.0.0.0 参数,但务必配合防火墙或 VPN 使用------这个系统没有内置的认证机制。
6.2 数据备份
threat_ioc.db 是一个独立的 SQLite 文件,直接复制该文件即可完成备份。建议配合 cron 做定期备份:
bash
# 每天凌晨备份
0 2 * * * cp /path/to/threat_ioc.db /backup/threat_ioc_$(date +\%Y\%m\%d).db
6.3 情报流转工作流建议
- 采集阶段:从蜜罐日志、外部威胁情报源、同行分享获取原始 IOC 数据
- 导入阶段:通过本系统的导入模块批量入库,自动完成解析、评分、去重
- 标注阶段:对自动评分较高或缺失关键字段的记录,通过手工编辑补充
- 分析阶段:利用仪表盘和筛选功能分析威胁趋势、识别高频家族
- 输出阶段:导出 CSV 后投入防火墙规则、IDS 签名、SIEM 告警等下游系统
七、扩展方向
当前版本是一个"能用的基础版",以下是我认为值得扩展的方向:
- API 接口:用 FastAPI 封装查询和导入端点,方便与 SOAR 平台对接
- 外部情报源集成:对接 AbuseIPDB、VirusTotal 等 API,自动补全归属地和风险评分
- PDF 报告生成:按周/月导出威胁态势报告,适合向上汇报
- 黑白名单自动同步:通过 SSH/API 将黑名单 IP 批量写入防火墙规则
- 告警推送:当出现严重级别的新 IOC 时,通过企业微信/钉钉推送通知
- 多用户权限:为团队场景增加登录认证和操作审计
这些功能的核心逻辑都已经预留了扩展接口:状态字段区分了黑白名单、标签字段支持任意维度的分类、source_file 字段可追溯数据来源。在现有架构上叠加这些能力不会涉及大的重构。
八、总结
这个恶意IP管理系统本质上解决的是一个很朴素的问题:让安全人员能高效地管理自己积累的威胁情报。1078 行 Python 代码,基于 Streamlit 和 SQLite 两个成熟组件,实现了从数据导入、智能解析、风险评估到可视化分析、检索导出的完整闭环。
它不替代企业级 TIP 平台,而是填补了 TIP 所不覆盖的场景------个人渗透测试中的情报积累、小团队的红蓝对抗资产管理、以及安全研究人员对自有情报库的精细化管理。
完整的源代码和部署文档详见项目仓库。如果在使用过程中遇到问题或有改进建议,欢迎交流。
本文所有技术细节基于 恶意IP管理系统 v1.0 版本,最后更新于 2026 年 8 月。