在 PHP 中,通过 转义 和 过滤 防护 MySQL 注入攻击是基础措施。以下是具体的实现方法和实例。


---

1. 转义用户输入

转义是通过添加反斜杠 \ 来处理特殊字符(如 '、"、\、\0 等),防止它们破坏 SQL 查询结构。常用方法如下:

方法 1:使用 mysqli_real_escape_string()

mysqli_real_escape_string() 会根据数据库连接的字符集,对输入数据进行安全的转义。

<?php
// 数据库连接
$mysqli = new mysqli("localhost", "username", "password", "database");

// 用户输入
$username = $_POST['username'];
$password = $_POST['password'];

// 转义输入数据
$username = $mysqli->real_escape_string($username);
$password = $mysqli->real_escape_string($password);

// 构造 SQL 查询
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";

// 执行查询
$result = $mysqli->query($query);
?>

方法 2:使用 addslashes()

addslashes() 会简单地对单引号、双引号、反斜杠和空字符添加转义字符。

> ⚠️ 注意:addslashes() 不适合处理数据库输入,因为它不了解数据库上下文。



<?php
$username = addslashes($_POST['username']);
$password = addslashes($_POST['password']);

$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";


---

2. 过滤用户输入

过滤用于确保输入数据符合预期格式,拒绝不合法或恶意输入。

方法 1:使用正则表达式

通过正则表达式验证输入格式。

<?php
$username = $_POST['username'];

// 检查用户名是否只包含字母、数字和下划线,长度在 3-20
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
die("Invalid username format.");
}

方法 2:使用 PHP 的过滤器

PHP 提供了一些内置的过滤器函数,比如 filter_var()。

<?php
$id = $_GET['id'];

// 验证输入是否为整数
if (!filter_var($id, FILTER_VALIDATE_INT)) {
die("Invalid ID.");
}

方法 3:使用白名单

限定输入值为预定义的合法值。

<?php
$role = $_POST['role'];
$allowed_roles = ['admin', 'user', 'editor'];

// 检查输入是否在白名单中
if (!in_array($role, $allowed_roles)) {
die("Invalid role.");
}


---

3. 转义 + 过滤的完整实例

转义和过滤结合使用,可以有效防护 MySQL 注入。

<?php
// 数据库连接
$mysqli = new mysqli("localhost", "username", "password", "database");

// 用户输入
$username = $_POST['username'];
$password = $_POST['password'];

// 过滤输入格式
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
die("Invalid username format.");
}

// 转义输入数据
$username = $mysqli->real_escape_string($username);
$password = $mysqli->real_escape_string($password);

// 构造查询
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
$result = $mysqli->query($query);

// 检查查询结果
if ($result->num_rows > 0) {
echo "Login successful!";
} else {
echo "Invalid username or password.";
}
?>


---

4. 对转义和过滤的评价

优点:

转义:能有效避免特殊字符破坏 SQL 语句,适用于基本的安全防护。

过滤:能够防止非法输入,限制数据范围,提高数据质量。


缺点:

转义的局限性:

手动转义增加代码复杂度。

依赖于开发者的实现,容易遗漏某些场景。


过滤的局限性:

需要针对每个输入自定义规则,复杂场景下容易出错。



建议:

虽然转义和过滤是有效的防护方法,但并不是最佳解决方案。现代 PHP 开发推荐使用参数化查询(PDO 或 MySQLi 预处理语句),因为它比手动转义更高效、更安全。


---

5. 与参数化查询结合

可以将转义和过滤与参数化查询结合使用,构建更全面的安全体系。

<?php
$pdo = new PDO("mysql:host=localhost;dbname=test", "username", "password");

// 用户输入
$username = $_POST['username'];
$password = $_POST['password'];

// 过滤输入
if (!preg_match('/^[a-zA-Z0-9_]{3,20}$/', $username)) {
die("Invalid username format.");
}

// 使用参数化查询
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
$stmt->execute([':username' => $username, ':password' => $password]);

$result = $stmt->fetch();
if ($result) {
echo "Login successful!";
} else {
echo "Invalid username or password.";
}
?>


---

总结

1. 转义:使用 mysqli_real_escape_string() 或类似方法,确保输入安全。


2. 过滤:验证和清理输入数据,保证其合法性。


3. 结合参数化查询:这是最安全和推荐的防护方案,自动处理转义,避免注入。
 
 
Back to Top