防止SQL注入的核心是禁用用户输入拼接,必须使用预处理语句(PDO/MySQLi参数化查询),辅以输入校验、最小权限原则和安全配置,杜绝直接拼接、废弃函数及动态标识符。

防止 SQL 注入的核心是:永远不要把用户输入直接拼接到 SQL 语句中。MySQL 项目中,最可靠、最推荐的做法是使用预处理语句(Prepared Statements)配合参数化查询,同时辅以输入校验和权限控制。
用 PDO 或 MySQLi 的预处理机制
这是防御 SQL 注入的黄金标准。数据库驱动会自动区分“SQL 结构”和“数据内容”,从根本上杜绝恶意代码执行。
-
PDO 示例(推荐):
$pdo = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND status = ?");
$stmt->execute([$username, $status]); // 自动转义,类型安全 -
MySQLi 面向对象示例:
$mysqli = new mysqli("localhost", $user, $pass, "test");
$stmt = $mysqli->prepare("INSERT INTO logs (ip, action) VALUES (?, ?)");
$stmt->bind_param("ss", $client_ip, $action); // s=string, i=integer
$stmt->execute();
严格过滤和验证用户输入
预处理不能替代业务层校验。对输入做白名单式约束,能提前拦截异常请求,降低攻击面。
- 数字类字段(如 ID、分页页码):用
(int)强转或filter_var($input, FILTER_VALIDATE_INT) -
邮箱、URL、手机号等:使用
filter_var()对应过滤器,例如filter_var($email, FILTER_VALIDATE_EMAIL) - 用户名、标题等字符串:限制长度、禁止特殊字符(如
/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]{2,20}$/u),避免正则回溯漏洞 - 绝不信任前端传来的任何值——包括 hidden input、cookie、header 中的数据
最小权限原则与数据库配置加固
即使某条语句被绕过,限制数据库账户权限也能大幅降低危害。
- Web 应用连接 MySQL 时,使用专用账号,只授予必要权限:
GRANT SELECT, INSERT, UPDATE ON mydb.users TO 'webapp'@'localhost';
禁用DROP、DELETE、CREATE、LOAD_FILE等高危权限 - 关闭 MySQL 的
local_infile(防止利用LOAD DATA INFILE读取服务器文件) - 生产环境禁用错误信息外泄:PHP 中设
display_errors = Off,MySQL 中避免返回详细报错(如mysqli_report(MYSQLI_REPORT_OFF))
避免已淘汰或不安全的写法
这些方式看似简单,但极易引入风险,务必替换掉:
- ❌
"SELECT * FROM users WHERE id = " . $_GET['id']—— 直接拼接,高危 - ❌
mysql_real_escape_string()(已废弃)或addslashes()—— 无法覆盖所有编码绕过场景,不推荐 - ❌ 动态构建表名/字段名(如
"SELECT * FROM " . $_POST['table'])—— 预处理不支持占位符用于标识符,必须用白名单映射 - ✅ 正确做法:表名/字段名由程序内定义数组控制,例如
$allowed_tables = ['users', 'orders']; if (!in_array($table, $allowed_tables)) die('Invalid table');










