http走私攻击源于前后端服务器对content-length与transfer-encoding头解析不一致,python中若手动设置或未清理双header(如cl+te),尤其在代理场景下易触发该漏洞。

HTTP走私攻击与Python中Header处理的直接关联
Python本身不会导致HTTP走私,但用requests、urllib或自建HTTP客户端时,若手动拼接Content-Length和Transfer-Encoding,或复用连接时未清空header字段,就可能触发后端解析歧义——尤其是当你的服务作为前端代理(比如用Flask + requests转发请求)时,攻击者可利用双Header注入制造走私。
requests库中Content-Length被自动覆盖却仍出问题?
requests默认会根据data内容自动计算并设置Content-Length,如果你手动传入headers={'Content-Length': '123'},它**不会报错,但会静默忽略你的值**;更危险的是,若你同时传了data和files,它可能改用multipart/form-data并带上Transfer-Encoding: chunked(取决于底层urllib3版本),而你完全没感知。
- 永远不要手动设置
Content-Length或Transfer-Encoding,交给requests处理 - 如果必须控制编码方式(例如测试场景),改用
http.client或urllib3.PoolManager显式构造,避免黑盒行为 - 检查
urllib3版本:≥1.26.0默认禁用chunked上传,旧版本在data为生成器时会自动启用Transfer-Encoding,极易引发走私
用Flask做代理时,哪些Header必须删除或标准化?
当Flask接收请求再用requests转发时,原始请求里可能含恶意双Header(如两个Content-Length,或Content-Length + Transfer-Encoding),Flask默认会合并同名Header成列表,但requests只取第一个——这就埋下歧义种子。
- 转发前必须清理敏感Header:
del request.headers['Content-Length']、del request.headers['Transfer-Encoding'](哪怕它们不存在,用pop()更安全) - 对
Connection、Keep-Alive、Proxy-开头的Header一律丢弃,防止代理链污染 - 若需保留
Content-Type,确保其值是单字符串而非列表(request.headers.get('Content-Type', '')比request.headers['Content-Type']更安全)
如何验证你的Python服务是否仍存在走私风险?
最有效的验证不是看代码,而是抓包观察真实发出的请求字节流。用curl -v或nc手工构造含双Header的请求打到你的服务,再检查后端日志或响应延迟异常——很多走私漏洞在应用层无报错,只表现为请求“消失”或“错乱执行”。
- 测试Payload示例:
POST / HTTP/1.1 Host: example.com Content-Length: 44 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 Host: example.com Foo: x
- 关键观察点:你的服务是否把
GET /admin当成下一个请求处理?如果是,说明后端服务器(如Nginx、Apache)和你的Python层对Header解析不一致 - 真正修复点往往不在Python代码里,而在反向代理配置:Nginx需启用
underscores_in_headers off且禁用merge_slashes off,否则它会“帮忙”标准化Header,反而掩盖问题
走私漏洞的本质是协议解析层的信任错位,Python代码只是中间一环;盯着requests怎么发包,不如先确认你的网络路径上每台设备对Content-Length和Transfer-Encoding的优先级定义是否统一。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











