Content-Length 是什么
Content-Length 声明报文实体的长度,单位是八位字节的十进制数值,接收方据此判断哪里是报文结束。它和 Transfer-Encoding 是互斥的两种长度判定方式:分块传输时不带 Content-Length,带长度时不分块。请求同时出现两者、或长度与实际字节数不一致时,前后端若理解不同,就会出现请求走私这类严重安全问题。
基本信息
| 方向 | 请求头与响应头都可出现 |
|---|---|
| 单位 | 八位字节(bytes),十进制整数 |
| 取值 | 0 表示空报文体;必须与实际字节数严格一致 |
| 互斥关系 | 与 Transfer-Encoding: chunked 不能同时使用 |
| 规范 | RFC 9110 §8.6、RFC 9112 §6.3 |
| 安全关联 | 请求走私(Request Smuggling)的关键字段 |
典型使用场景
- 调试上传接口:确认客户端声明的长度与实际发送的字节数一致
- 排查接口挂起:长度声明大于实际发送量时,服务端会一直等剩下的数据
- 理解分块传输:流式响应与不确定长度的场景改用 Transfer-Encoding
- 安全加固:网关层拒绝同时带两种长度声明或含重复 Content-Length 的报文
- 处理中文内容:按字节而非字符计算长度,避免被截断
读写与核对
读写与核对
# 空请求体
curl -X POST -H 'Content-Length: 0' https://api.example.com/ping
# 查看响应声明的长度与实际内容是否一致
curl -sI https://static.example.com/app.js | grep -i content-length
# 用实际字节数核对(wc -c 才是字节数,中文按字符算会少)
wc -c report.json
# 构造固定长度请求时显式给出长度
printf 'hello' | curl -X POST --data-binary @- \
-H 'Content-Length: 5' https://api.example.com/echo长度判定方式
| 方式 | 适用场景 | 注意点 |
|---|---|---|
| Content-Length | 已知长度的定长报文 | 必须与实际字节数严格一致 |
| Transfer-Encoding: chunked | 流式生成、长度未知 | 不能与 Content-Length 同时出现 |
| 两者同时出现 | 属于异常报文 | 应拒绝或按统一规则处理,否则可被走私利用 |
| 长度声明偏大 | 客户端提前断开 | 服务端一直等待余下数据,连接被占用 |
| 长度声明偏小 | 报文被截断 | 后端只读到前半段,出现解析错乱 |
计算长度时统计的是字节数而不是字符数:一个中文字符在 UTF-8 下通常占 3 个字节,按字符数写长度会导致服务端少读数据,出现 JSON 截断、文件损坏等难以直接归因的现象。
前端网关与后端应用对 Content-Length 与 Transfer-Encoding 的优先级判断不一致时,攻击者可以构造一个报文让两级服务器解析出不同的请求边界,从而实施请求走私:防御方式是统一编排层的判定规则,并对歧义报文直接返回 400。