PHP 在做 SQL 注入防御时有哪些方法

1. 使用预处理语句

这是防御 SQL 注入的首选方法,也是最安全、最推荐的方式。预处理语句将 SQL 代码与数据完全分离,数据库会先编译SQL 模板,然后再将用户数据作为参数绑定进去。这样,无论用户输入什么,数据都只会被当作值来处理,而不会被当作SQL 代码的一部分

  • PDO (PHP Data Objects)

    // 创建PDO连接
    $pdo = new PDO("mysql:host=localhost;dbname=testdb", "username", "password");
    
    // 1. 准备SQL语句模板,使用 ? 占位符
    $stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
    
    // 2. 绑定参数,将用户输入作为值传递
    $stmt->execute([$_POST['username']]);
    
    // 3. 获取结果
    $user = $stmt->fetch();
    

    PDO 是现代 PHP 开发中处理数据库连接和查询的标准库,它支持多种数据库,并且提供了强大的预处理功能

  • MySQLi

    // 创建MySQLi连接
    $mysqli = new mysqli("localhost", "username", "password", "testdb");
    
    // 1. 准备SQL语句模板,使用 ? 占位符
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE username = ?");
    
    // 2. 绑定参数,指定数据类型
    $stmt->bind_param("s", $_POST['username']); // "s" 表示 string
    
    // 3. 执行查询
    $stmt->execute();
    
    // 4. 获取结果
    $result = $stmt->get_result();
    $user = $result->fetch_assoc();
    

    MySQLi 是专为 MySQL 设计的扩展,也支持预处理语句

2. 使用 ORM 框架

如果你在使用像 LaravelSymfonyYii 这样的现代 PHP 框架,那么ORM(对象关系映射)库(如Eloquent或Doctrine)已经为你处理了预处理语句的复杂性

  • Laravel Eloquent 示例

    use App\Models\User;
    
    // Eloquent会自动使用预处理语句
    $user = User::where('username', $_POST['username'])->first();
    

    使用 ORM,你不再需要直接编写 SQL 语句,而是通过操作对象来完成数据库交互,这从根本上避免了 SQL 注入的可能性

3. 数据转义

在某些老旧的系统或特殊情况下,如果无法使用预处理语句,你必须对所有用户输入进行转义。转义的目的是将用户输入中的特殊字符(如单引号 '、双引号 "、反斜杠 \ 等)进行处理,使它们失去原有的特殊含义,被数据库当作普通字符串来处理

  • 使用 mysqli_real_escape_string()

    // 在使用前确保已经建立了MySQLi连接
    $username = mysqli_real_escape_string($conn, $_POST['username']);
    
    // 将转义后的变量拼接到SQL语句中
    $sql = "SELECT * FROM users WHERE username = '$username'";
    $result = mysqli_query($conn, $sql);
    

    这种方法只在最后一道防线使用,并且不推荐作为主要防御手段,因为它容易被遗漏,并且不同的数据库需要不同的转义函数,增加了开发者的负担

  • 注意绝对不要再使用 addslashes(),因为它无法处理所有字符集,容易被绕过。mysql_escape_string() 也已经被废弃

4. 最小权限原则

这是一个重要的安全原则,可以降低 SQL 注入成功后的危害

  • 不要使用 root 用户或拥有所有权限的用户来连接数据库
  • 为应用程序创建专用的数据库用户,并只赋予它完成任务所需的最小权限。例如,一个只读操作的脚本,其数据库用户就应该只有 SELECT 权限
防御方法 优点 缺点 推荐度
预处理语句 最安全、最彻底的防御;将数据与代码分离;性能好。 语法相对复杂一些;无法用于某些动态 SQL(如表名、列名)。 最高
ORM 框架 从根本上杜绝 SQL 注入;开发效率高;代码可读性好。 需要学习框架;不适用于简单或无框架项目。 非常高
数据转义 适用于老旧系统或无框架的项目。 容易遗漏;依赖开发者记忆;不彻底。 低,仅作补充
最小权限 降低攻击后的危害。 无法从根本上防御注入。 非常高(作为安全原则)
Copyright © 版权信息 all right reserved,powered by Gitbook该文件修订时间: 2025-09-25 03:13:01

results matching ""

    No results matching ""