IP 白名单偶尔漏判:处理 CIDR 和 IPv4 映射地址
同一个 IPv4 对端可能以 192.0.2.9 或 ::ffff:192.0.2.9 进入应用。先确定业务如何处理 IPv4 映射地址,再用 CIDR 成员关系判断。下面的策略把映射地址还原为 IPv4,白名单配置仍分别使用原生 IPv4 与 IPv6 网段。
1. 本机复现
保存为 cidr_lab.py,运行 python cidr_lab.py。地址只作匹配输入,脚本不发网络请求。
from ipaddress import IPv6Address, ip_address, ip_network
networks = tuple(ip_network(value, strict=True) for value in (
"192.0.2.0/28", "2001:db8:42::/48"
))
def allowed(value):
try:
address = ip_address(value)
except ValueError:
return False
if isinstance(address, IPv6Address):
if address.scope_id is not None:
return False
if address.ipv4_mapped is not None:
address = address.ipv4_mapped
return any(address.version == network.version and address in network
for network in networks)
for value, expected in (
("192.0.2.15", True),
("192.0.2.16", False),
("::ffff:192.0.2.9", True),
("::192.0.2.9", False),
("2001:db8:42::1", True),
("2001:db8:43::1", False),
("192.0.2.9:443", False),
):
result = allowed(value)
assert result is expected
print(f"{value} -> {result}")
try:
ip_network("192.0.2.9/28", strict=True)
except ValueError:
print("network with host bits: rejected")
else:
raise AssertionError("expected strict network validation")
本地实测输出如下。
192.0.2.15 -> True
192.0.2.16 -> False
::ffff:192.0.2.9 -> True
::192.0.2.9 -> False
2001:db8:42::1 -> True
2001:db8:43::1 -> False
192.0.2.9:443 -> False
network with host bits: rejected
2. 把对端来源和匹配规则分开配置
/28 固定 IPv4 的前 28 位,剩下 4 位给出 16 个地址。本例按前缀做成员匹配,因此 .15 仍在范围内。网络接口的广播地址、可分配地址等规则属于另一层。strict=True 会拒绝配置里的主机位,避免运营人员输入单个主机地址时无意中授权整个网段。
应用直连时,可以从连接元数据读取对端地址。部署在反向代理后,先确认哪一跳可信,以及该代理是否会覆盖应用读取的转发头。客户端自行提供的转发头不能直接作为白名单输入。地址与端口应从框架解析后的字段中分别取得,避免用冒号切割 IPv6。若决定把映射地址按 IPv4 处理,配置校验也应引导管理员用 IPv4 CIDR 表达对应规则。
小结
使用地址对象执行前缀匹配,明确映射地址的归类,再从可信连接链路获取待判定地址。
数据来源与检索时间
检索时间 2026-11-13。
| 来源 | URL | 对应内容 |
|---|---|---|
| RFC 4632 第 3.1 节 | https://www.rfc-editor.org/rfc/rfc4632.html#section-3.1 | CIDR 前缀表示与地址数 |
| RFC 4291 第 2.5.5.2 节 | https://www.rfc-editor.org/rfc/rfc4291.html#section-2.5.5.2 | IPv4 映射 IPv6 地址格式 |
| Python ipaddress | https://docs.python.org/3.11/library/ipaddress.html | 网段严格校验、成员关系与 ipv4_mapped |
核验说明
- Windows、Python 3.11.9 验证了 IPv4 边界、IPv6、映射地址、错误输入和带主机位的配置。真实代理链与白名单中间件需要结合部署另测。