cookie值拼接进sql等于直接交出数据库钥匙,必须用参数化查询防御。攻击者可篡改cookie执行任意sql,base64或简单正则无法阻止绕过,签名仅防篡改不解决拼接问题,orm手动拼接同样中招。

SQL语句里拼接 Cookie 值等于主动交出数据库钥匙
直接把 Cookie 里的值(比如 session_id=abc123 或 user_token=xyz789)用字符串拼接进 SQL 查询,等同于让攻击者能任意控制查询逻辑。这不是“可能被注入”,而是“只要 Cookie 可篡改,就必然可注入”——因为 HTTP Cookie 完全由客户端控制,服务端未校验、未参数化时,它和用户输入没有任何区别。
SELECT * FROM users WHERE token = ' + cookie_value + ' 是典型高危写法
这种拼接常见于老式登录校验或会话查找逻辑,例如在 Node.js 中用 mysql 模块、PHP 中用 mysqli::query、Java 中用 Statement.execute 等非参数化方式构造 SQL。
攻击者只需在 Cookie 中传入 user_token=' OR '1'='1,整条语句就变成:
SELECT * FROM users WHERE token = '' OR '1'='1'
结果是匹配全部用户,甚至配合注释符 -- 或分号 ; 还能执行多语句(取决于驱动是否启用多语句模式)。
- 即使
Cookie值经过 base64 编码或简单正则过滤(如只允许字母数字),也挡不住绕过:base64 解码后仍是可控字符串,正则漏掉'、;、/*等关键字符很常见 - 部分框架对
Cookie做了签名(如 Express 的signedCookies),但签名只防篡改,不解决拼接本身的问题——一旦签名密钥泄露或验证逻辑被绕过,照样崩 - ORM 如 Sequelize、TypeORM 默认也不自动防御拼接;若手动拼进
where字段(如where: `token = '${req.cookies.token}'`),照样中招
唯一安全做法:所有外部输入走参数化查询或预编译语句
无论来源是 URL、Body 还是 Cookie,只要是动态值,就必须脱离 SQL 字符串结构。
- Node.js(
pg):用client.query('SELECT * FROM users WHERE token = $1', [req.cookies.token]) - Python(
psycopg2):用cursor.execute("SELECT * FROM users WHERE token = %s", (request.cookies.get('token'),)) - PHP(
PDO):用$stmt = $pdo->prepare("SELECT * FROM users WHERE token = ?"); $stmt->execute([$token]); - Java(
JDBC):必须用PreparedStatement,绝不用Statement拼接
注意:参数化只保护「值」,不保护「标识符」(如表名、列名)。如果 Cookie 决定了查哪张表(如 tenant_id 动态选库),那得用白名单映射,不能拼接表名。
Cookie 值本身还要额外校验长度、格式和时效性
参数化解决注入,但不解决业务逻辑漏洞。比如 user_token 长度异常(500 字符)、含非法字符(控制符、Unicode 零宽空格)、时间戳明显过期,这些都该在进 SQL 前拦截。
- 用
crypto.timingSafeEqual()(Node)或hash_equals()(PHP)比对 token,防止时序攻击 - 查库前先检查 token 是否在 Redis 黑名单里(如用户登出后未失效)
- 避免把敏感字段(如密码哈希、密钥)直接存进 Cookie;应只存不可逆的随机令牌,并与服务端 session 绑定
最常被忽略的一点:开发时习惯用 Postman 或浏览器插件手动设 Cookie 测试,容易忘记它和真实攻击面完全一致——那个你随手填的 admin=true,就是攻击者第一批尝试的 payload。










