cookie注入的根本原因是$_request混用get/post/cookie数据,修复应明确参数来源、用filter_input校验、所有cookie参与的sql必须预处理、waf无法可靠防护、解码后须立即过滤。

直接改 $_REQUEST 用法不现实,得切到源头
PHP里用 $_REQUEST['id'] 同时接收 GET、POST、Cookie 数据,是 Cookie 注入能生效的根本原因。但线上项目不可能把所有 $_REQUEST 全替成 $_GET 或 $_POST —— 有些逻辑确实依赖 Cookie 传参(比如灰度开关、AB测试标识)。真正该做的是:明确每个参数的来源意图。比如 id 必须来自 URL,那就只读 $_GET['id'];如果是登录态 token,那就只读 $_COOKIE['token'],并单独校验。混用 $_REQUEST 是懒,不是巧。
filter_input 比手写 isset + is_numeric 更可靠
很多人修复时写一堆判断:if (isset($_REQUEST['id']) && is_numeric($_REQUEST['id'])) { ... }。问题在于:它只拦了数字型,但没处理类型转换漏洞(比如 '123abc' 过 is_numeric 返回 true);也没覆盖字符串型参数的边界。用 filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) 才是正解——它强制返回 int 或 false,且默认拒绝带非数字后缀的输入。对 Cookie 参数,必须显式指定 INPUT_COOKIE,例如:filter_input(INPUT_COOKIE, 'user_role', FILTER_SANITIZE_STRING)。漏掉 INPUT_COOKIE 就等于白加。
预处理语句必须覆盖所有 Cookie 参与的查询
常见误区是“只在登录模块用了 PDO 预处理,其他地方还是拼 SQL”。只要某处 SQL 里出现 $_COOKIE['xxx'],哪怕只有一行,整个链路就失效。检查点包括:日志记录(INSERT INTO log (ip, cookie_val) VALUES (...))、权限校验(SELECT * FROM user WHERE role = '{$_COOKIE['role']}')、甚至缓存键生成("user_{$cookie_id}" 虽不直连 DB,但若被用于后续 SQL 构造,一样危险)。修复时建议 grep 全项目:grep -r "$_COOKIE\[" --include="*.php" .,逐个确认是否进了预处理流程。
WAF 规则对 Cookie 注入基本无效
多数 WAF 默认只监控 GET 和 POST body,Cookie 头不在检测范围内。即使开了 Cookie 检测,规则也常滞后——比如只拦 union select,但攻击者用 extractvalue(1,concat(0x7e,(select user()),0x7e)) 就绕过。更麻烦的是,WAF 无法区分合法业务 Cookie(如 theme=dark)和恶意注入(theme=dark' AND 1=2--),容易误杀。所以不能依赖 WAF 拦 Cookie 注入,它只能当最后一道辅助防线,不能替代代码层修复。
最易被忽略的是 Cookie 值的编码与解码环节:前端用 encodeURIComponent 传,后端用 urldecode 或 rawurldecode 解,但这两个函数行为不同,可能让过滤逻辑失效。比如 %27(单引号)经 urldecode 变成 ',但某些旧版过滤器只扫 ASCII 字符,漏掉百分号编码后的 payload。修复时务必统一解码时机,并在解码后立即过滤或预处理,别拖到 SQL 拼接前一刻才处理。










