这是一个跑在两台云主机上的安全观测站:把主机层的 Wazuh、网络层的 Suricata、 以及三台蜜罐(Cowrie / Dionaea)产生的告警,汇进同一个面板,对外只开只读接口。 它的问题是「我这边到底在被怎么打、我拦下了什么」——所以每个数字下面都写着它从哪个端点来。
① 看攻击实况
实时攻击流(5 分钟窗口聚合)、攻击图谱(攻击者 → 四阶段粒子流)、威胁矩阵(14 个 ATT&CK 手法格)、
数据统计(来源国 / ASN / 规则命中)。数据源:/alerts /stories /geo /webstats。
② 看处置链
护栏拦下了多少动作、真正执行了几个、封过哪些地址、蜜罐被连了多少次、攻击者拿什么口令撞的。
数据源:/audit /honeypot。地址一律打码到前三段。
③ 直接问它
「AI 问答」页是对着本站自己的知识库检索后作答,引用到条目;检索不到就明说检索不到, 不编造。问答接口同样有频率限制,公开面只做解释、不做取证判决。
站上还跑着一台练习靶场(Pikachu):跑在独立内网、禁止出网、状态可每天重置, 用来验证「真被打进来之后,告警会长什么样、面板会亮成什么样」。它不是给人随便玩的 —— 入口加了口令门禁,只有站主能登录,口令不在这页公开。
链路:lab.xiaokeqing.cn → Cloudflare 隧道 → nginx auth_request
→ 口令页 → 签名 Cookie(24h)→ 容器;容器内不能出网,宿主机只能读到它自己的日志。
| 指标 | 端点 / 字段 | 口径(容易误读的地方) |
|---|---|---|
| 累计拦截 | audit.summary.blockedByGuard | 护栏拦下的动作数,累计,不是本周 |
| 累计封禁 IP | audit.summary.blockTotal | 留痕条数去重后的地址数;同时给出当前生效数 |
| 蜜罐连接 | honeypot.connections | total 恒为 10000,那是统计上限哨兵,不是真实累计 |
| 24h 告警 | geo.coverage.totalAlerts | 窗口内未去重总量;其中带源 IP 的才进地理统计 |
| 告警源 | dataSource.wazuhMode | REAL = 真的 Wazuh 在供数;降级会显式写出来 |
公开面只读、不含任何写操作;地理统计用 DB-IP Lite 离线库,只到国家/省,不定位到人。 蜜罐是真实诱饵,攻击者的口令尝试会被记录但不会在页面上明示原文。
# 全部只读,可直接 curl;返回 JSON,字段同上表
curl -s https://demo.xiaokeqing.cn/api/health | head -c 200
curl -s https://demo.xiaokeqing.cn/api/public/audit | head -c 400
curl -s https://demo.xiaokeqing.cn/api/public/honeypot | head -c 400这些接口由站点同源的 meta[name=wb-api] 声明,页面自己也不写死域名;
取不到数据时页面显示「未取到」而不是填 0 —— 失败要看得见。