CRLF注入攻击直接瞄准网站响应头,攻击者通过向输入字段注入回车符(%0D)和换行符(%0A),能够篡改HTTP响应头,实现会话固定、跨站脚本(XSS)甚至重定向用户至恶意网站。防护的核心在于对输出到HTTP响应头中的所有用户输入进行严格的清洗和编码。
理解CRLF注入的攻击原理与危害
HTTP协议依靠回车换行符(CRLF)来分隔头部字段和正文。正常响应头如“Location: /home”后跟一个CRLF。若应用将用户输入未经处理直接放入响应头,攻击者提交“example.com%0D%0ASet-Cookie: malicious=value”,服务器会将其解析为两个头部:Location跳转和一个新的Set-Cookie。这可能导致会话劫持(Session Fixation),攻击者预设会话ID,诱导用户使用从而窃取会话。
更危险的利用是注入整个HTTP响应。例如,在可控制头部内容的场景,输入“%0D%0A%0D%0A<script>alert('XSS')</script>”会在头部后插入空行并开始正文,触发反射型XSS。此外,通过注入“Location: http://恶意网站”可实现钓鱼重定向。这类漏洞常出现在URL重定向、文件下载头部设置、自定义错误页面等环节。
实施响应头清洗的关键防御策略
首要防御是“黑名单过滤”的彻底摒弃。单纯删除“\r\n”字符不足够,因编码绕过(如Unicode、多重编码)层出不穷。应采用“白名单验证”与“编码输出”结合的策略。对所有动态设置响应头的参数,定义严格允许的字符集(如字母、数字、有限符号),拒绝其他字符。
强制实施输出编码。在将数据写入响应头前,必须进行适当的编码。例如,将换行符、回车符转换为无害字符,或使用框架提供的安全函数。在Java中,可使用ESAPI编码器:
ESAPI.encoder().encodeForHTMLAttribute(userInput);
在.NET中,应对头部值进行URL编码或自定义过滤。
设置安全头部增强防护。即使存在注入风险,部署Content Security Policy (CSP) 可限制脚本执行,降低XSS影响。头部如“X-Content-Type-Options: nosniff”防止MIME类型混淆攻击。
具体清洗与验证的代码实现示例
以Python Flask应用为例,实现一个安全的头部设置函数。首先,定义清洗函数移除或替换危险字符:
def sanitize_header_value(value):
if not value:
return ""
# 替换CRLF字符为空格
value = value.replace('\r', ' ').replace('\n', ' ')
# 移除其他控制字符(ASCII 0-31, 127)
value = ''.join(char for char in value if ord(char) >= 32 and ord(char) != 127)
# 可选:限制长度防止溢出
return value[:2000]在设置响应头时调用:
from flask import Response resp = Response() safe_value = sanitize_header_value(user_input) resp.headers['X-Custom-Header'] = safe_value
对于重定向URL,必须验证域名白名单。例如:
allowed_domains = ['example.com', 'trusted.org']
def safe_redirect(url):
from urllib.parse import urlparse
parsed = urlparse(url)
if parsed.netloc and parsed.netloc not in allowed_domains:
return '/default-safe-page'
return url此方法杜绝了开放重定向漏洞,该漏洞常与CRLF注入共生。
服务器配置与框架级防护措施
现代Web框架内置了部分防护,但需正确配置。在Node.js Express中,避免直接使用"res.set()"传入用户输入。使用中间件自动过滤头部值。例如,可编写全局中间件:
app.use((req, res, next) => {
const originalSetHeader = res.setHeader;
res.setHeader = function(name, value) {
if (typeof value === 'string') {
value = value.replace(/[\r\n]/g, '');
}
originalSetHeader.call(this, name, value);
};
next();
});服务器层面,Nginx或Apache应限制自定义头部的长度和内容。在Nginx配置中,可设置:
server {
# 防止头部注入,限制特殊字符
location / {
# 使用$http变量时注意过滤
proxy_set_header Custom-Header "$http_user_header";
# 最好使用固定值或严格控制的变量
}
}同时,定期更新服务器和框架以修补已知漏洞。
自动化检测与持续监控流程
防护需结合主动检测。使用静态应用安全测试(SAST)工具扫描源代码,查找直接拼接响应头的模式。动态应用安全测试(DAST)工具,如渗透测试,模拟注入攻击。手动测试可借助Burp Suite,在输入中插入%0D%0A观察响应变化。
监控日志中的异常头部活动。例如,日志中出现包含CRLF字符的请求应触发警报。在Splunk或ELK栈中设置规则:
index=web_logs *%0D%0A* OR *%0D* OR *%0A*
实现实时告警。
最后,将响应头清洗纳入开发安全培训。代码审查中,重点关注"Location"、"Set-Cookie"、"X-Forwarded-For"等头部设置点。建立安全编码规范,要求所有响应头输出必须通过中心化的安全函数处理。
