Cookie和Session值绝不能直接拼入SQL查询,必须使用预处理语句绑定参数,无论数据来源如何;同时需严格校验类型、范围,防范会话劫持与权限绕过。

Cookie和Session值不能直接进SQL查询
直接把 $_COOKIE['user_id'] 或 $_SESSION['uid'] 拼进 SQL 字符串,等于主动给攻击者开后门。哪怕这些值看起来“只由服务端写入”,只要它最终来自 HTTP 请求(比如 Cookie 可被手动篡改、Session ID 可被固定),就绝不能信任。
常见错误现象:
- 用户修改浏览器 Cookie 中的
user_id=123为user_id=123 OR 1=1--,查询返回所有用户 - 登录后 Session 中存了
$_SESSION['role'] = 'admin',但没校验类型,攻击者伪造请求带role='admin\' OR \'1\'=\'1'绕过权限检查
必须用预处理语句绑定参数
无论数据来源是 $_GET、$_POST、$_COOKIE 还是 $_SESSION,只要进 SQL,就必须走预处理。PDO 和 MySQLi 都支持,核心是「模板与数据分离」。
正确做法示例(PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ? AND status = ?");
$stmt->execute([$_SESSION['uid'], $_COOKIE['status']]);
错误做法(哪怕加了 intval() 或 filter_var()):
$sql = "SELECT * FROM users WHERE id = " . intval($_SESSION['uid']); // 问题:类型转换只能防数字,但 session/cookie 值可能是字符串、JSON、base64 编码等,无法一概而论
关键点:
- 不要用
addslashes()或mysql_real_escape_string()处理 Cookie/Session 值——它们已过时且不覆盖所有边界情况 - 预处理的占位符(
?或:name)必须对应真实参数变量,不能是拼接后的字符串 - 如果从 Session 中取的是 JSON 字符串(如
$_SESSION['profile']),先json_decode()再提取字段,再绑定,不要整段塞进 SQL
Session 和 Cookie 本身不是 SQL 注入入口,但常成跳板
SQL 注入不会直接从 Cookie 字段发生,但它常配合其他漏洞放大危害。典型链路是:Cookie → Session ID 劫持 → 获取高权限 Session 数据 → 将恶意构造的 Session 值用于 SQL 查询。
所以防护要分层:
- 设置 Cookie 时强制
HttpOnly和Secure,防止 XSS 窃取PHPSESSID - 用户登录成功后必须调用
session_regenerate_id(true),避免会话固定 - 敏感 Session 数据(如
$_SESSION['is_admin'])不要依赖前端传入,而应在登录验证后由服务端明确赋值,并在每次使用前做类型和范围校验(例如in_array($_SESSION['role'], ['user', 'admin'])) - 不要在 SQL 中查询
WHERE session_id = ?—— Session ID 是会话标识,不是业务主键;查用户应始终基于user_id等受控字段
别忽略错误信息泄露和日志记录风险
当 Cookie 或 Session 值触发 SQL 错误(比如类型不匹配、空值插入非空字段),默认错误信息可能暴露表结构或字段名,这为后续注入提供线索。
实操建议:
- 关闭
display_errors,开启log_errors,错误日志中不要记录原始$_COOKIE或$_SESSION内容 - 对所有外部输入(含 Cookie/Session)做最小化假设:比如
$_COOKIE['theme']只接受'light'或'dark',其余一律拒绝或重置,而不是放行后再过滤 - 数据库账号权限严格限制:Web 应用连接数据库的账号,只授予
SELECT/INSERT/UPDATE必需表的权限,禁用DROP、UNION SELECT等高危操作权限
真正难防的不是单点 SQL 注入,而是把 Cookie/Session 当作“可信上下文”来用。一旦你开始写 "WHERE role = '{$_SESSION['role']}'" 这种代码,就已经在信任链上开了第一个口子。


















