☰
A.协议与Web基础1(HTTP请求走私)
2026/9/27 21:54:41 网站建设 项目流程

(最近发现自己的基础特别差,恶补一下,这边用问答的方式来学习)

核心问题1:

1、HTTP请求走私(CL.TE / TE.CL)为什么会产生?前端代理和后端服务器的解析差异在哪?

具体展开:

(以下均为个人理解:查了资料以后,自己手写的理解;有问题欢迎指正)

需要搞懂的基本概念:

前端服务器&后端服务器:

你= 客户端(浏览器)

服务员= 前端代理(比如 Nginx、CDN节点、负载均衡器)。你只跟服务员说话。

厨师= 后端服务器(真正处理业务的程序,比如 Tomcat、Node.js)。

你的请求是先给“服务员”,服务员再转交给“厨师”。

HTTP/1.0和HTTP/1.1去区别:

HTTP/1.0是每次请求建通道后,请求完又把通道拆掉,再次请求又需要重新建通道,很慢。

HTTP/1.1(长连接):请求后保持一条TCP通道,可以连续发多个请求。

CL和TE的区别:

既然建立了长连接那怎么知道第一个请求何时结束,第二请求何时开始呢?就引入了CL和TE两种方法。

方法A:Content-Length(简称 CL)

例如:请求包中有Content-Length: 13,后端就往后读13个字节,读完这个请求就结束。

方法B:Transfer-Encoding: chunked(简称 TE)

简单理解就是:每次传输不知道总长度,一块一块发,每块前面标明这块多大。当我发一个大小为0的块时,表示结束。

一般格式如下:

5\r\n (表示下一块有5个字节) Hello\r\n (具体的5个字节) 0\r\n (大小为0,表示全部发完了!) \r\n (结束的换行符)

RFC标准规定:如果一个请求同时带了 CL 和 TE,应该以 TE 为准,忽略 CL。

漏洞理解:

假设“服务员”(前端代理)和“厨师”(后端服务器)用的是不同公司写的软件(比如前端是 Nginx,后端是 Tomcat)。

如果故意发了一个畸形(不规范)的请求,里面同时包含了 CL 和 TE,前端和后端对于请求的大小可能就会产生分歧。

详细拆解 CL.TE 和 TE.CL

只是前后端的数据大小判断方式不同:

CL.TE = 前端用 Content-Length,后端用 Transfer-Encoding。

TE.CL = 前端用 Transfer-Encoding,后端用 Content-Length。

可以利用这两种方法构造“幽灵请求”

场景一:CL.TE(前端认CL,后端认TE)

攻击者发送如下原始数据给前端:

POST / HTTP/1.1 Host: example.com Content-Length: 13 Transfer-Encoding: chunked 0 SMUGGLED

前端知道大小是13会全部传给后端,但是后端看到0,觉得请求已经结束。

后面的SMUGGLED后端认为它是下一个新请求的开头! 此时,如果有正常用户发来了一个请求GET /admin HTTP/1.1...。 后端会把滞留的SMUGGLED和正常用户的请求拼起来,变成:SMUGGLEDGET /admin HTTP/1.1...,从而执行攻击者想要的操作。

场景二:TE.CL(前端认TE,后端认CL)

攻击者构造如下请求:

POST / HTTP/1.1 Host: example.com Content-Length: 3 Transfer-Encoding: chunked 6\r\n GOTCHA 0\r\n \r\n

前端遵守TE,知道第一块是6,第二块是0,可能直接原样转发给后端。(也可能会把 chunked 格式去掉,重新计算真实长度并加上新的 CL 头)

后端却忽略TE只看CL,只认Content-Length: 3。 后端只读了前3个字节(即6\r\n),就认为这个请求结束了。

会产生这样的情况:前端认 TE 读完了整个请求,但后端只认 CL 读了一点点就停了,剩下的全变成了“幽灵”。

前后端解析差异产生的原因

  1. 畸形 TE 头(容错处理不同): 黑客故意把Transfer-Encoding: chunked写成奇怪的样子,比如:

    Transfer-Encoding: chunked2 (多了个2) Transfer-Encoding: CHUNKED (大写) Transfer-Encoding : chunked (冒号前加了空格) Transfer-Encoding: \tchunked (加了制表符)

    有些前端软件比较智能,会自动修复(规范化)这些错误,认出它是 TE;但有些后端软件也许比较死板,一看格式不对,直接忽略它,退回到使用 CL(fallback to CL)。这就产生了差异。

  2. 前端重写 Body: 有时候前端代理在转发时,会主动把 chunked 编码解开,转换成普通的带有 CL 的请求发给后端。如果转换过程中没处理好,也会导致两边认知不同。

  3. H2.CL 变体(HTTP/2 降级):HTTP/2 本身是没有 CL 和 TE 这种定界问题的(它有自己的帧结构)。但是很多架构是:客户端到前端用 HTTP/2,前端到后端降级成 HTTP/1.1。 前端在把 H2 翻译成 H1 的时候,如果不小心带上了错误的 CL 头,而后端又信了这个 CL,就会产生新的走私漏洞(叫 H2.CL)。(这个我目前还没学会,这边先了解一下)

危害

窃取他人请求体:黑客把幽灵请求构造为“把数据发到我的服务器”,当正常用户访问时,用户的密码/Cookie会被拼接到幽灵请求里发给黑客。

绕过前端 ACL(访问控制):前端代理可能拦截了/admin路径,但黑客通过走私,让后端直接收到/admin请求,绕过了前端的防火墙。

缓存投毒(Cache Poisoning):黑客走私一个恶意响应,让前端的 CDN 缓存下来,导致所有访问该网站的用户都看到黑客伪造的页面。

防御

前端拒绝歧义请求:前端代理如果发现一个请求里既有 CL 又有 TE,或者 TE 格式畸形,直接返回 400 Bad Request,拒绝转发。不要试图去“猜”或“修复”。

全链路 HTTP/2 端到端:HTTP/2 协议从根本上解决了这个问题(使用二进制分帧,不需要 CL 和 TE 来定界)。如果前端到后端也用 HTTP/2,就不会有这种转换导致的差异了。

补充概念:这边需要区别软件开发中的前后端分离

比较维度网络架构(如HTTP走私)软件开发(如前后端分离)
“前端”指的是什么反向代理服务器、网关、CDN、Nginx用户看到的界面(网页、App、Vue/React代码)
“后端”指的是什么真正处理业务的源站服务器(Tomcat等)提供数据和逻辑的服务器程序(Java/Python/数据库)
他们怎么交流通过底层的 TCP/HTTP 协议转发字节流通过约定的 API 接口(HTTP + JSON)交换数据
常见面试题HTTP走私、负载均衡、跨域配置、缓存穿透前后端分离优缺点、RESTful API、JWT鉴权、跨域(CORS)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询