You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
|
|
|
# 简单的SQL 注入漏洞
|
|
|
|
|
|
|
|
|
|
|
|
## 漏洞攻击
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
// 用户输入(未过滤)
|
|
|
|
|
|
$username = $_POST['username'];
|
|
|
|
|
|
$password = $_POST['password'];
|
|
|
|
|
|
|
|
|
|
|
|
// 危险操作:直接拼接 SQL 查询
|
|
|
|
|
|
$sql = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
|
|
|
|
|
|
$result = mysqli_query($conn, $sql);
|
|
|
|
|
|
|
|
|
|
|
|
if (mysqli_num_rows($result) > 0) {
|
|
|
|
|
|
echo "登录成功!";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo "用户名或密码错误!";
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
如何绕过密码验证?
|
|
|
|
|
|
|
|
|
|
|
|
攻击者在 username 输入框中输入:
|
|
|
|
|
|
|
|
|
|
|
|
````
|
|
|
|
|
|
admin' --
|
|
|
|
|
|
````
|
|
|
|
|
|
|
|
|
|
|
|
实际执行的 SQL:
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
SELECT * FROM users WHERE username = 'admin' -- ' AND password = ''
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
-- 是 SQL 注释符号,导致后续的 AND password = '' 被忽略。
|
|
|
|
|
|
查询变为:只要 username = 'admin' 成立即可登录,无需密码。
|
|
|
|
|
|
|
|
|
|
|
|
## 漏洞原因和处理策略
|
|
|
|
|
|
|
|
|
|
|
|
输入的字符串包含特殊字符,这些特殊字符与原有的SQL查询字符串一起构成了意外的SQL。输入的数据只能当作字符串使用,要使用转义。
|
|
|
|
|
|
|
|
|
|
|
|
## 漏洞修复
|
|
|
|
|
|
|
|
|
|
|
|
```php
|
|
|
|
|
|
<?php
|
|
|
|
|
|
// 使用预处理语句防止注入
|
|
|
|
|
|
$stmt = $conn->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
|
|
|
|
|
|
$stmt->bind_param("ss", $username, $password);
|
|
|
|
|
|
$stmt->execute();
|
|
|
|
|
|
$result = $stmt->get_result();
|
|
|
|
|
|
|
|
|
|
|
|
if ($result->num_rows > 0) {
|
|
|
|
|
|
echo "登录成功!";
|
|
|
|
|
|
} else {
|
|
|
|
|
|
echo "用户名或密码错误!";
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
预使用PHP自带的SQL执行模板和绑定可以有效防止这种类型的SQL注入。
|