Header字段(User-Agent、Referer、Cookie)与$_POST同样危险,必须参数化查询,不可拼接字符串;需配合长度限制、白名单校验和日志截断加固。

User-Agent、Referer、Cookie 这些字段和 $_POST 一样危险,不参数化就入库,等于主动开后门——必须走参数化查询,没有例外。
Header 字段为什么会被当成“安全输入”而漏防
很多团队误以为 Header 是“系统自带”的元数据,比表单输入可信;但攻击者完全可控 User-Agent(curl -H "User-Agent: ' OR 1=1--")、可伪造 Referer、篡改 Cookie。日志记录、风控埋点、行为分析模块常直接拼接这些字段进 SQL,一写错就中招。
- 常见错误现象:修改
User-Agent为'后返回 MySQL 报错You have an error in your SQL syntax - 页面无报错但响应明显变慢(
SLEEP(5)类时间盲注) - 登录成功但用户行为日志丢失,或风控规则突然失效(说明 Header 处理路径独立且未加固)
所有 Header 取值必须走参数化接口,不能拼字符串
不是加一层 mysqli_real_escape_string() 或正则过滤就能过关,而是彻底让数据库驱动把值当纯数据处理。不同语言的实操要点:
- Java(JDBC):
PreparedStatement+setString(),绝不用"...'" + request.getHeader("User-Agent") + "'..." - Python(psycopg2 / PyMySQL):用
%s占位符,传参为元组,如cursor.execute("INSERT INTO logs (ua) VALUES (%s)", (ua,)) - PHP(PDO):
bindParam()或命名占位符,如$stmt->execute(['ua' => $_SERVER['HTTP_USER_AGENT']]),禁用mysql_query()系列老函数 - Node.js(pg / mysql2):用
$1占位符,client.query("SELECT * FROM logs WHERE referer = $1", [referer])
ORM 框架(Django ORM、SQLAlchemy)默认安全,但一旦调用 raw()、extra() 或 f-string 拼接 SQL,风险立刻回归。
Header 注入的额外加固点:长度限制 + 白名单 + 日志截断
参数化解决的是“执行逻辑被篡改”,但攻击者仍可能用超长 User-Agent 触发缓冲区问题或拖慢服务。需在网关层补防:
- Nginx 层限制长度:
map $http_user_agent $ua_too_long { ~^.{500,} 1; default 0; },配合if ($ua_too_long) { return 400; } - 对
Accept、Content-Type等固定字段做白名单校验,非法值直接400拒绝,不进业务逻辑 - 记录原始 Header 到日志时,强制截断到 256 字符以内,避免日志文件膨胀或二次注入风险
- 数据库字段类型设为
VARCHAR(255)而非TEXT,并加NOT NULL和默认值约束
最容易被忽略的细节:Cookie 和 Referer 同样要查
开发者常只盯 User-Agent,却放行 Cookie(含 session_id、tracking_id)和 Referer(可被前端 JS 动态伪造)。只要代码里有类似 "INSERT INTO access_log (cookie, referer) VALUES ('" + cookie + "', '" + referer + "')" 的写法,就存在漏洞。
尤其注意:有些框架会自动解析 Cookie 成键值对,但若手动取 request.headers.get('Cookie') 原始字符串入库,依然危险。Referer 也一样——别因它“看起来像 URL”就跳过参数化。


















