预处理语句(Prepared Statements)是防止 SQL 注入攻击的有效方法。在预处理语句中,SQL 查询语句的结构在执行前就已经定义好了,实际的参数数据会在执行时作为绑定参数传递,而不是直接拼接到 SQL 查询中,这样就避免了恶意用户通过修改查询结构来执行注入攻击。
以下是使用 PHP 和 MySQLi 函数库进行 SQL 注入防护的例子:
示例:使用预处理语句防止 SQL 注入
假设我们有一个登录页面,用户通过用户名和密码登录。
错误的做法(容易受到 SQL 注入攻击):
phpCopy Code
<?php
// 用户输入的用户名和密码
$username = $_POST['username'];
$password = $_POST['password'];
// 不安全的 SQL 查询,直接拼接用户输入
$query = "SELECT * FROM users WHERE username='$username' AND password='$password'";
// 执行查询
$result = mysqli_query($conn, $query);
?>
在这个例子中,恶意用户可以通过输入特殊的 SQL 语句来绕过身份验证,比如输入:
- 用户名:
admin' --
- 密码:
anypassword
这会导致 SQL 查询变成:
sqlCopy Code
SELECT * FROM users WHERE username='admin' --' AND password='anypassword'
SQL 注释符 --
会导致后面的密码部分被忽略,攻击者可能成功登录。
正确的做法(使用预处理语句防止 SQL 注入):
phpCopy Code
<?php
// 用户输入的用户名和密码
$username = $_POST['username'];
$password = $_POST['password'];
// 使用预处理语句防止 SQL 注入
$query = "SELECT * FROM users WHERE username = ? AND password = ?";
// 创建一个预处理语句
$stmt = mysqli_prepare($conn, $query);
// 绑定参数('s' 表示字符串类型)
mysqli_stmt_bind_param($stmt, 'ss', $username, $password);
// 执行查询
mysqli_stmt_execute($stmt);
// 获取查询结果
$result = mysqli_stmt_get_result($stmt);
// 进一步处理查询结果
if (mysqli_num_rows($result) > 0) {
// 登录成功
echo "登录成功!";
} else {
// 登录失败
echo "用户名或密码错误!";
}
// 关闭预处理语句
mysqli_stmt_close($stmt);
?>
解释:
- 使用了
mysqli_prepare
来准备 SQL 查询语句。这里的查询语句包含了占位符(?
),表示将来需要绑定的参数。 - 使用
mysqli_stmt_bind_param
绑定用户输入的变量($username
和$password
)到查询语句的占位符。 - 由于这些输入数据是作为参数传递给查询,而不是直接拼接到查询字符串中,数据库引擎会将它们处理为数据而不是 SQL 代码,这有效防止了 SQL 注入攻击。
总结:
- 预处理语句通过将 SQL 查询和数据分离来防止 SQL 注入。
- 参数绑定可以确保用户输入的数据不会被当作 SQL 代码执行,从而提高了安全性。
这种做法是防止 SQL 注入的最佳实践,不仅能有效防止攻击,还能提高应用的安全性和可维护性。