介绍
Corner Shop 的订单应用从私有 PostgreSQL 数据库读取和创建记录。页面虽然正常,Visitor 却也能直接访问数据库。因此,应用正常并不意味着数据库边界安全。
你将比较真实连接,在预设的 Gateway 限制转发,同时保留订单和公共状态服务。只需基本终端操作能力。所有人物和记录均为合成数据。三个终端节点是网络命名空间独立、共享同一个实例内核的容器,并非三台独立虚拟机。
追踪订单及其网络路径
本步骤将创建真实订单,并比较两条数据库访问路径。应用是面向顾客的程序,数据库负责存储记录。打开 Order Page,找到 seed: Green tea,在 Order reference 中输入 practice-1,点击 Create tea order。新记录会存入 PostgreSQL,而不只是显示在页面上。
网络图列出每个节点的 IP 地址,用于标识网络目的地;端口则标识该地址上的服务。PostgreSQL 位于 172.28.20.10:5432,独立的公共状态服务使用端口 8001。App Client(172.28.10.20)需要数据库,而 Visitor(172.28.10.30)只需要公共状态。
切换到 App Client。预置的 tcp-probe 会建立真实 TCP 连接,最多等待三秒。两个参数分别是目的地址和端口:
tcp-probe 172.28.20.10 5432
预期输出 TCP OPEN。它只证明网络可达,不代表有权读取记录。psql 是 PostgreSQL 查询客户端。下面的命令仅向本次命令提供训练密码。引号把服务器、端口、用户、数据库和三秒连接超时组合为一个连接字符串。-c 执行引号内的 SQL;SELECT 从 orders 读取指定列,ORDER BY 对结果排序,分号结束 SQL 语句。
PGPASSWORD=training-only psql "host=172.28.20.10 port=5432 user=shopapp dbname=shop connect_timeout=3" -c "SELECT id, item FROM orders ORDER BY id;"
在结果中找到 practice-1 和 Green tea。这个刻意公开的训练凭据将保持不变,以便单独观察网络边界的变化。
切换到 Visitor,重复两个命令:
tcp-probe 172.28.20.10 5432
PGPASSWORD=training-only psql "host=172.28.20.10 port=5432 user=shopapp dbname=shop connect_timeout=3" -c "SELECT id, item FROM orders ORDER BY id;"
两者都成功:非预期客户端既能连接,也能读取合成订单。密码无效时,连接到 PostgreSQL 后才会出现身份验证错误;网络端口仍然暴露。
路由告诉节点应将数据包发往何处。查看 Visitor 到数据库的预设路由:
ip route get 172.28.20.10
重点是 via 172.28.10.254(Gateway)和 src 172.28.10.30(Visitor)。App Client 使用同一个网关,但来源地址不同。数据库的返回路由指向 Gateway 的另一接口 172.28.20.254。两个客户端都没有直连数据库网段的接口。路由属于预设基础设施,请保持不变。本步骤的检查依据是真实订单,无需提交报告。
仅允许应用访问数据库
本步骤将在 Gateway 过滤经过的数据包。切换到 Gateway。iptables 修改内核中的数据包过滤规则。链是有序的规则列表,先匹配到的处理决定生效。FORWARD 处理穿过节点的流量,INPUT 处理以节点本身为目的地的流量。环境已将 FORWARD 接到实验专用的 LAB_FORWARD 链;其中初始的宽松规则造成了暴露。
先查看规则。-n 保留数字地址,-v 显示包计数,-L 列出指定链:
iptables -nvL LAB_FORWARD
只修改本终端内的 LAB_FORWARD。不要更改宿主机规则、路由、凭据或服务。规则立即生效,并在本次实验会话中持续有效。我们将用四项处理决定替换宽松规则;未匹配的数据包会被预设的父链拒绝。
-F 清空指定链。在添加规则期间,转发服务会短暂中断,但终端和 Order Page 入口仍可访问。若输入有误,从清空命令重新开始,再输入下面全部四条规则。
iptables -F LAB_FORWARD
响应也必须能够返回。例如,数据库发往 App Client 的回复,目的端口已不再是数据库端口。-A 追加规则,-m conntrack 使用连接跟踪,--ctstate ESTABLISHED,RELATED 匹配已允许连接的回复或关联流量。-j ACCEPT 放行匹配的数据包:
iptables -A LAB_FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
接着允许应用发起新连接。-s 匹配来源,-d 匹配目的地,-p tcp 选择 TCP,--dport 匹配目的端口。此处单个地址表示精确的那个节点:
iptables -A LAB_FORWARD -s 172.28.10.20 -d 172.28.20.10 -p tcp --dport 5432 -j ACCEPT
在应用例外之后添加通用数据库拒绝规则。省略 -s 会覆盖其他来源。REJECT --reject-with tcp-reset 显式拒绝 TCP 连接,而不是让客户端一直等到超时:
iptables -A LAB_FORWARD -d 172.28.20.10 -p tcp --dport 5432 -j REJECT --reject-with tcp-reset
最后,为两个客户端保留独立的公共状态端口。允许该服务不会开放数据库端口:
iptables -A LAB_FORWARD -d 172.28.20.10 -p tcp --dport 8001 -j ACCEPT
列出结果:
iptables -nvL LAB_FORWARD
顺序应为:回复、应用数据库访问、通用数据库拒绝、公共状态访问。拒绝规则若位于应用例外之前,商店也会被阻断。只有匹配流量实际经过 Gateway,包计数才会增加;存在规则本身不构成成功证据。刷新 Order Page:App Client 应显示 OPEN,Visitor 显示 BLOCKED,公共状态显示 PUBLIC STATUS OK,订单仍能加载。
复测安全边界与商店功能
本步骤将确认连接矩阵,并完成另一笔真实订单。切换到 App Client,发起新连接:
tcp-probe 172.28.20.10 5432
预期为 TCP OPEN。使用相同凭据再次读取:
PGPASSWORD=training-only psql "host=172.28.20.10 port=5432 user=shopapp dbname=shop connect_timeout=3" -c "SELECT id, item FROM orders ORDER BY id;"
切换到 Visitor:
tcp-probe 172.28.20.10 5432
预期出现 TCP BLOCKED 和连接被拒绝的说明。这个命令会故意返回失败状态。静默丢包则会导致超时;两者都会阻止新连接,但仅凭超时无法确定原因。若 App Client 也失败,请回到 Gateway 检查规则顺序与回复处理。
curl 用于获取 Web 资源。--max-time 4 将整个请求限定为四秒;-f 将 HTTP 错误视为失败,-s 隐藏进度,-S 仍显示错误。在 Visitor 检查另一项公共服务:
curl --max-time 4 -fsS http://172.28.20.10:8001/status.txt
预期为 PUBLIC STATUS OK。即使关闭了数据库路径,阻断所有转发数据包也无法满足此要求。
打开 Order Page,创建 practice-2,确认两笔练习订单均显示。这会在修复后实际使用应用的数据库连接。再刷新一次,Visitor 必须仍被阻断。Gateway 计数可帮助排查偏差,但真实订单加上允许与阻断测试,才是实际证据。不要通过停止 PostgreSQL 或修改密码,把访客查询失败伪装成安全修复。
总结
你追踪了订单进入 PostgreSQL 的过程,比较了两个经路由访问的客户端,应用有序转发规则,并分别验证安全性与可用性。密码错误不同于 TCP 连接被阻断。关闭暴露的数据库路径时,应保留合法应用和无关服务。



