修复Python Web项目SSRF漏洞,核心是阻断用户输入对请求目标的完全控制权,必须结合协议限制、域名白名单、IP段校验、DNS解析后端点验证四层防线,且所有校验须在发起网络请求前完成。

直接上结论:修复Python Web项目SSRF漏洞,核心是**阻断用户输入对请求目标的完全控制权**,不能只靠黑名单过滤或简单正则匹配;必须结合协议限制、域名白名单、IP段校验、DNS解析后端点验证这四层防线,且所有校验必须在发起网络请求前完成。
requests.get() 传入用户URL前必须做目标校验
绝大多数SSRF漏洞就出在这里——把 request.args.get('url') 或 request.json.get('target') 直接喂给 requests.get()。这不是“用了requests库就安全”,而是把校验责任推给了第三方库,而 requests 本身不校验目标是否内网、是否危险协议。
实操建议:
- 禁止直接拼接用户输入到
requests.get(url),哪怕加了timeout=5也无济于事 - 必须先调用自定义校验函数,例如
is_safe_target(url),返回True才放行 - 校验函数内部要解析URL:用
urllib.parse.urlparse()拆出scheme、netloc、path,再分别处理 - 拒绝
file://、dict://、gopher://、ftp://等非HTTP协议(scheme not in ('http', 'https')) - 对
netloc做DNS解析并检查IP,不能只靠字符串匹配(避免127.0.0.1.xip.io绕过)
白名单机制不能只写域名,必须校验解析后的IP
只写 if url.startswith('https://api.example.com'): 是无效的。攻击者可用 api.example.com@192.168.1.100 或 DNS重绑定(DNS rebinding)绕过,最终请求仍发往内网。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 对用户提供的域名做真实DNS解析(用
socket.gethostbyname()或dns.resolver.resolve()),获取全部A记录/IP - 逐个检查每个IP是否属于允许范围:排除
127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、169.254.0.0/16、::1、fd00::/8等私有地址段 - 若域名解析失败或超时,应拒绝请求,而不是 fallback 到默认地址
- 生产环境禁用
allow_redirects=True(默认值),或手动拦截3xx响应中的Location头,防止跳转到内网地址
使用 urllib3 或 requests 的 mount + adapter 限制出口IP
更底层的防护是在HTTP客户端层面掐断内网访问能力,比应用层校验更可靠。适用于无法修改业务逻辑、但能调整HTTP客户端配置的场景。
实操建议:
- 自定义
requests.adapters.HTTPAdapter子类,在send()方法中提前校验request.url - 或用
urllib3.util.connection.create_connection()替代原生 socket,插入IP白名单检查逻辑 - 推荐方案:用
requests.Session()+ 自定义 adapter,全局替换项目中所有requests.get调用 - 注意:不要在 adapter 中做耗时DNS解析,否则拖慢正常请求;可缓存已验证域名的IP结果(TTL设为60秒)
文件读取类SSRF(如 file://)必须彻底禁用协议解析
当功能涉及“远程加载图片”“导入RSS”“解析外部XML”时,容易忽略 file:// 协议。一旦后端用 requests.get() 或 urllib.request.urlopen() 处理用户提交的URL,file:///etc/passwd 就会直接读取服务器本地文件。
实操建议:
- 显式禁止
file协议:校验时强制parsed.scheme in ('http', 'https') - 若业务真需读本地文件(极少见),应走独立路径,比如限定目录前缀
/var/www/uploads/,且用os.path.realpath()防路径遍历 - XML解析器(如
lxml、xml.etree.ElementTree)默认支持外部实体(XXE),必须禁用:parser = etree.XMLParser(resolve_entities=False) - PDF/DOCX等文档解析库(如
pdfminer、python-docx)若接受URL参数,同样要走同一套目标校验流程
最易被忽略的是:SSRF防护不能只做一次校验。当服务支持重定向、支持URL编码嵌套(如 %68%74%74%70%3a%2f%2f)、支持IPv6缩写(如 ::1),或前端做了二次编码而服务端未解码就校验,都会让整套防护失效。校验必须放在真正发起网络请求前的最后一环,且覆盖所有可能入口——包括 query string、JSON body、form data、甚至 header 中的回调地址。


















