
授权与合规声明本文全部操作对象均为自建隔离靶场本机容器或隔离虚拟机涉及安全测试的环节必须以取得合法授权为前提。未经授权的渗透测试违反《中华人民共和国网络安全法》与《刑法》相关条款须承担相应法律责任。本文只讲环境配置、版本对照与靶场隔离不含任何攻击步骤、利用载荷与绕过手法请勿将文中环境指向任何非自有系统。一、现象有的报文里看得到长度有的根本没有1.1 一组对不上的印象学抓包的时候人会攒下几组互相矛盾的印象。用工具去请一个页面头部里能看到一个明显的长度字段数字摆在那里换一个上传大文件之类的请求翻遍头部却找不到任何长度再换一个场景报文里同时塞了两个看起来都跟长度有关的字段谁说了算没人讲。更麻烦的是教程反复强调看Content-Length可你自己抓的那一份里它压根没有出现。这三组印象凑在一起很容易得出一个错误结论“长度字段时有时无好像全看运气。”于是之后每分析一份报文都变成这次到底有没有的碰运气。1.2 边界不是应用层临时决定的换个角度就清楚了一段字节流在网上传接收方必须知道从哪里开始算消息体、到哪里算结束否则它要么一直等下去要么把下一个消息的开头也一起吞进来。这件事不可能由应用自己临时约定——它是协议层规定的而且规定的不是一条规则是一套有先后顺序的判定流程。这套流程写在RFC 9112HTTP/1.1里本次已逐字核对见附表 A核验日期 2026-10-06。本文要做的就是把消息体到哪里算结束这套判定顺序讲清楚。此后你再看任何一份抓包结果长度字段有没有就不再是运气问题而是一个按顺序往下走的问题。1.3 本篇要回答的三个问题顺着这条线本文只解决三件事消息体的存在是怎么被标记的第二章两个标记字段谁说了算第三章官方给出的判定顺序到底有几条第四章。第五、六章分别讲清这套顺序里最常出现的两种形态——分块传输以及容易被和它混为一谈的另一个编码第七章给一套照着走的抓包判断动作。本章可以带走的一句长度字段时有时无不是运气是协议用一套有顺序的规则在判定边界。二、消息体是怎么被标记存在的两个头字段2.1 请求里由这两个字段之一标示RFC 9112 §6 对请求里消息体的存在给了一句很短的原文「The presence of a message body in a request is signaled by a Content-Length or Transfer-Encoding header field.Request message framing is independent of method semantics.」B01这句话有两层意思。第一层好懂请求里到底有没有消息体、消息体到哪儿结束看的是Content-Length或Transfer-Encoding这两个头字段而不是看这条请求长什么样。第二层是那句加粗的补充——请求分帧与方法语义无关。也就是说用什么方法和这条消息怎么分帧是两件互不相干的事。GET 能不能带消息体、POST 是不是一定有消息体这类问题属于方法语义是另一篇文章的范围而分帧这件事本身不看方法。2.2 Content-Length 的适用前提没有 Transfer-Encoding这里有一个非常容易漏掉的前提。RFC 9112 §6.2 说当消息没有Transfer-Encoding头字段时Content-Length才提供预期大小十进制 octets也就是八位组——对有内容的消息而言它提供的正是判定数据与消息在何处结束所必需的分帧信息B13。注意措辞“没有Transfer-Encoding时”是这句话的前置条件不是一句可有可无的补充。规范还给了反向的一条硬规则逐字是「A sender MUST NOT send a Content-Length header field in any message that contains a Transfer-Encoding header field.」——发送方 MUST NOT 在任何一个含Transfer-Encoding的消息里发Content-LengthB13。想知道的该看哪个字段前提条件请求里有没有消息体Content-Length或Transfer-Encoding两者之一出现即表示有B01消息体有多长Content-Length仅当没有Transfer-EncodingB13消息体怎么分帧Content-Length的值同上B13含Transfer-Encoding时还能发Content-Length吗不能发送方MUST NOTB132.3 长度字段不是万能的把 2.2 那张表读一遍会发现一件反直觉的事Content-Length只有在另一个字段不存在的时候才轮到它说话。所以抓包里没有长度字段并不代表这条报文没有消息体——它只说明这次的边界不是由长度字段来定的。⚠️代码待验证# 观察点看请求头里到底带了哪一个边界字段# 本文未在本机实际运行该命令保留待验证标记curl-v-XPOST--dataa1https://example.invalid/echo# 关注头部里 Content-Length 是否出现、值是多少那还有什么办法定边界Transfer-Encoding。RFC 9112 §6.1 对它的定位是它列出为形成消息体而已经或将要施加在内容上的传输编码序列而且它的主要设计目的逐字是「primarily intended to accurately delimit dynamically generated content」B02——主要就是为了准确界定动态生成内容的边界。换句话说当内容在发送之前还不知道有多长时协议给了另一个工具来划边界而不是逼着你先把字节数清出来。本章可以带走的一句请求里消息体的存在由Content-Length或Transfer-Encoding之一标示且分帧与方法无关Content-Length只在没有Transfer-Encoding时才有话语权。三、两个字段同时出现定义是覆盖不是互斥3.1 为什么是覆盖一段历史原因初学者最容易卡在这里既然是二选一那为什么还会同时出现答案就写在同一节里——RFC 9112 §6.1 逐字说明「Early implementations of Transfer-Encoding would occasionally sendbotha chunked transfer coding for message framingand an estimated Content-Lengthheader field for use by progress bars. This is why Transfer-Encoding is defined asoverridingContent-Length, as opposed to them being mutually incompatible.」B10翻成白话早期的实现偶尔会两个都发——分块编码是真的用来分帧的而那个Content-Length是给进度条用的一个估算值。正因为历史上真的出现过这种两个都在的报文规范才把它定义成覆盖overriding关系而不是互斥关系B10。如果你一直以为这两个字段互斥、不会同时出现那么从这里开始就会一直对不上。3.2 同时出现时服务器可以怎么处理既然不互斥规范就得交代同时出现该怎么办。RFC 9112 §6.1 给的是一段带选择余地的规则服务器MAY 拒绝同时含Content-Length与Transfer-Encoding的请求或仅按Transfer-Encoding处理无论采取哪一种都 MUST 在响应之后关闭连接B11。这里有两个词要盯住。一个是MAY——“拒绝和只按 TE 处理是并列的可选项不是必须怎样把它读成服务器必须拒绝就失真了。另一个是MUST——不管选哪一条路关连接都是硬的规范给的理由是以避免潜在攻击”。同时含两个字段时规范怎么定情态动词服务器处理方式MAY拒绝或仅按Transfer-Encoding处理MAY可选项处理完之后MUST在响应后关闭连接MUST硬性3.3 HTTP/1.0 的消息带 Transfer-Encoding一律视为分帧有误还有一条更一刀切的规则服务器或客户端收到含Transfer-Encoding的HTTP/1.0消息MUST 视为分帧有误——注意即使这条消息里还带着Content-Length也照样算分帧有误处理完之后关闭连接B12。原因在第五章还会再见到一次Transfer-Encoding是HTTP/1.1 引入的官方一般假设只声明支持 HTTP/1.0 的实现不会处理传输编码内容B08。这条规则说明一件事两个字段同时在场在低版本里不是一道选择题直接判为分帧有误。本章可以带走的一句Transfer-Encoding与Content-Length是覆盖而非互斥源于一段历史同时出现时服务器 MAY 拒绝或只按 TE 处理、但 MUST 关连接HTTP/1.0 消息带 TE 一律视为分帧有误。四、官方给的判定顺序八条4.1 八条按优先级排列到这里正好回答第一章那个问题判定消息体到哪儿算结束官方给的是一张有先后顺序的清单。RFC 9112 §6.3 把这套判定按优先级排成八条B14。下面这张表是按规范原意整理的序号即优先级从上往下走命中哪一条就用哪一条。序号情形长度由什么决定依据①对 HEAD 的响应1xx / 204 / 304 响应一律由头字段之后第一个空行终止无论消息里有哪些头字段B14 ①②对 CONNECT 的 2xx 响应空行之后连接立即成为隧道客户端MUST 忽略其中的Content-Length/Transfer-EncodingB14 ②③同时有Transfer-Encoding与Content-LengthTransfer-Encoding覆盖Content-LengthB14 ③④有Transfer-Encoding且chunked 是最后一个编码由读取并解码分块数据决定直到编码指示数据完成B14 ④④′有Transfer-Encodingchunked不是最后一个响应由服务器关闭连接为止决定请求长度无法可靠确定服务器 MUST 回400并关连接B14 ④⑤无Transfer-Encoding且Content-Length无效分帧无效MUST 视为不可恢复错误唯一例外见正文B14 ⑤⑥有有效Content-Length无Transfer-Encoding其十进制值即预期消息体长度octetsB14 ⑥⑦是请求以上都不成立消息体长度为0没有消息体B14 ⑦⑧是响应且未声明长度由服务器关闭连接前收到的 octets 数决定B14 ⑧表里的第 ⑤ 条留了一个唯一例外规范的原意是除非那个字段值能被成功解析成逗号分隔列表、列表内所有值都有效且都相同这时就用那一个单一值否则一律按不可恢复错误处理。请求里出现这种情况服务器 MUST 回 400 并关闭连接代理在响应里遇到必须关闭到服务器的连接、丢弃响应、向客户端发 502用户代理在响应里遇到必须关闭到服务器的连接并丢弃该响应B14 ⑤。4.2 三条最容易被忽略的推论第一请求不靠关连接定界。§6.3 有一条注释逐字写着「Request messages are never close-delimitedbecause they are always explicitly framed by length or transfer coding, with the absence of both implying the request ends immediately after the header section.」B16——请求永远不是靠关闭来定界的两个字段都没有就意味着请求在头段之后立即结束。这正好解释了 4.1 表里的第 ⑦ 条。反过来说“靠关闭来定界这个特性主要为了向后兼容 HTTP/1.0而且规范也点明因为无法区分成功完成的、靠关闭来定界的响应和被网络故障中断的部分消息”服务器SHOULD尽可能生成用编码或长度定界的消息B15注意这里是 SHOULD。第二几个状态码是规则的后果。若一个请求含消息体却没有Content-Length服务器MAY回411Length RequiredB17服务器收到带自己不认识的传输编码的请求SHOULD回501Not ImplementedB07第六章再展开。这两个码本身怎么读不属于本文范围这里只用它们来记住哪一条规则被触发了。第三客户端的偏好是有理由的。发送含消息体请求的用户代理MUST发送有效的Content-Length或使用 chunked 传输编码B19——这是底线。但在此之上还有一条偏好若长度事先已知SHOULD 用有效的Content-Length而不是 chunked理由是某些既有服务即使理解 chunked仍会对它回 411B18常常是因为这些服务经由一个需要预先知道长度的网关实现。所以chunked 更新、更先进这个印象要改一改在这条偏好上能报出长度就报长度。⚠️代码待验证# 观察点看一个 HEAD 响应如何定界对应判定顺序第 ① 条# 本文未在本机实际运行该命令保留待验证标记curl-v-Ihttps://example.invalid/# 关注响应只有头段头段之后第一个空行即结束不看任何长度字段本章可以带走的一句边界判定是八条优先级清单自上而下命中即止请求永远不靠关连接定界两个字段都没有就等于头段之后立即结束。五、分块传输是怎么工作的5.1 它解决的是事先不知道多大Transfer-Encoding的列表里最常出现的一个编码值就是chunked分块。为什么它这么重要RFC 9112 §7.1 逐字说明「Chunked enables content streams ofunknown sizeto be transferred as a sequence of length-delimited buffers, which enables the sender toretain connection persistenceand the recipient toknow when it has received the entire message.」B20这一句把三个好处一并说清了内容是未知大小的流时也能传发送方可以保持连接的持久性不必靠关连接来表示我说完了接收方能知道整条消息什么时候收完。这正是 4.1 表里第 ④ 条要依赖的能力。规范对接收方还有一条能力底线接收方MUST 能解析chunked传输编码因为它在内容大小事先未知时对分帧起关键作用B03。分块传输的关键点规范怎么说出处解决什么未知大小的内容流也能传且保持连接持久、接收方能判断收完B20接收方的能力底线MUST 能解析chunkedB03能不能重复分块发送方MUST NOT对同一消息体多次施加 chunkedB03请求里还有别的编码时chunkedMUST放在最后一个B035.2 语法与读到 0 就算收完分块的语法很朴素。RFC 9112 §7.1 给出的形状是一块由chunk-size后面可能跟chunk-ext加 CRLF、再接chunk-data与 CRLF 组成其中chunk-size是1*HEXDIG一个或多个十六进制数字而收尾块写作last-chunk 1*(0) [chunk-ext] CRLFB21。当收到chunk-size为 0 的块——它后面可能跟一个 trailer 段、最后以空行终止——分块传输编码就算完成B21。请把这一句记住判定分块传完了的信号是那个大小写着 0 的块而不是连接断开。这也解释了 5.1 里保持连接持久是怎么做到的。5.3 三条使用纪律不许把大小限死。HTTP/1.1没有定义任何办法来限制分块响应的大小、从而让中介确信能缓冲整个响应。因此接收方MUST 预期可能很大的十六进制数字并防止因整数转换溢出或整数表示导致的精度丢失而出现的解析错误B22。chunked 不带参数。chunked 编码不定义任何参数其存在SHOULD被视为错误B23是 SHOULD不是 MUST。不认识的扩展要忽略。chunk 扩展用于提供每块的元数据例如签名或哈希、消息中段控制信息、或消息体大小的随机化接收方MUST 忽略不认识的 chunk 扩展B24。⚠️代码待验证# 观察点用 --raw 看分块响应的原始形态十六进制块大小 数据 CRLF# 本文未在本机实际运行该命令保留待验证标记curl--raw-vhttps://example.invalid/stream# 关注头部里是否出现 Transfer-Encoding: chunked# 以及数据区里是否出现以 0 收尾的块配套资料这一章讲的分块传输要点表 读到 0 即收完的判定连同后面的判定顺序表一起收进一份速查扫码即可获取本章可以带走的一句chunked 让大小未知的内容也能分帧收完的信号是大小写着 0 的那个块chunked 不带参数不认识的扩展要忽略。六、两个编码不是一个东西6.1 一个是消息的属性一个是表示的属性名字里都有编码Transfer-Encoding和Content-Encoding很容易被当成一回事。但 RFC 9112 §6.1 有一句逐字的话把它们拉开「Unlike Content-Encoding (Section 8.4.1 of [HTTP]),Transfer-Encoding is a property of the message, not of the representation.」B05传输编码是消息的属性内容编码是表示的属性。这是本文要划清的一条线Transfer-Encoding管的是这一条消息怎么在连接上被分帧、怎么被切块Content-Encoding管的是这个表示被怎么压缩过。二者作用的层次不同不能互相顶替。6.2gzip, chunked该怎么读规范给了一个官方示例Transfer-Encoding: gzip, chunked含义是内容先用 gzip 压缩、再分块以此形成消息体B04。读它的顺序要跟列表的书写顺序一致——从左到右就是施加顺序。正因如此5.1 里那条chunked 必须在最后才那么重要在请求里如果对内容施加了 chunked 以外的传输编码发送方MUST把 chunked 作为最后一个传输编码B03——因为分块是最后一道用于分帧的工序。对比项Transfer-EncodingContent-Encoding它是谁的属性消息的属性表示的属性管什么这条消息怎么在连接上分帧、切块这个表示被怎么压缩过典型值chunked可与其他编码并列chunked 在最后gzip、deflate、compress一类本文范围本文主线内容编码那一层另有专文本文不重写说明右列涉及的是 RFC 9110 §8.4 的方向属于另一篇文章的范围本文只做层次不同这一处对照。⚠️代码待验证# 观察点看响应里两个编码分别出现在哪一层# 本文未在本机实际运行该命令保留待验证标记curl-v-HAccept-Encoding: gziphttps://example.invalid/page# 关注Content-Encoding表示层与 Transfer-Encoding消息层是否同时出现6.3 三条硬规则1xx / 204 / CONNECT 的 2xx 不得带 TE。服务器MUST NOT在 1xxInformational或 204No Content响应中发送Transfer-Encoding也MUST NOT在对 CONNECT 请求的 2xx 响应中发送B06。这和 4.1 表第 ①、② 条能对上这些响应本来就没有消息体可言。不认识的传输编码回 501。服务器收到带自己不认识的传输编码的请求SHOULD回 501Not ImplementedB07是 SHOULD。这条恰好从反面印证了各接收方对编码的理解必须一致。版本边界。Transfer-Encoding是 HTTP/1.1 引入的官方一般假设只声明支持 HTTP/1.0 的实现不会处理传输编码内容B08。因此客户端MUST NOT发送含Transfer-Encoding的请求除非它知道服务器会处理 HTTP/1.1或更新的次版本请求服务器MUST NOT发送含Transfer-Encoding的响应除非对应请求表明是 HTTP/1.1或更新B09。一句话双方都是 HTTP/1.1 以上才轮到用 TE。本章可以带走的一句Transfer-Encoding是消息的属性、Content-Encoding是表示的属性两者不是一回事TE 只在双方都是 HTTP/1.1 以上时才用。七、把顺序用在抓包上7.1 一套照着走的判断顺序有了前六章遇到任何一份抓包消息体到哪儿结束都可以按下面这个顺序判断从上往下命中即止顺序先看什么结论1这条是请求还是响应请求不靠关连接定界响应的情形要多分几种2是不是 HEAD 的响应或 1xx / 204 / 304 响应是 → 头段之后第一个空行即结束不看任何长度字段3是不是对 CONNECT 的 2xx 响应是 → 空行之后即隧道忽略其中的Content-Length/Transfer-Encoding4有没有Transfer-Encoding有且 chunked 在最后 → 按分块读读到 0 的块为止chunked 不在最后 → 按请求/响应分别处理5没有 TE 时Content-Length有效吗有效 → 十进制值就是消息体长度无效 → 视为分帧错误6两个都没有且是请求消息体长度为 07两个都没有且是响应由服务器关闭连接前收到的 octets 数决定把这张表放回开头那三种印象里问题就都通了没有长度字段不代表没有消息体而是边界改由别的条款来定两个字段同时出现不是出错规范早有覆盖规则“教程说看Content-Length对不上”是因为那句口诀只在没有Transfer-Encoding这个前提下才成立。⚠️代码待验证# 观察点 1看请求头里到底带了哪一个边界字段# 本文未在本机实际运行保留待验证标记curl-v-XPOST--dataa1https://example.invalid/echo# 关注Content-Length 是否出现Transfer-Encoding 是否出现# 观察点 2看响应里是否用 chunked 定界curl-v--rawhttps://example.invalid/stream# 关注响应头是 Transfer-Encoding: chunked还是 Content-Length7.2 一条边界说明本文只讲规则不讲构造最后有一条必须交代清楚。分帧规则之所以定得这么细是因为**对边界理解不一致本身就是一个被规范点名的风险**。RFC 9112 §11.2 定义了请求走私这一类风险其定性逐字是「Request smuggling is a technique thatexploits differences in protocol parsing among various recipientsto hide additional requests (which might otherwise be blocked or disabled by policy) within an apparently harmless request.」B25——它利用的是各接收方之间协议解析的差异。也正因为如此本规范在 §6.3 引入了新的请求解析要求用来降低其有效性B25。相应地4.1 表第 ③ 条中两个字段同时出现那种消息规范的原意是ought to be handled as an error。本文只写官方对风险的定性以及规范因此收紧了哪些规则不写任何构造方式、不给任何报文样例也不评价任何具体产品的处理。想走得稳先把读这套顺序练熟——知道边界该由哪一条来定比记住任何一个字段名都重要。配套资料这套抓包判断顺序表连同八条判定清单、分块要点、两个编码的对照一起收进资料包扫码即可获取本章可以带走的一句判断边界从上往下走、命中即止规则只用来读报文不用来构造报文。附表 A本文引用事实与官方出处对照表#事实陈述一手出处来源名 章节核验日期本文位置1请求中消息体的存在由Content-Length或Transfer-Encoding标示逐字强调Request message framing is independent of method semanticsRFC 9112 §6 — https://www.rfc-editor.org/rfc/rfc9112.txt2026-10-06第二章2Transfer-Encoding的定位列出为形成消息体而施加的传输编码序列primarily intended to accurately delimit dynamically generated contentRFC 9112 §6.12026-10-06第二章3接收方MUST能解析chunked内容大小事先未知时对分帧起关键作用发送方MUST NOT对同一消息体多次施加 chunked请求里对内容施加 chunked 以外编码时 chunkedMUST在最后RFC 9112 §6.12026-10-06第五、六章4官方示例Transfer-Encoding: gzip, chunked内容先 gzip 压缩、再分块RFC 9112 §6.12026-10-06第六章5逐字Transfer-Encoding is a property of the message, not of the representation传输编码是消息的属性内容编码是表示的属性RFC 9112 §6.12026-10-06第六章6服务器MUST NOT在 1xx / 204 响应中发送Transfer-Encoding也MUST NOT在对 CONNECT 的 2xx 响应中发送RFC 9112 §6.12026-10-06第六章7服务器收到带自己不认识的传输编码的请求SHOULD回 501Not ImplementedRFC 9112 §6.12026-10-06第四、六章8Transfer-Encoding由HTTP/1.1 引入一般假设只声明支持 HTTP/1.0 的实现不会处理传输编码内容RFC 9112 §6.12026-10-06第三章、第六章9客户端MUST NOT发送含 TE 的请求除非知道服务器处理 HTTP/1.1服务器MUST NOT发送含 TE 的响应除非请求表明 HTTP/1.1RFC 9112 §6.12026-10-06第六章10历史原因逐字早期实现偶尔两个都发分块编码用于分帧 估算的Content-Length供进度条用故 TE 被定义为overridingContent-Length而非与它互斥RFC 9112 §6.12026-10-06第三章11服务器MAY拒绝同时含两字段的请求或仅按 TE 处理无论哪种都 MUST 在响应后关闭连接RFC 9112 §6.12026-10-06第三章12收到含 TE 的HTTP/1.0消息MUST视为分帧有误即使存在Content-Length处理后关闭连接RFC 9112 §6.12026-10-06第三章13Content-Length的适用前提没有Transfer-Encoding时才提供预期大小十进制 octets并给出分帧信息逐字发送方MUST NOT在任何含 TE 的消息里发Content-LengthRFC 9112 §6.22026-10-06第二章14消息体长度的判定顺序按优先级共 8 条含同时出现时 TE 覆盖 CL、chunked 是否在最后的分支、CL 无效的例外情形与各方处置RFC 9112 §6.32026-10-06第四章15因无法区分靠关闭定界的完成响应与被中断的部分消息服务器SHOULD尽可能生成用编码或长度定界的消息关闭定界主要为兼容 HTTP/1.0RFC 9112 §6.32026-10-06第四章16逐字Request messages are never close-delimited请求永远不靠关闭定界两者都没有则请求在头段之后立即结束RFC 9112 §6.32026-10-06第四章17服务器MAY对含消息体但无Content-Length的请求回 411Length RequiredRFC 9112 §6.32026-10-06第四章18长度已知时客户端SHOULD用有效Content-Length而非 chunked因某些既有服务即使理解 chunked 仍会回 411RFC 9112 §6.32026-10-06第四章19发送含消息体请求的用户代理MUST发送有效Content-Length或使用 chunked 传输编码RFC 9112 §6.32026-10-06第四章20chunked 的用途逐字让未知大小的内容流可传使发送方保持连接持久、接收方知道何时收完整条消息RFC 9112 §7.12026-10-06第五章21chunked 语法chunk-size 1*HEXDIG、last-chunk 1*(0) [chunk-ext] CRLF收到 chunk-size 为 0 的块即完成RFC 9112 §7.12026-10-06第五章22HTTP/1.1 未定义限制分块响应大小的方法接收方MUST预期可能很大的十六进制数字并防整数转换溢出/精度丢失RFC 9112 §7.12026-10-06第五章23chunked 编码不定义任何参数其存在SHOULD被视为错误RFC 9112 §7.12026-10-06第五章24chunk 扩展用于提供每块元数据等接收方MUST 忽略不认识的 chunk 扩展RFC 9112 §7.1.12026-10-06第五章25§11.2 对请求走私的定性逐字exploits differences in protocol parsing among various recipients本规范在 §6.3 引入了新的请求解析要求以降低其有效性RFC 9112 §11.22026-10-06第七章26本文未实测curl -v/curl --raw/curl -I等观察点未在本机实际运行相关代码块保留代码待验证标记本文未实测2026-10-06第二、四、五、六、七章待验证27本文未涉及待验证主流 web 服务器 / 反向代理对同时出现两个头的实际处理配置项名称逐产品未核本文只写 RFC 的规则不写某产品怎么配表 B-补 BX02待验证2026-10-06全文未写待验证附表 B术语速查表术语一句话解释消息体message body头段之后、由分帧规则划定边界的那一段数据分帧framing判定消息从哪开始、到哪结束这件事本文全篇主题Content-Length头字段仅在没有Transfer-Encoding时才给出消息体的预期大小Transfer-Encoding头字段列出为形成消息体而施加的传输编码序列属性属于消息chunked最常用的传输编码值把内容切成长度 数据的块收尾块大小为 0chunk分块传输里的一个块chunk-size 可选chunk-ext 数据chunk 扩展chunk-ext每块的附加元数据接收方MUST忽略不认识的last-chunk收尾块写作1*(0)它的出现表示分块传输完成Content-Encoding头字段指示表示被怎么压缩过属性属于表示本文只做对照表示representation内容编码所作用的那个对象与消息是不同的层次关闭定界close-delimited靠关连接来表示我说完了主要为兼容 HTTP/1.0请求永不用它覆盖overridingTransfer-Encoding与Content-Length同时出现时的关系而非互斥411 / 501分别是含消息体但无Content-Length与不认识的传输编码触发的规则后果代码待验证 / 待验证前者指命令未在本机实际运行后者指该项未实测或未取到逐字依据写在最后这篇用到的资料写这篇文章时我盯着有的报文看得到长度、有的根本没有这个画面想了很久最后发现它根本不是运气问题——消息体到哪儿算结束是 RFC 9112 用一套有先后顺序的规则定下来的。把顺序记住看任何一份抓包都知道该按哪一条去找边界。顺手也整理了几份配套的东西靶场环境对照表DVWA、upload-labs 在 Windows / macOS / Linux 三平台的可行性与推荐路径Web 安全学习路线图从基础打牢到安全管理四个阶段各学什么常用靶场清单每个靶场练什么、适合哪个阶段资料是我自己整理的放在下面这个码上扫码即可获取添加时备注「靶场」优先通过。拿到之后建议先看环境对照表那一份再回头把本文那张判定顺序表和抓包判断顺序表对照着过一遍下次再看到没有长度字段的报文就知道该往哪一条去找边界了。