KernelRanch
返回文章列表

IP 白名单偶尔漏判:处理 CIDR 和 IPv4 映射地址

2026-11-13 #network#cidr#ipv6

同一个 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.1CIDR 前缀表示与地址数
RFC 4291 第 2.5.5.2 节https://www.rfc-editor.org/rfc/rfc4291.html#section-2.5.5.2IPv4 映射 IPv6 地址格式
Python ipaddresshttps://docs.python.org/3.11/library/ipaddress.html网段严格校验、成员关系与 ipv4_mapped

核验说明

  • Windows、Python 3.11.9 验证了 IPv4 边界、IPv6、映射地址、错误输入和带主机位的配置。真实代理链与白名单中间件需要结合部署另测。