在PHP中,防止SQL注入攻击的核心原则是永远不要信任用户输入,必须对所有输入数据进行过滤和转义,以下是几种有效的防注入方法及代码示例:

✅ 最佳方案:使用预处理语句(Prepared Statements)
PDO (推荐,支持多种数据库)
<?php
// 连接数据库
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 用户输入(示例)
$username = $_POST['username'];
$email = $_POST['email'];
try {
// 准备SQL模板
$stmt = $pdo->prepare("INSERT INTO users (username, email) VALUES (:username, :email)");
// 绑定参数(自动转义)
$stmt->bindParam(':username', $username, PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
// 执行
$stmt->execute();
echo "数据安全写入!";
} catch (PDOException $e) {
die("错误: " . $e->getMessage());
}
MySQLi (面向对象风格)
<?php
$mysqli = new mysqli("localhost", "user", "pass", "test");
// 检查连接
if ($mysqli->connect_error) {
die("连接失败: " . $mysqli->connect_error);
}
// 用户输入
$username = $_POST['username'];
$email = $_POST['email'];
// 准备并绑定
$stmt = $mysqli->prepare("INSERT INTO users (username, email) VALUES (?, ?)");
$stmt->bind_param("ss", $username, $email); // "ss" 表示两个字符串类型
// 执行
if ($stmt->execute()) {
echo "数据安全写入!";
} else {
echo "错误: " . $stmt->error;
}
$stmt->close();
$mysqli->close();
⚠️ 备选方案:过滤转义输入(不推荐,仅作应急)
仅当无法使用预处理语句时考虑,需结合其他防护措施
<?php // 使用 mysqli_real_escape_string(需先连接数据库) $username = mysqli_real_escape_string($conn, $_POST['username']); $email = mysqli_real_escape_string($conn, $_POST['email']);
// 过滤特殊字符(额外防护)
$username = htmlspecialchars($username, ENT_QUOTES, ‘UTF-8’);
$sql = “INSERT INTO users (username, email) VALUES (‘$username’, ‘$email’)”;
// 注意:仍有风险!不推荐直接拼接SQL

---
### 🔒 关键安全实践:
1. **强制使用参数化查询**:
- 永远用 `prepare` + `bindParam`/`bind_param`
- 禁止直接拼接SQL语句(如 `"SELECT * FROM users WHERE id = $_GET[id]"`)
2. **输入验证**:
```php
// 验证邮箱格式
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
die("无效邮箱格式");
}
// 验证整数ID
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === false) {
die("ID必须是整数");
}
-
最小权限原则:
数据库用户只赋予必要权限(禁用DROP、FILE等)
-
错误处理:

- 生产环境关闭错误回显:
display_errors = Off - 记录日志:
log_errors = On
- 生产环境关闭错误回显:
-
防XSS跨站攻击:
// 输出到HTML时转义 echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
🚫 危险做法(务必避免):
// ❌ 直接拼接输入(高危!)
$sql = "SELECT * FROM users WHERE name='$_GET[name]'";
// ❌ 过时函数(不安全)
$sql = "SELECT * FROM users WHERE id=" . mysql_real_escape_string($_GET['id']);
// ❌ 宽字节注入(GBK等编码)
$conn->set_charset("utf8"); // 必须设置正确编码
📚 完整安全示例(PDO + 输入验证):
<?php
// 1. 连接数据库
try {
$pdo = new PDO('mysql:host=localhost;dbname=mydb;charset=utf8', 'user', 'pass', [
PDO::ATTR_EMULATE_PREPARES => false, // 禁用模拟预处理
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
// 2. 验证输入
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
if ($id === null || $id === false) {
die("非法ID参数");
}
// 3. 使用预处理查询
try {
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindValue(':id', $id, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// 4. 安全输出
foreach ($result as $row) {
echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8');
}
} catch (PDOException $e) {
error_log("SQL错误: " . $e->getMessage());
die("操作失败,请重试");
}
| 方法 | 安全性 | 数据库支持 | 推荐度 |
|---|---|---|---|
| PDO预处理 | 多数据库 | ✅ 首选 | |
| MySQLi预处理 | 仅MySQL | ✅ 推荐 | |
| 手动转义+过滤 | 所有 | ⚠️ 应急 | |
| 拼接SQL | 所有 | 🚫 禁止 |
终极建议:始终使用PDO或MySQLi的预处理语句,结合输入验证和输出转义,可抵御99%的注入攻击。
图片来源于AI模型,如侵权请联系管理员。作者:酷小编,如若转载,请注明出处:https://www.kufanyun.com/ask/292920.html

