在 PHP 中防止 SQL 注入

[使用预处理语句和 PDO 防止 PHP 中的 SQL 注入]

我们可以将预处理语句与 PDO 一起使用,以防止在 PHP 中进行 SQL 注入。当将查询和数据混合发送到数据库时,将发生 SQL 注入。在这种方法中,我们没有在 SQL 语句中指定数据的确切值。我们改用占位符。因此,将参数化的 SQL 语句作为第一个请求发送到服务器。我们使用 prepare() 函数来实现这一点。我们将第二个请求中参数的确切值绑定到数据库服务器。为此,我们使用 bindValue() 函数。这样,我们在第一个请求时发送程序,在第二个请求中发送数据。如果我们要求将数据与 SQL 代码一起使用,则用户可以更改程序并编写恶意代码。因此,它可以防止恶意 SQL 代码被注入到服务器中。

例如,表 users 包含以下字段和数据。

+----+-----------+----------+------------+
| id | firstname | lastname | dob        |
+----+-----------+----------+------------+
|  1 | bruce     |  rose    | 1998-02-13 |
|  2 | jeff      |  james   | 2000-03-30 |
+----+-----------+----------+------------+

它创建一个变量 $firstname,并为其分配名称 bruce。它创建变量 $sql 并在其上写了一个查询 SELECT * FROM users WHERE firstname =:fname;

不要为 firstname 写出确切的数据值。而是使用参数:fname。使用 $pdo 变量在查询变量上调用 prepare() 函数。将:fname 的值替换为变量 firstname。使用 execute() 函数执行该语句。如果凭据与数据库匹配,则使用 fetch() 函数检查结果。如果是这样,则显示所选行的 idfirstnamelastname

下面的示例演示了预准备语句的用法。它将 firstname 字段的值存储在变量中,以验证凭据是否匹配。如果该变量包含一些恶意代码,它将显示消息 Credentials do no match。这是因为 prepared() 函数仅接受参数化查询,而不允许使用确切的数据。$pdo 变量包含数据库连接的对象。

示例代码:

# php 7.*
<?php
$firstname = "bruce";
$sql = "SELECT * FROM users WHERE firstname =:fname ;";
$stmt = $pdo->prepare($sql);
$stmt->bindValue(":fname", $firstname);
$stmt->execute();
if(!$result = $stmt->fetch(PDO::FETCH_OBJ)){
    
    
    echo "Credentials do no match";
} else {
    
    
    echo"Id: ".$result->id. " Name: ".$result->firstname." ".$result->lastname;
}
?>

输出:

Id: 1 Name: bruce rose

[在 PHP 中使用参数化查询的 prepared 语句来防止 SQL 注入]

我们可以将 prepared 语句与参数化查询一起使用,以防止在 PHP 中进行 SQL 注入。我们使用 mysqli() 函数的对象创建数据库连接。在这种方法中,我们使用问号符号 ? 作为数据的占位符。我们将 prepare() 函数用作上述方法。我们使用 bind_param() 函数将真实数据绑定到占位符中。该方法遵循与上述方法类似的工作机制。

例如,建立一个数据库连接,创建一个 mysqli() 函数的对象,并将其分配给变量 $conn。将名称 jeff 分配给变量 $firstname。创建变量 $sql 并编写查询 SELECT * FROM FROM where where first name = ?;。使用 $conn 变量调用查询变量上的 prepare() 函数。更换占位符 ? 与变量 $firstname 一起使用。使用 execute() 函数执行该语句。调用 get_result() 函数将结果存储在 $result 变量中。如果条件失败,请检查该行是否具有 num_rows 属性,并使用 exit() 函数返回消息 No Rows。调用 fetch_assoc() 方法,并将其存储在 while 循环中的 $row 变量中。显示所选行的 idfirstnamelastname

示例代码:

#php 7.x
<?php
$conn = new mysqli($host, $user, $pwd, $dbName);
$firstname = "jeff";
$sql = "SELECT * FROM users WHERE firstname = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("s", $firstname);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows === 0) exit('No rows');
    while($row = $result->fetch_assoc()) {
    
    
    echo"Id: ".$row['id']. " Name: ".$row['firstname']." ".$row['lastname'];
}

输出:

Id: 2 Name: jeff james

[将 PDO::ATTR_EMULATE_PREPARES 属性设置为 false 以防止 SQL 注入]

如果我们没有正确设置 PDO 属性,则在 PDO 中使用预处理语句可能不足以防止 SQL 注入。我们应该将 PDO::ATTR_EMULATE_PREPARES 属性设置为 false 以防止注入。如果将属性设置为 true,则 PDO 将仅模拟准备好的语句,而不使用它们。因此,系统将容易受到 SQL 注入的攻击。

例如,在变量 $pdo 中创建到数据库的 PDO 连接。使用该变量调用 setAttribute() 函数。将属性 PDO::ATTR_EMULATE_PREPARES 设置为 false。

代码示例:

#php 7.x
<?php
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
?>

猜你喜欢

转载自blog.csdn.net/weixin_50251467/article/details/131776947