Python怎么做IP白名单_全局中间件拦截与IP网段CIDR校验实战

P粉602998670

P粉602998670

2026-04-26

689人浏览

原创

用 ipaddress 模块校验 cidr 网段需先解析为 ip_network 和 ip_address 对象再用 in 判断,禁用字符串直接比较;预加载白名单为 frozenset 提升性能,严格处理 ipv4/ipv6 及代理 ip。

python怎么做ip白名单_全局中间件拦截与ip网段cidr校验实战

怎么用 ipaddress 模块校验 CIDR 网段(别手写正则)

Python 自带的 ipaddress 是唯一靠谱的 IP 处理方案,别用正则匹配 CIDR,也别手动拆点分十进制。它能天然处理 192.168.0.0/16::1/128、甚至混合 IPv4/IPv6 的判断逻辑。

常见错误是把字符串当 IP 对象直接比较:"192.168.1.5" in "192.168.0.0/16" —— 这永远返回 False,因为这是字符串 in 字符串。

  • 必须先用 ipaddress.ip_network() 解析网段,用 ipaddress.ip_address() 解析客户端 IP
  • 校验用 ip_address in ip_network,不是字符串包含
  • 注意 ip_network() 默认严格模式:如果传入 "192.168.1.5/24"(主机位非 0),会抛 ValueError;加参数 strict=False 可自动归一化
  • IPv6 地址从 request.remote_addr 拿到时可能带 ::ffff: 前缀(IPv4-mapped),需用 addr.ipv4_mapped or addr 兼容处理
import ipaddress
<p>def is_in_whitelist(ip_str: str, cidr_list: list[str]) -> bool:
try:
ip = ipaddress.ip_address(ip_str)
except ValueError:
return False
for cidr in cidr_list:
try:
net = ipaddress.ip_network(cidr, strict=False)
if ip in net:
return True
except ValueError:
continue  # 跳过非法 CIDR,如 "abc/24"
return False
</p>

Django 全局中间件里怎么安全取真实客户端 IP

直接读 request.META.get("REMOTE_ADDR") 在 Nginx 反代后基本没用——它返回的是 Nginx 的内网地址(如 127.0.0.1)。必须依赖 X-Forwarded-For,但不能无条件信任。

容易踩的坑:没做代理链剥离,被伪造头绕过白名单;或没处理多级代理导致取错最左 IP。

  • 只信任你控制的反向代理(比如 Nginx)添加的 X-Forwarded-For,并在中间件里配置可信代理列表(settings.TRUSTED_PROXIES = ["127.0.0.1", "::1"]
  • request.META.get("HTTP_X_FORWARDED_FOR", "") 取值,按逗号分割后取第一个非可信 IP(即最“远”的原始客户端 IP)
  • 务必过滤空值、私有地址(127.0.0.0/810.0.0.0/8 等),防止攻击者填 X-Forwarded-For: 127.0.0.1, 1.2.3.4 绕过
  • 如果用的是 django-ipware 库,优先用它的 get_client_ip(request),它已内置上述逻辑

FastAPI 怎么在依赖项里拦截非白名单 IP(而不是写一堆 if)

FastAPI 的依赖注入机制比写中间件更轻量、更语义清晰。把 IP 校验封装成 Depends,所有需要保护的路由加一个参数就行,不用侵入业务逻辑。

Python 3.14.2
Python 3.14.2

Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。

下载

关键点在于:依赖函数必须抛出 HTTPException,否则会被静默忽略;且不能在依赖里直接操作 request.state 或修改响应流程。

  • 定义依赖函数,接收 request: Request,调用上面的 is_in_whitelist()
  • 校验失败时 raise HTTPException(status_code=403, detail="IP not allowed")
  • 路由中声明为依赖:def api_route(x: int, _: None = Depends(whitelist_check)):
  • 注意:依赖执行时机在路径操作函数之前,但晚于中间件;若需记录日志,得在依赖里自己 print 或打结构化日志
  • 不要在依赖里做耗时操作(如查数据库白名单),白名单应预加载为内存 list/set
from fastapi import Depends, HTTPException, Request
<p>async def whitelist_check(request: Request):
client_ip = get_real_ip(request)  # 复用上面的取 IP 逻辑
if not is_in_whitelist(client_ip, settings.WHITELIST_CIDRS):
raise HTTPException(403, "Forbidden: IP not in whitelist")
</p>

为什么用 set 存 CIDR 而不是每次 parse(性能差 10 倍以上)

每次请求都调用 ipaddress.ip_network(cidr) 是严重性能浪费。解析 CIDR 是纯 CPU 计算,不涉及 IO,但 Python 的 ip_network 构造开销大,尤其含 IPv6 时。

实测:1000 次 ip_network("10.0.0.0/8") 耗时约 8ms;而预解析后存进 set,每次只需 in 判断,耗时低于 0.01ms。

  • 启动时一次性解析全部白名单 CIDR,转成 frozenset[ipaddress.IPv4Network | ipaddress.IPv6Network]
  • 运行时只做 ip_address in network_obj,这是 C 层实现,极快
  • 别用 dict 存(key 是字符串 CIDR),那又退回到字符串匹配,失去网段语义
  • 如果白名单动态更新(如后台改配置),用线程安全的 concurrent.futures.ThreadPoolExecutor + 原子替换变量,避免 reload 时中间状态失效

复杂点在于 IPv4 和 IPv6 网段要分开存或统一用 ipaddress._BaseNetwork 类型判断;最容易被忽略的是没做异常兜底——某个 CIDR 写错(如 192.168.1.0/33),整个白名单初始化失败,服务起不来。必须在预加载阶段捕获并 warn,跳过非法项。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1104

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

2072

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1185

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

8820

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

1479

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

1551

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

881

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

531

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1111

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PyCharm官方快速入门指南
PyCharm官方快速入门指南

共0课时 | 0人学习

Python函数定义官方教程
Python函数定义官方教程

共0课时 | 0人学习

Python 3.14.6官方文档
Python 3.14.6官方文档

共0课时 | 0人学习