Apache HTTP Server在接收TCP连接后,第一件事就是从输入缓冲区中读取一行数据,也就是HTTP请求行。请求行虽然只有一行,却直接决定了后续路由、权限判断和协议处理逻辑。如果这一行格式不合法,Apache可能返回400 Bad Request,也可能在宽松模式下继续解析并把风险传导给后端应用。理解Apache对请求行格式的严格校验机制,有助于在安全性和兼容性之间做出合适配置。

请求行的标准结构与Apache的解析顺序
按照HTTP/1.1规范,请求行由三部分组成:请求方法、请求目标和协议版本,三者之间各用一个空格字符分隔,行尾必须是回车换行。一个合法请求行形如:GET /index.html HTTP/1.1。方法是一个token,只能包含字母、数字以及少量标点,不能包含空格;请求目标通常是一个绝对路径或绝对URI,空格必须先做百分号编码;协议版本固定为HTTP/0.9、HTTP/1.0、HTTP/1.1等,字母必须大写。
Apache解析请求行时会先定位第一个空格和第二个空格,把字符串切分成三段。注意切分不是简单的按空白连续处理,而是基于单个空格字符作为分隔符。也就是说,GET /index.html HTTP/1.1中方法后有两个空格时,第二段会成为空字符串,第三段变成/index.html,最终导致版本识别失败。严格模式下Apache会直接拒绝这类请求,而宽松模式可能尝试忽略多余空格,但这会带来解析差异。
这种差异在实际代理架构中非常危险。前端代理和后端源站如果对空格处理不同,攻击者就可以构造一种请求,让前端认为请求目标是A,后端却解析成B,从而实现缓存投毒或访问控制绕过。因此现代Apache默认推荐使用严格解析,尽量与标准保持一致。
HttpProtocolOptions Strict如何改变请求行校验
Apache提供的HttpProtocolOptions指令用于控制HTTP协议解析器的严格程度。该指令可以写进主配置或虚拟主机配置,常用参数包括Strict和Unsafe。启用Strict后,请求行必须完全符合RFC规范:方法后的空格只能有一个,请求目标中不允许出现未编码的控制字符,协议版本必须严格书写。启用Unsafe则会放宽这些限制,以兼容某些不符合规范的旧客户端。
下面的配置片段展示了如何在Apache虚拟主机中开启严格校验:
<VirtualHost *:80>
ServerName ipipp.com
HttpProtocolOptions Strict Require1.0
DocumentRoot /var/www/html
</VirtualHost>
其中Require1.0表示拒绝HTTP/0.9请求,因为HTTP/0.9没有状态行和协议版本,容易与异常数据混淆。如果需要兼容非常老旧的客户端,可以改用Allow0.9,但建议仅在明确知道需要时开启。还要注意,Strict与Unsafe是互斥选项,后设置的会覆盖前面的设置。
严格模式还会影响请求方法。默认情况下Apache只识别RFC定义的方法,例如GET、POST、PUT、DELETE等。如果客户端发送自定义方法,在严格模式下可能返回400或501,而使用LenientMethods可以允许扩展方法名。不过扩展方法名仍然不能包含空格或控制字符。
常见畸形请求行与响应表现
为了更直观地理解严格校验,可以构造几种典型的畸形请求行。第一种是方法后出现多个空格:GET /index.html HTTP/1.1。在严格模式下,Apache会返回400 Bad Request,并在错误日志中记录请求行解析失败。第二种是使用制表符代替空格:GET\t/index.html HTTP/1.1。一些旧客户端会发送这种格式,但RFC明确要求空格分隔,因此严格模式同样拒绝。
第三种是请求目标中包含原始空格:GET /index page HTTP/1.1。HTTP规范要求空格必须编码为%20,未编码的空格会提前终止请求目标。Apache在严格模式下会把它视为非法目标,返回400。第四种是行尾只发送LF而没有CR:GET /index.html HTTP/1.1\n。虽然很多服务器宽容处理单个LF,但严格模式会认为不完整或非法,等待或拒绝。
下面通过nc直连80端口发送一个多余空格的请求,观察响应:
printf 'GET /index.html HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n' | nc 127.0.0.1 80
返回内容通常会包含HTTP/1.1 400 Bad Request以及一个简单的错误页面。如果没有开启严格模式,服务器可能返回200,但这并不意味着请求是安全的,反而说明解析器把多余空格做了容错。排查这类问题时可以结合LogLevel调整日志级别,Apache错误日志会打印类似request failed: erroneous characters after protocol string的提示。
严格校验对安全与兼容性的影响
严格请求行校验最直接的安全收益是减少了请求走私风险。请求走私通常利用前端服务器和后端服务器对请求边界解析不一致。一个包含多余空格、重复Content-Length头或异常Transfer-Encoding头的请求,在宽松解析器下可能被拆分或重组,让攻击者拿到其他用户的响应。当Apache自身作为反向代理或后端时,保持严格解析可以降低这类攻击面。
但严格校验也会影响兼容性。部分物联网设备、老旧扫描器、定制HTTP客户端可能一直在发送不合规请求行。如果直接开启Strict,这些设备会突然无法访问。运维人员可以在灰度期间统计400请求占比,分析访问日志中是否存在特定User-Agent或网段的批量失败。对于确实无法修复的客户端,可以单独为它们配置一个虚拟主机使用Unsafe模式,主业务入口保持严格。
总体建议是:面向公网的Apache或作为反代入口的实例开启HttpProtocolOptions Strict,并定期检查异常请求。内部调用如果完全可控,也可以保持严格,以便尽早暴露客户端实现问题。安全治理往往是从严格校验一个看似简单的请求行开始的。