你能否通过一个案例展示PHP如何防止SQL注入攻击

wen PHP项目 50

本文目录导读:

你能否通过一个案例展示PHP如何防止SQL注入攻击

  1. 不安全的代码示例(容易受到SQL注入攻击)
  2. 安全的代码示例(使用预处理语句)
  3. 更完整的注册和登录示例
  4. 数据库表结构
  5. 关键防护措施总结

我来通过一个用户登录系统的案例,演示PHP如何防止SQL注入攻击。

不安全的代码示例(容易受到SQL注入攻击)

<?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 "登录失败";
}
?>

攻击者可以输入:

  • 用户名:admin' --
  • 密码:

这会变成:SELECT * FROM users WHERE username = 'admin' --' AND password = '...',绕过了密码验证!

安全的代码示例(使用预处理语句)

<?php
// 安全的登录验证 - 使用PDO预处理语句
// 数据库连接配置
$host = 'localhost';
$dbname = 'user_system';
$username = 'root';
$password = '';
try {
    // 创建PDO连接
    $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
    // 设置错误模式为异常
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    // 获取用户输入
    $userInput = $_POST['username'];
    $passInput = $_POST['password'];
    // 使用预处理语句(推荐方式)
    $stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");
    // 绑定参数(自动处理转义)
    $stmt->bindParam(':username', $userInput, PDO::PARAM_STR);
    $stmt->bindParam(':password', $passInput, PDO::PARAM_STR);
    // 执行查询
    $stmt->execute();
    // 获取结果
    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    if ($user) {
        // 使用password_verify验证密码哈希(更安全)
        if (password_verify($passInput, $user['password'])) {
            echo "登录成功!欢迎 " . htmlspecialchars($user['username']);
        } else {
            echo "密码错误";
        }
    } else {
        echo "用户不存在";
    }
} catch (PDOException $e) {
    // 记录错误但不显示敏感信息给用户
    error_log("数据库错误: " . $e->getMessage());
    echo "系统错误,请稍后再试";
}
?>

更完整的注册和登录示例

<?php
class SecureUserAuth {
    private $pdo;
    public function __construct($host, $dbname, $username, $password) {
        $dsn = "mysql:host=$host;dbname=$dbname;charset=utf8mb4";
        $this->pdo = new PDO($dsn, $username, $password, [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            PDO::ATTR_EMULATE_PREPARES => false  // 使用真实的预处理语句
        ]);
    }
    // 安全注册
    public function register($username, $password) {
        // 参数验证
        if (strlen($username) < 3 || strlen($username) > 20) {
            return "用户名长度必须在3-20之间";
        }
        if (strlen($password) < 6) {
            return "密码长度至少6位";
        }
        try {
            // 检查用户名是否已存在(使用预处理语句)
            $checkStmt = $this->pdo->prepare("SELECT id FROM users WHERE username = :username");
            $checkStmt->execute([':username' => $username]);
            if ($checkStmt->fetch()) {
                return "用户名已存在";
            }
            // 密码哈希(绝不要明文存储密码)
            $hashedPassword = password_hash($password, PASSWORD_DEFAULT);
            // 安全插入数据
            $insertStmt = $this->pdo->prepare(
                "INSERT INTO users (username, password, created_at) VALUES (:username, :password, NOW())"
            );
            $insertStmt->execute([
                ':username' => $username,
                ':password' => $hashedPassword
            ]);
            return "注册成功";
        } catch (PDOException $e) {
            error_log("注册错误: " . $e->getMessage());
            return "注册失败,请稍后重试";
        }
    }
    // 搜索功能(同样是安全的)
    public function searchUsers($keyword) {
        // 使用LIKE查询也安全
        $stmt = $this->pdo->prepare(
            "SELECT id, username FROM users WHERE username LIKE :keyword LIMIT 10"
        );
        // LIKE查询需要特殊处理
        $searchTerm = '%' . $keyword . '%';
        $stmt->execute([':keyword' => $searchTerm]);
        return $stmt->fetchAll();
    }
}
// 使用示例
$auth = new SecureUserAuth('localhost', 'user_system', 'root', 'password');
// 安全注册
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['register'])) {
    $result = $auth->register($_POST['username'], $_POST['password']);
    echo $result;
}
// 安全搜索
if (isset($_GET['search'])) {
    $users = $auth->searchUsers($_GET['keyword']);
    foreach ($users as $user) {
        echo htmlspecialchars($user['username']) . "<br>";
    }
}
?>

数据库表结构

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

关键防护措施总结

  1. 使用预处理语句(PDO或MySQLi) - 最有效的防御
  2. 参数绑定 - 避免直接拼接SQL
  3. 密码哈希 - 使用password_hash()password_verify()
  4. 输入验证 - 检查数据类型、长度、格式
  5. 输出转义 - 使用htmlspecialchars()防止XSS
  6. 最小权限原则 - 数据库用户只授予必要的权限
  7. 错误处理 - 不向用户显示敏感错误信息

通过这种方式,即使攻击者输入 ' OR '1'='1 这样的恶意内容,预处理语句也会将其视为普通字符串,不会影响SQL语句的结构。

抱歉,评论功能暂时关闭!