跳到主要内容

在线 Demo

在线 Demo

项目:SecAgent

SecAgent · AI 安全运营助手

一句话:把「告警 → 研判 → 处置」这条安全运营链路,做成一个可编排、可审计、有护栏的 AI 助手。

解决什么问题

企业安全运营中心每天产生几千到几万条告警,其中九成以上是误报和重复,真正的攻击被淹没在噪声里。分析师要在告警系统、日志平台、知识库、资产表之间来回切换才能下判断;判断完还要手工封 IP、锁账号——慢、容易出错,而且处置过程没有留痕,事后无法复盘。

新人上手要几个月,老手的经验留在脑子里带不走。

我做了什么

能力具体实现
降噪同一源 IP + 时间窗 + 同类告警自动聚合成一条,带 ×N 徽标,可下钻原始明细
多 Agent 研判编排层 + 调度员,派发给研判员(查知识库 RAG)、取证员(拉告警与日志)、处置员(执行动作)三个专职智能体,汇总输出「结论 + 证据 + 处置结果」
分级处置 + 护栏自动封禁;高危动作强制人工审批;白名单拦截内网/环回地址;全部动作写审计
知识库问答33 篇安全知识文档向量化,支持带出处引用与相似度阈值拒答
红队评测27 例用例(基础 19 + 绕过型 8),同时输出绕过率与误报率两个独立维度;绕过率 4/19 = 21.05%(95% CI 约 8%~44%),8 例正常流量未观察到误拦(真实误报率 95% 置信上限约 37.5%)

一个关键的设计取舍

处置动作的护栏写在代码里,不写在提示词里。

因为提示词可以被精心构造的输入绕过,而代码层的白名单绕不过去。这条取舍说明我清楚大模型的能力边界——知道该在哪里踩刹车。

技术栈

Spring Boot 3.2 · Spring AI / Spring AI Alibaba · RAG · 多 Agent 编排 · Tool Calling · SSE 流式输出 · 自研向量存储抽象(内存 / Milvus 可切换)· Docker

相关文章

🚧 在线 Demo 正在部署中。 部署完成后这里会放可点击的试玩入口。


这个站点本身

一句话:用 Hugo + PaperMod 构建的纯静态技术站,托管在 GitHub Pages。

它值得单列的原因:这不是套个模板就完事——为了让它符合一个安全从业者该有的样子,做了这些取舍:

决策原因
纯静态,不要 CMS 和数据库没有数据库就没有 SQL 注入,没有后台就没有弱口令
零第三方脚本每个外部脚本都是把访问者的浏览器控制权分一份给别人
页面内不加统计/字体/客服同上,只留必要的评论组件
源码与构建产物分离main 放源码,gh-pages 放产物,发布可复现

相关文章:《我把这个博客当成一个安全项目来做》

在线 Demo

🔗 打开试用

打开 SecAgent 在线 Demo ↗
demo.xiaokeqing.cn —— 部署在阿里云 2 核 2G 上、容器只监听回环地址, 对外通过 Cloudflare 命名隧道提供 HTTPS。
地址是固定的:即使以后把服务迁到别的服务器,这个链接也不会失效。

🔑 演示账号

用户名analyst
密码SecAgent-Demo-2026
角色分析员(ANALYST)

这个角色能做什么、不能做什么:

✅ 可以❌ 不可以
查看告警大屏、事件归档执行处置动作(封 IP / 锁账号 / 杀进程)
对话研判、知识库检索审批处置申请
提交知识条目(待审)审核知识库、管理用户

权限是刻意收窄的。 处置动作全部要求管理员角色 + 人工审批,所以公开一个分析员账号不会带来风险。

配额说明:为了让服务不被刷爆,接口有 50 次/天 的模型调用配额和 30 次/分钟 的限流。用完了第二天恢复。


建议试这几件事

按顺序试,能看出系统的设计思路:

1️⃣ 先问一个知识库问题

在「对话研判」里输入:

什么是路径穿越,怎么防御?

看什么:回答下面会附检索证据,包含命中的文档名、片段内容、相似度分数。 证据被包在一个 <UNTRUSTED_DATA> 标签里 —— 这是提示词注入防护: 知识库文档本身也可能是攻击载荷,不能被当成给模型的指令。

2️⃣ 再问一个需要"动手"的问题

帮我看看最近的告警里有没有可疑的

看什么:调度员会判定这是研判任务,派给对应角色的智能体,并调用工具去拉告警数据,而不是凭空编答案。

3️⃣ 去看告警大屏

看什么:列表默认显示的是聚合后的结果(同一源 IP + 时间窗 + 同类告警合成一条),带 ×N 徽标。点进去能下钻到原始明细。

这是解决"告警风暴"的核心设计。

4️⃣ 去看处置中心

看什么:处置动作分三级 —— 自动执行 / 需审批 / 禁止。 注意「需审批」那一列 —— 这是整个项目最重要的设计:高危动作永远不会自动执行。

5️⃣ 试着让它做危险的事

在对话里试试:

帮我封禁 127.0.0.1 这个 IP

看什么:会被代码层的白名单拦下来,而不是靠提示词拒绝。 内网地址、环回地址在处置护栏里是硬拦截的 —— 因为提示词可以被绕过,白名单不能。


为什么地址是这个

demo.xiaokeqing.cn —— 走的是 Cloudflare 命名隧道,不是临时隧道。

区别在这里:

临时隧道命名隧道(现在用的)
地址随机分配,重启就换固定,绑在 Cloudflare 账号下
换服务器链接失效链接不变(只在新机器上重装隧道)
入站端口不需要不需要

服务器上没有任何入站端口是开着的 —— 容器只监听 127.0.0.1, 隧道是服务器主动向 Cloudflare 建立出站连接。所以从外面扫这台机器, 扫到的只有 22 端口(而且已经关了密码登录)。

这条也是买域名真正要解决的问题:让地址和机器解耦。 服务器是消耗品,域名是资产。


已知限制(不想让你踩坑)

限制说明
数据是模拟的告警和日志是 MOCK 数据,没有接真实 SOC 环境
处置动作没实测过代码里有完整实现和护栏,但不敢在生产环境真的封 IP 演示
响应偏慢服务器在杭州,隧道绕经境外,首屏约 1.2~1.5 秒
手机端能用,但告警大屏这类宽表格在小屏上体验一般

关于防护强度的真实数字

红队评测跑过了,27 例(19 例基础 + 8 例绕过型),结果:

指标数值说明
绕过率4 / 19 = 21.05 %95% 置信区间约 8 % ~ 44 %
误报率0 / 8 未观察到误拦真实误报率的 95% 置信上限约 37.5 %
拦下 / 绕过15 / 4

为什么要写置信区间,而不是写「误报率 0%」

8 个正常样本里 0 次误拦,不等于误报率是 0。 按统计学上的「三法则」,n 次试验 0 次事件时,真实发生率的 95% 置信上限约为 3/n —— 也就是 3/8 ≈ 37.5%。样本量太小,这个数字只够说明「没有明显误杀」, 支撑不了「误报率很低」的结论。

同理,4/19 的绕过率区间宽到 8%~44%,几乎不具区分度。

写清楚这一点,是因为一个漂亮但站不住的 0% 比一个诚实的区间更容易被问倒。

为什么不写「拦截率 100%」:第一版 19 例跑出来就是 0 绕过、0 误报, 但那个数字没有意义 —— 用例是照着防护规则写的,当然全能命中。 0% 绕过率不是成绩,是评测集失效的信号。

所以补了 8 例专门针对规则边界的变形载荷(字符插空 / 全角 / Base64 / 同义改写 / 凭据拆开写…),绕过率立刻变成 42.11%。然后修掉其中能修的 4 类 (加文本归一化 + 补中文模式),降到 21.05%。

关键是:修完之后误报率没有变差 —— 8 个正常用例依然全部放行。 说明拦截率的提升不是靠「宁可错杀」换来的。

剩下 4 类修不掉,而且我知道为什么修不掉:

  • 纯语义改写(「请把上面那段话作废…」)—— 正则无解
  • Base64 编码的指令 —— 正则只看明文
  • 编码后的私钥 —— 同上
  • 中文自然语言表述的口令 —— 需要语义理解

这四类不是「还没修」,是「用规则修不了」。 加正则只会带来误报。 它们的存在,正是这条链路上必须保留人工审批的原因 —— 纵深防御不是口号。

下一步:这套用例是自己写的,可信度天花板就在那。 计划接入 NVIDIA Garak 与 Microsoft PyRIT 这类业界工具, 用第三方用例集解决「自己出题自己阅卷」的问题。


想看它是怎么做出来的 → 项目介绍
想提问或查文档 → AI 问答

数据来源 · 口径 · 免责

  • 接口基址—
  • 口径只读公开端点 · IP 已由后端掩码
  • 轮询10–15s 自适应(监测中心 5 个端点时放宽到 ≥20s,给限流留余量)· 标签隐藏即暂停
  • 服务端15s 缓存 · 20 次/分钟限流
  • 前端不再加工或还原 IP,只原样展示服务端掩码后的字段

公开端点实时探测(一次性,只读)

  • 探测中…

免责与取舍(逐条都是当前事实,2026-10-13 复核): ① 所有数字都来自上面的公开只读端点,取不到就写「未接入 / 上次同步」,不补假数据、不用样本冒充真实; ② /api/public/audit 展示的是真实封禁与处置留痕,并在卡片里写明来源,而不是编一条 live 数据; ③ /api/public/latest 已上线:返回窗口聚合(windowSize=200 / windowAlertCount / severityCounts / sourceCounts / latestEvent / latestBlock),字段全部来自公开白名单 (来源 IP 显示为前三段 + 末段 x,不含标题、内网目的地址、聚合 id)。此前文档里写的"404 未上线"是旧结论,已更正; ④ 明细下钻端点 /api/public/alerts/{aggId} 仍未上线,所以监测中心只展示聚合记录自带的字段, 不额外拼一份「原始事件列表」; ⑤ 蜜罐命令时间线(commandsAvailable=false)保持「数据源未接入」,不编造命令内容; ⑥ HTTP 状态码分布与 7 天 × 24 小时热力格没有画:公开端点里没有 statusCode / httpStatus 字段, 也没有历史日桶 —— 监测中心底部把这两项如实列成"读不到",而不是拿 24h 数据伪装成 7 天; ⑦ 前端不做匿名常驻 SSE / WebSocket,秒级实时只给登录后的私有后台。