概述 —— 这个页面做什么
白名单 页面用于管理要从 InfraGuard 自动封禁流水线中排除的 IP 和网段。在此登记的条目构成一份"豁免名册",检测采集器在执行封禁之前会先查阅它 —— 从而避免可信来源(CDN、合作方 API、办公网线路)因误报而被封禁。
其核心概念是有效期:
expires_at为 NULL → 永久豁免(永不过期)。适用于 CDN、办公网线路等始终可信的来源。expires_at为日期时间 → 临时豁免(过了该时刻即自动失效)。适用于短期调查窗口或自动无辜判定。
豁免有三种来源:
| 来源 | 值 | 含义 |
|---|---|---|
| 手动 | manual |
运维人员直接从界面添加 |
| 自动(无辜) | auto |
srct_tx 查询某个 IP 的信誉,若确凿无辜则自动登记 30 天豁免 |
| 默认 | seed |
由 InfrWhitelistSeeder 迁入的、原先硬编码的 CDN/OFFICE 网段(永久) |
infr_whitelist表位于legacy_glory连接(与blacklist_info、suricata_*等表同一个数据库),而不是应用数据库。这样 Node 采集器srct_tx才能在封禁前直接读取这张表,并把无辜 IP 直接写入其中。
何时使用
- 避免误报:预先登记可能触发扫描/速率启发式规则的正常流量(监控机器人、合作方爬虫、支付回调)。
- 调查期间的临时例外:为某个网段设置到期时间,使其豁免数天。
- 始终信任 CDN/办公网:把 Cloudflare/Google/AWS/Akamai 的前端 IP 或固定的办公网 IP 设为永久豁免。
- 复核自动判定:查看、延长或删除
srct_tx创建的auto条目。 - 在封禁列表中解封误封的 IP,并防止它再次被封禁(登记一条豁免)。
页面构成
顶部 KPI(5 个)
由 WhitelistService::summary() 计算,带 30 秒缓存。生效中 = is_active = 1 且(expires_at IS NULL 或 expires_at > now)。
| KPI | 含义 | 计算方式 |
|---|---|---|
| 生效中的豁免 | 当前有效的豁免总数 | 生效中条目的数量 |
| 永久 | 无有效期的条目 | 生效中 且 expires_at IS NULL |
| 临时 | 将会到期的条目 | 生效中 − 永久 |
| 自动豁免 | 判定为无辜的自动条目 | 生效中 且 source = 'auto' |
| 即将到期 | 7 天之内到期 | 生效中 且 expires_at <= now+7d |
豁免列表
一张可筛选的表格(每页 25 行)。排序为永久优先(expires_at IS NULL DESC)→ 有效期升序 → id 降序。
| 列 | 说明 |
|---|---|
| 网段 | 规范化后的 cidr(例如 203.0.113.0/24 或 203.0.113.10/32) |
| 名称 | label(例如"Cloudflare""办公网") |
| 来源 | manual / auto / seed 徽标 |
| 有效期 | 永久 / YYYY-MM-DD HH:MM / n days left / 已过期 |
| 添加时间 | created_at |
| 操作 | 移除(在你拥有写入权限时) |
筛选项:状态(生效中 · 已过期 · 全部)、来源(手动 · 自动 · 默认 · 全部)、搜索(IP · CIDR · 名称)。列表每 30 秒轮询一次更新。
手动添加弹窗
[Add manually](手动添加)按钮会打开一个弹窗。输入项:IP 或 CIDR、名称(可选)、到期日期时间(可选;留空即为永久)。
使用方法
1. 添加一条手动豁免
- 点击
[Add manually](手动添加)。 - 输入 IP 或 CIDR。单个 IP 会规范化为
/32;网段则规范化为其网络地址(见下文的规范化规则)。 - 可选地填写名称和到期日期时间。若要永久豁免,请把有效期留空。
- 点击
[Add](添加)。如果相同的cidr已存在,则该条目会被重新启用(is_active=1),并更新其有效期和名称。
2. 规范化(normalizeCidr)规则
WhitelistService::normalizeCidr() 会把输入改写为规范形式(与区域设置无关,和 srct_tx 的匹配约定完全一致)。
203.0.113.10 → 203.0.113.10/32 (单个 IP 变成 /32)
203.0.113.0/24 → 203.0.113.0/24 (保持不变)
203.0.113.55/24 → 203.0.113.0/24 (主机位被掩掉 → 网络地址)
10.0.0.5/8 → 10.0.0.0/8
999.1.1.1 → (无效 → null,422 invalid_ip)
- 仅支持 IPv4。前缀长度为 0–32。
- 保存之前,控制器会先用正则
^\d{1,3}\.\d{1,3}\.\d{1,3}(\.\d{1,3})?(/\d{1,2})?$做预校验,再由服务用filter_var(... FILTER_FLAG_IPV4)+ip2long做最终确认。
添加
/24网段时可以保留主机位 ——203.0.113.55/24会自动存为203.0.113.0/24(它的网络地址)。
3. 填写有效期
- 留空 → 永久(
expires_at = NULL)。 YYYY-MM-DD或YYYY-MM-DD HH:MM→ 由Carbon::parse解析。- 解析失败同样按永久处理(
parseExpiry→ null)。
4. 删除
列表行上的删除操作会在确认后调用 remove。该行会被物理删除(不是软删除)。即使是 seed 的 CDN 条目也可以删除,但下次运行种子脚本时可能会被重新创建。
5. srct_tx 的自动无辜判定(auto 来源)—— 条目是怎么产生的
srct_tx 采集器会在封禁扫描/速率异常 IP 的前一刻,用一套非常严格的流程核验其无辜性,只有判定确凿时才会在这里留下一条 auto 记录。
- 白名单过滤 —— 若已存在于
infr_whitelist(以及代码内置的 CDN 列表),立即豁免并跳过。 - 仅对 E 单独信号的候选查信誉 —— 只有那些携带易误报的"仅短扫描"信号(启发式 E)、且不带任何硬信号(A/A2/B/C/D)的 IP,才会去 AbuseIPDB 查询(密钥轮询 · 6 小时缓存 · 每轮扫描有上限)。
- 完全无辜的判定 —— 若
abuse_score=0且reports=0且不是 Tor(或已在白名单中且评分为 0),则自动向infr_whitelist(source=auto)登记一条 30 天豁免(ip/32),并跳过封禁。
自动无辜判定仅限
srct_tx。kts_tx(Kitsune ML)只会读取并据此过滤白名单 —— 它不做信誉查询,也不做自动登记。
6. cidrList() —— 供代码生成复用
WhitelistService::cidrList() 返回去重后的生效中且未过期的 CIDR 列表(30 秒缓存)。当规则与阈值页面生成 srct_tx/kts_tx 脚本时,这份列表会作为 CDN_WHITELIST_CIDRS 常量的数据源注入 —— 于是在界面上管理的豁免就流入了实际的采集器代码。
数据来源
表 infr_whitelist(连接:legacy_glory,迁移 000734)
| 列 | 类型 | 说明 |
|---|---|---|
id |
bigint PK | |
cidr |
varchar(43) unique | 规范化后的 IP(/32)或网络(/n) |
label |
varchar(120) null | 是什么/属于谁 |
source |
varchar(12) | manual / auto / seed |
reason |
varchar(500) null | 自动判定的依据(信誉评分/类别) |
country |
varchar(4) null | 国家代码 |
expires_at |
datetime null | NULL = 永久 |
is_active |
tinyint(1) | 生效标志 |
created_by |
int null | 登记者的用户 id |
created_at / updated_at |
timestamps |
索引:(is_active, expires_at)、source。
infr_whitelist建在legacy_glory(GLORY)数据库上。如果legacy_glory没有配置为 mysql/mariadb,迁移和种子脚本会被守卫为空操作 —— 页面照常渲染,但 KPI 读出来都是 0。在实际部署中必须填好 GLORY 连接。
种子脚本 InfrWhitelistSeeder(source=seed,永久)
把原先硬编码的 CDN/OFFICE 网段迁移进来(借助 firstOrCreate 实现幂等)。其中包含 Cloudflare、Google、Meta、AWS、Akamai 的前端网段,以及一个 OFFICE 固定 IP。
php artisan db:seed --class=InfrWhitelistSeeder
模型 · 服务
- 模型:
App\Models\Infr\InfrWhitelist(protected $connection = 'legacy_glory')。 - 服务:
App\Services\Security\WhitelistService——summary()(KPI,30 秒缓存)、page()(筛选/分页)、add()/remove()(写入)、cidrList()(代码生成数据源)、normalizeCidr()(静态 SOT)。 - 控制器:
App\Http\Controllers\Security\WhitelistController——index·live·add·remove。
访问权限
| 操作 | 最低等级 | 备注 |
|---|---|---|
| 进入/查看安全区域 | 安全菜单 min_req 2 |
demo(1) 看不到安全菜单 |
| 添加/移除白名单(写入) | 等级 ≥ 2 | WhitelistController::canWrite() = user_level >= 2 |
等级体系:demo=1 · staff=5 · admin=10。因此 staff 和 admin 既能读也能写;写入失败会返回 403 forbidden(提示"不允许(需要等级 2 及以上)")。
每一次写入都会记入 InfrAuditLog:
- 添加 →
sec.whitelist_add(target=ip,meta 中含id·reactivated)。 - 移除 →
sec.whitelist_remove(target=ip,meta 中含id)。
故障排查与常见问题
所有 KPI 都是 0,列表也是空的
legacy_glory 连接尚未配置,或者 infr_whitelist 表还不存在。请检查 GLORY 数据库设置并运行迁移/种子脚本。遇到数据库错误时,该服务会平稳地返回空值。
"不是有效的 IP/CIDR"(422)
输入不是 IPv4,或者前缀长度超出 0–32。不支持 IPv6。示例:203.0.113.10、203.0.113.0/24。
我输入的是 /24,但存下来的网段不一样
这是预期行为。主机位会被掩到网络地址(203.0.113.55/24 → 203.0.113.0/24)。
重复添加同一个 IP 会产生重复条目吗?
不会。cidr 是唯一的,因此已有条目会被重新启用,并更新其有效期和名称(响应中带 reactivated: true)。如果已有条目来源是 seed,来源仍保持 seed。
为什么会出现 auto 条目/我可以删除它们吗?
那是 srct_tx 判定某个 IP 确凿无辜后,自动登记的一条 30 天豁免。你可以删除它,但如果该 IP 再次被误判,它可能会被重新登记。
过期的条目会自动消失吗?
记录行仍会保留,只是过了有效期后就不再计入"生效中"。把状态筛选切换到已过期/全部即可看到它们。要彻底清除请使用移除。
我已经豁免了某个 IP,但它仍然被封禁
请检查:(1) 规范化后的网段是否真的覆盖了该流量 IP(例如 /32 与 /24 的差别);(2) cidrList() 的缓存(30 秒),以及采集器脚本是否已重新生成;(3) blacklist_info 中是否已经存在封禁记录。已有的封禁必须从封禁列表中解除。
相关条目
- 封禁列表与信誉 —— 封禁名单管理(与豁免相反)
- 自动封禁 —— 调度器自动封禁(白名单/无辜判定的否决)
- 威胁 —— IDS 威胁研判、IP 下钻
- 规则与阈值 —— srct_tx/kts_tx 常量 + cidrList 注入
- IP 信誉 —— 应用内 AbuseIPDB 查询
- 审计日志 —— 审计写入操作
