预处理与防注入
prepare/execute 预处理、SQL 注入原理与防御、参数绑定
预处理与防注入
SQL 注入是 Web 安全的第一大威胁。预处理(Prepared Statement)是唯一正确的防御方式。
学完本章你将: 掌握 prepare/execute、SQL 注入原理、参数绑定。
SQL 注入演示
php
<?php
// ❌ 危险——拼接用户输入
$name = $_GET['name']; // 用户输入:'; DROP TABLE users; --
$pdo->query("SELECT * FROM users WHERE name = '$name'");
// 实际执行:SELECT * FROM users WHERE name = ''; DROP TABLE users; --'
// 整张表被删!
php
<?php
// ✅ 安全——预处理(参数与 SQL 分离)
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name");
$stmt->execute(["name" => $_GET['name']]);
// 无论用户输入什么,都只是"数据",绝对不会被当作 SQL 执行
占位符的两种写法
php
<?php
// 命名占位符(推荐——可读性好)
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = :name AND age > :age");
$stmt->execute(["name" => "小明", "age" => 18]);
// 问号占位符(短但易出错)
$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ? AND age > ?");
$stmt->execute(["小明", 18]);
IN 子句的参数绑定
php
<?php
// IN 子句需要动态构建占位符
$ids = [1, 2, 3, 5, 8];
$inPlaceholders = implode(",", array_fill(0, count($ids), "?"));
$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($inPlaceholders)");
$stmt->execute($ids);
防御清单
php
<?php
// ✅ 永远使用预处理——即使只是简单查询
// ✅ 关闭模拟预处理(ATTR_EMULATE_PREPARES = false)
// ✅ 用 htmlspecialchars 输出到 HTML(防 XSS)
// ✅ 用 filter_var 验证输入格式
// ❌ 绝不拼接用户输入到 SQL