4. HTTP请求中的输入载体
同一个HTTP请求里,输入并不只存在于“参数”这一个地方。URL查询串、路径段、请求头、Cookie、表单字段、JSON/XML请求体、上传文件,各自走不同的解析路径,被不同的组件读取,也因此有不同的注入面。理解这些载体的解析机制差异,是按载体设计验证规则的前提。
一、请求结构:输入载体的物理位置
一个典型的HTTP请求可以拆成请求行、请求头和请求体三部分。请求行里包含方法、路径和查询串;请求头是键值对集合;请求体则承载表单、JSON、XML或二进制文件。不同位置的输入,在服务端被解析的时机和组件完全不同。
二、各载体的解析机制与风险差异
URL查询参数位于问号之后,以&分隔键值对。服务端框架通常自动解码百分号编码和+号。风险在于:参数值可能被直接拼入SQL、日志或重定向地址,导致SQL注入、日志伪造或开放重定向。验证时应按参数语义限定类型和长度,例如page只允许正整数,sort只允许白名单字段名。
路径参数嵌入在URL路径中,如/users/42/orders中的42。它常被路由框架提取为变量,但路径段本身可能包含编码后的斜杠或点号,若未规范化就用于文件路径拼接,会引发路径穿越。验证策略是:先做URL解码,再检查是否匹配预期格式(如纯数字ID),拒绝包含..、/、\的值。
表单字段通过application/x-www-form-urlencoded或multipart/form-data提交。前者将键值对编码为name=Alice&role=user,后者用边界分隔多个部分,可同时携带文本和文件。表单字段的风险在于批量赋值:攻击者可能提交role=admin覆盖隐藏字段。验证时应使用白名单字段,对每个字段独立校验,而不是直接信任整个表单对象。
JSON/XML请求体由Content-Type声明,服务端用对应解析器反序列化。JSON的风险包括深层嵌套导致解析耗尽、类型混淆(字符串"1"与数字1)、以及原型污染(如__proto__键)。XML则额外面临外部实体注入(XXE)和实体扩展攻击。验证时需限制请求体大小、嵌套深度,并对每个字段做类型和范围检查;XML解析器应禁用外部实体。
HTTP头是键值对集合,常被用于传递认证令牌、语言偏好、客户端信息。风险在于:X-Forwarded-For可被伪造用于绕过IP限制,User-Agent可能被写入日志导致日志注入,自定义头可能被直接拼入响应头导致响应拆分。验证时应只信任由可信代理设置的转发头,对写入日志或响应的头值做换行符过滤。
Cookie通过Cookie头传递,服务端解析为键值对。Cookie常承载会话ID,若未设置HttpOnly和Secure,易被XSS窃取。此外,Cookie值可能被用于服务端模板或数据库查询,导致注入。验证策略是:会话Cookie只做存在性和格式校验,业务Cookie按字段语义校验,并始终设置安全属性。
文件上传通过multipart/form-data提交,服务端解析出文件名、内容类型和二进制内容。风险包括:文件名路径穿越、内容类型伪造、文件内容携带恶意脚本或病毒。验证时应检查文件扩展名白名单、内容类型与实际内容是否一致、文件大小限制,并将文件存储在Web根目录之外,重命名后保存。
三、按载体设计验证规则的思路
不同载体的解析机制决定了验证规则不能一刀切。可以按以下维度建立设计思路:
- 解析时机:查询参数和路径参数在路由阶段解析,请求体和文件在业务处理阶段解析。越早解析的输入,越需要在框架层做基础约束。
- 信任边界:HTTP头中的
X-Forwarded-For、Host等可能被伪造,应视为不可信;而由反向代理注入的头可视为半可信。Cookie中的会话ID由服务端签发,可视为可信但需防篡改。 - 数据类型:查询参数和表单字段本质是字符串,需显式转换类型;JSON字段有原生类型,但仍需校验范围;文件是二进制流,需校验魔数和大小。
- 注入面:路径参数和文件名易触发路径穿越;查询参数和表单字段易触发SQL注入和XSS;JSON/XML易触发反序列化漏洞和XXE;HTTP头易触发响应拆分和日志注入。
按载体设计验证规则的检查清单(示例):
| 载体 | 解析组件 | 关键验证点 | 典型风险 |
|---|---|---|---|
| URL查询参数 | 路由/框架 | 类型、长度、白名单 | SQL注入、开放重定向 |
| 路径参数 | 路由 | 格式、禁止..和斜杠 | 路径穿越 |
| 表单字段 | Body解析中间件 | 字段白名单、逐字段校验 | 批量赋值、XSS |
| JSON/XML | Body解析中间件 | 大小、深度、类型、禁用外部实体 | 原型污染、XXE |
| HTTP头 | HTTP服务器 | 信任来源、换行符过滤 | 响应拆分、日志注入 |
| Cookie | HTTP服务器 | 安全属性、格式校验 | 会话劫持、注入 |
| 文件上传 | 文件处理模块 | 扩展名、魔数、大小、存储路径 | WebShell、路径穿越 |
实际落地时,建议在请求进入业务逻辑之前,先按载体分类做一次“入口校验”:对查询参数和路径参数做格式与范围检查,对请求体做大小和结构限制,对HTTP头和Cookie做信任标记,对文件做类型和大小检查。这样,后续业务代码可以基于已校验的输入继续处理,减少重复防御。验证规则应随载体不同而调整,而不是用同一套正则覆盖所有输入。
注意:不要因为某个载体“看起来不常被攻击”就跳过验证。例如User-Agent头常被忽略,但它可能被写入数据库并在后台管理页面展示,形成存储型XSS。每个进入系统的输入载体都应被纳入验证范围。