概述 — 这个页面做什么
安全 ▸ 防火墙(/security/firewall)会把服务器群对外开放的每一个端口画进同一张暴露地图。它按风险(crit / warn / ok / unknown)为每个开放端口着色,并区分它究竟是已登记的服务(managed),还是意料之外的开放(unmanaged),让你立刻看清“外部能看到什么,以及为什么”。
它连接三个数据源:
infr_instance_firewall (per-instance firewall rules = open ports/services)
× infr_instance (host meta — public IP · criticality · env · status)
× infr_service (registered logical services — instance_id · port)
→ classified by FirewallLore → exposure map
- 这是一个只读控制台。 防火墙规则本身的编辑与采集属于 资产 ▸ 实例 ▸ [fw] 的职责;本页只是把那份台账重新组织成全局视图。
- 由于所有数据源都是新的
infr_表,它完全不会碰legacy_glory(Suricata、Kitsune 等)— 直接通过 Eloquent 查询,不需要SecurityRepository。 - 30 秒轮询(实时)。风险分类逻辑的正本位于
App\Support\FirewallLore,解释文本位于resources/lang/{ko,en}/fwlore.php。
职责边界:本页关注的是端口的物理开放与暴露(攻击面)。*逻辑上的服务可达性(健康检查)*属于 服务 ▸ 目录。同一个端口在两处的观察角度不同。
什么时候使用
- 盘点整个服务器群的攻击面 — “现在从外部能看到哪些端口?”
- 找出意料之外的开放 — 已经开放、却不是已登记服务的数据库、缓存或远程管理端口(未纳管的暴露)。
- 优先处置最严重的暴露 — 在拥有公网 IP 的主机上开放的 crit 风险端口。
- 一眼看出哪些主机开放了某个端口(按端口视图)。
- 查看单台机器暴露了什么、暴露了多少(按主机视图)。
- 了解某个端口为什么有风险、如何收敛(端口风险解读弹窗)。
页面布局
页头(HERO)
标题/副标题(Ports your fleet leaves open — attack-surface exposure map)、最近采集时间戳、LIVE / PAUSED 开关(30 秒轮询开/关),以及全屏按钮。
空状态
如果完全没有防火墙规则,会出现引导面板 — Go to Instances 按钮会把你带到 /asset/instances。从 实例 ▸ [fw] 导入 firewall-cmd 的结果,或通过远程模拟采集开放端口,地图就会填充起来。
KPI 条(5 个磁贴)
| KPI | 标签 | 定义 | 计算方式 |
|---|---|---|---|
| ports | 开放端口 | 所有主机的开放端口条目总数 | 已分类规则的条数 |
| hosts | 暴露的主机 | 至少开放一个端口的机器 | instance_id 去重 |
| crit | 危险暴露 | 被判定为 crit 的端口 | risk == 'crit' |
| unmanaged | 未纳管的暴露 | 既不是已登记服务、风险又不是 ok 的端口 |
!managed && risk != 'ok' |
| public_crit | 公网 · crit | 在拥有公网 IP 的主机上开放的 crit 端口 | crit && public |
公网 · crit 是有意为之的重复计数。 公网 IP 上的一个 crit 端口,已经计入
Risky exposure,(如果它不是已登记服务)也计入Unmanaged exposure— 但因为这个交集(public × crit)是整个服务器群中最严重的一类暴露,所以把它再一次单列为独立 KPI,确保没有任何一项被漏掉。如果这个磁贴不为零,请优先处理它。
暴露风险条
一条四色堆叠柱(crit·warn·ok·unknown)展示风险构成。下方的图例是点击筛选器 — 点击某个风险等级即可只保留该等级(再次点击取消)。柱条旁边的 coverage(例如 7 / 12 hosts collected)表示拥有防火墙规则的主机数与实例总数之比。
工具栏 · 筛选
- 视图切换:按端口/按主机。
- 协议:all / TCP / UDP。
- 风险:all / crit / warn / ok / unknown。
- 仅未纳管 复选框:只显示不是已登记服务的端口。
- 搜索:匹配端口 · 服务 · 主机(含别名)。
按端口视图
端口卡片网格。每张卡片显示端口/协议 · 服务标签 · 风险徽章、开放该端口的主机小标签(最多 8 个 + +N),页脚显示主机数 · 公网暴露数 · 类别。点击卡片 → 端口详情 + 风险解读弹窗。排序依据为风险 → 主机数 → 端口号。
按主机视图
主机卡片网格。每张卡片显示主机名 · 别名 · env · 重要度、公网徽章、该机器开放的端口小标签(按风险着色,若为已登记服务则带 check-decagram 标记),页脚显示各风险等级的数量 · 端口总数。点击端口小标签 → 打开同一个详情弹窗。排序依据为 crit 数量 → warn 数量 → 端口数。
端口详情 + 风险解读弹窗
端口/协议 · 服务名 · 风险徽章 · 类别,外加 fwlore 的三段式说明:
- 这是什么(what) — 该端口是什么服务。
- 为什么有风险(why) — 它的暴露可能导致哪些攻击。
- 建议处置(best) — 如何收敛这一暴露。
其下是开放该端口的主机列表(env · 重要度 · 区域 · 公网/内部 · 已纳管/未纳管徽章),以及一个 Manage in Instances ▸ [fw] 链接。
使用方法
- 若 LIVE 处于开启状态,页面每 30 秒刷新一次。如果调查过程中跳动的数值让你分心,请切换到 PAUSED。
- 首先查看 公网 · crit 这个 KPI — 如果它不为零,点击风险图例中的
crit收窄按端口视图,然后优先处理带有公网小标签(地球图标)的主机。 - 用 仅未纳管 分离出“意料之外的开放”。如果这里出现了并非已登记服务的数据库(3306/5432/27017)、缓存(6379/11211)、Docker(2375)或远程管理(23/3389/VNC),请立即收敛。
- 点击端口卡片,阅读解读弹窗中的 why/best,然后沿
Manage in Instances ▸ [fw]去收紧规则,或将其登记为服务。 - 真正关闭端口或编辑规则不在这里完成,而是在目标主机的防火墙上,以及 实例 ▸ [fw] 中完成。本页是一张地图和一件审计工具。
风险分类规则(FirewallLore)
端口字符串可以是单个值(8080),也可以是一个范围(6081-6100)。范围按其起始端口与常用端口映射表比对。
| risk | rank | 含义 | 示例 |
|---|---|---|---|
| crit | 3 | 一旦暴露即刻危险 — 数据存储 · 远程管理 · 文件共享 · 容器 | MySQL 3306, Redis 6379, RDP 3389, SMB 445, Docker 2375, k8s-api 6443 |
| warn | 2 | 需留意 — 管理类 · 遗留 · 非标准 | SSH 22, SMTP 25, 8080/8443, SNMP 161, Grafana 3000 |
| ok | 1 | 标准的对外服务 | HTTP 80, HTTPS 443, DNS 53, NTP 123, WireGuard 51820 |
| unknown | 0 | 未映射 — 需要复核 | 不在目录中的端口/范围 |
- VNC 段(5900–5910) 作为范围而非逐条处理,判定为
remote_admin · crit。 - 属于
unknown的较宽端口范围(例如6081-6100)会被至少提升为 warn,因为范围越宽,攻击面越大。 - 对于未映射的端口,如果提供了服务标签,则会显示出来供参考,但风险仍保持
unknown;如果没有标签,前端会渲染为Unknown service。
纳管判定
已登记服务的映射以 infr_service.instance_id : port 为键。如果该实例在这个端口上有已登记的服务,则该规则为已纳管(check-decagram 标记、managed_name)。范围端口按其**起始端口(low)**匹配。没有已登记服务时该规则即为未纳管 — 并且如果其风险不是 ok,就会计入 Unmanaged exposure 这个 KPI。
数据来源
| 表/来源 | 作用 | 由谁写入 |
|---|---|---|
infr_instance_firewall |
每个实例的开放端口/服务规则(台账) | 资产 ▸ 实例 ▸ [fw] — 手动 CRUD / firewall-cmd --list-all 原始文本导入 / scripts/infr_firewall_probe.cjs JSON 导入 |
infr_instance |
主机元信息 — name · alias · env · criticality · status · ip_public |
资产 ▸ 实例 |
infr_service |
已登记的逻辑服务(instance_id · port · name · kind)→ 纳管判定 |
服务 ▸ 目录 |
App\Support\FirewallLore |
端口 → {key,label,category,risk,icon} 分类正本(与语言无关) | 代码 |
resources/lang/{ko,en}/fwlore.php |
按风险等级与类别的 what/why/best 解读 | 语言包 |
infr_instance_firewall 的规则结构(UNIQUE instance_id, zone, proto, port):
{
"zone": "public",
"ports": [
{ "port": "22", "proto": "tcp", "service": "ssh" },
{ "port": "443", "proto": "tcp", "service": "https" },
{ "port": "3306", "proto": "tcp", "service": "mysql" },
{ "port": "6081-6100", "proto": "tcp", "service": "" }
]
}
[fw] 的导入器同样能解析 firewall-cmd --list-all 的原始文本(区域标题 → services: 映射 → ports: 直接读取):
public (active)
services: http https ssh
ports: 8080/tcp 6081-6100/tcp 3306/tcp
构建好的仪表盘在服务端缓存 30 秒(infr:sec:firewall:dashboard)。当完全没有规则时,它返回一个空负载(empty=true),从而渲染引导状态。
访问权限
- 查看:整个
/security/*前缀都被infr.level:2中间件包裹 → 仅限 staff(5)及以上(内部判定为user_level >= 2)。demo(1)被完全挡在安全数据之外。 - 本页没有写操作(纯读取)。防火墙规则的编辑与导入在 资产 ▸ 实例 ▸ [fw] 中进行,并以级别 ≥ 2 + 审计日志把关。
- 级别体系:demo=1 · staff=5 · admin=10(部分区域会追加
infr.level:N把关)。参见 RBAC 级别。
排查与常见问题
我只看到空白页面(“还没有防火墙数据”)。
这说明 infr_instance_firewall 中没有任何规则。把 firewall-cmd --list-all 的结果粘贴到 资产 ▸ 实例 ▸ [fw] 中导入,或通过远程模拟采集开放端口。
某个端口显示为 Unknown service。
该端口不在 FirewallLore 目录中(风险为 unknown)。如果它是正当服务,请在 服务 ▸ 目录 中登记,或在 [fw] 规则的 service/note 中补上标签。如果并不需要,就把它关掉。
它是已登记的服务,却显示 unmanaged。
纳管判定要求在同一个实例上、在该端口存在 infr_service。如果服务位于另一台主机或另一个端口,就不会匹配。范围端口只按其起始端口匹配。
Risky exposure 不为零,但 Public · crit 是 0。
这说明所有开放 crit 端口的主机都仅限内部(没有 ip_public)— 暴露半径较小,因此相对更安全。不过仍应收敛它们,以应对内部威胁与横向移动。
数值不是实时的。 可能 LIVE 处于 PAUSED,或者标签页处于后台。仪表盘在服务端缓存 30 秒,因此在 [fw] 中改动规则后的最多 30 秒内,你可能仍会看到旧值。
我能在这里关闭端口吗? 不能。本页是一张只读地图。实际封堵在目标主机的防火墙上完成,规则台账的更新在 实例 ▸ [fw] 中完成。
相关内容
- 资产 ▸ 实例 ▸ [fw] — 防火墙规则台账 · 这张地图的写入侧(采集 · 编辑 · 导入)
- 远程模拟 · 通过 tlx.php 探针采集开放端口
- 服务 ▸ 目录 · 已登记服务(纳管判定) · 逻辑可达性
- 资产 ▸ 实例 · 实例元信息(公网 IP · 重要度)
- 安全 ▸ 概览 · 安全控制台入口(防御漏斗)
- 管理 ▸ 运维策略 · “监控端口”选择器复用了 FirewallLore 的端口目录
