PHP 防止 SQL 注入详解及防范指南
SQL 注入是攻击者通过操纵输入数据篡改 SQL 查询的攻击手段,可导致数据泄露、篡改或删除,以下是 PHP 中防范 SQL 注入的完整方案:

核心防御原则
- 永远不信任用户输入
- 使用参数化查询(预处理语句)
- 最小权限原则(数据库账号权限限制)
最佳实践:参数化查询(推荐)
使用 PDO (PHP Data Objects)
<?php
// 连接配置
$host = 'localhost';
$dbname = 'test_db';
$user = 'root';
$pass = '';
try {
// 创建 PDO 实例(启用错误报告和预处理)
$pdo = new PDO(
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
$user,
$pass,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false // 禁用模拟预处理
]
);
// 示例:查询用户(命名参数)
$userId = $_GET['id'];
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $userId]); // 自动处理类型和转义
// 获取结果
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 示例:插入数据(位置参数)
$name = $_POST['name'];
$email = $_POST['email'];
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$name, $email]); // 参数顺序对应
} catch (PDOException $e) {
error_log("Database error: " . $e->getMessage());
exit("数据库错误");
}
?>
使用 MySQLi (面向对象风格)
<?php
$mysqli = new mysqli("localhost", "user", "pass", "test_db");
// 检查连接
if ($mysqli->connect_error) {
die("连接失败: " . $mysqli->connect_error);
}
// 预处理语句
$stmt = $mysqli->prepare("SELECT * FROM users WHERE email = ?");
$email = $_POST['email'];
$stmt->bind_param("s", $email); // "s" 表示字符串类型
$stmt->execute();
// 获取结果
$result = $stmt->get_result();
$user = $result->fetch_assoc();
$stmt->close();
$mysqli->close();
?>
补充防御措施
输入验证与过滤
// 验证邮箱格式
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) {
die("无效邮箱");
}
// 过滤整数输入
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false || $id < 1) {
die("非法ID");
}
最小化数据库权限
- 创建专用数据库账号,仅授予必要权限(如
SELECT, INSERT)。 - 禁止 root 账号用于 Web 应用。
错误处理
- 生产环境关闭错误显示:
ini_set('display_errors', 'Off'); error_reporting(0); - 记录错误到日志:
ini_set('log_errors', 'On'); ini_set('error_log', '/path/to/php-error.log');
应避免的做法(高风险!)
拼接 SQL 语句(极度危险!)
// 漏洞示例:攻击者可输入 ' OR '1'='1 绕过验证
$sql = "SELECT * FROM users WHERE username = '{$_POST['user']}'";
$result = mysqli_query($conn, $sql);
不安全的转义函数
mysql_real_escape_string()(已弃用,不推荐)addslashes()(无法防御所有情况)
注意:转义函数不能替代参数化查询!它们易受字符集漏洞影响。
进阶防护策略
-
Web 应用防火墙 (WAF)
使用 ModSecurity 等工具拦截恶意请求。 -
定期安全审计
使用工具扫描漏洞(如 SQLMap、Acunetix)。
-
ORM 框架
使用 Laravel Eloquent、Doctrine 等 ORM,自动处理参数化查询:// Laravel Eloquent 示例 User::where('email', $email)->first();
安全实践清单
| 措施 | 推荐级别 | 说明 |
|---|---|---|
| PDO 参数化查询 | 首选方案 | |
| MySQLi 预处理 | 次选方案 | |
| 输入验证 | 辅助防御 | |
| 最小数据库权限 | 降低损害范围 | |
| 避免拼接 SQL | 严禁使用 | |
弃用 mysql_* 函数 |
PHP 7+ 已移除 |
关键原则:参数化查询是唯一可靠的防御手段,其他方法均为补充措施。
通过遵循以上规范,可有效杜绝 SQL 注入漏洞,保障数据库安全。

图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/294038.html

