在 PHP 中防止 SQL 注入
- 使用预处理语句和 PDO 防止 PHP 中的 SQL 注入
-
在 PHP 中使用参数化查询的
prepared
语句来防止 SQL 注入 -
将
PDO::ATTR_EMULATE_PREPARES
属性设置为false
以防止 SQL 注入
我们将介绍一种使用准备好的语句和 PHP 数据对象(PDO)在 PHP 中防止 SQL 注入的方法。我们使用 PDO 通过这种方法建立数据库通信。此方法将数据和查询分别发送到数据库服务器,从而防止了数据和服务器的混合。
我们将介绍一种使用准备好的语句和参数化查询来防止 PHP 在 SQL 中注入的方法。我们使用 mysqli
以这种方法建立数据库通信。该方法具有与第一种方法类似的工作机制。形成对比的只是我们用来防止 SQL 注入的 mysqli
函数。
我们将向你展示一个示例,该示例通过将准备好的语句的仿真设置为 false
,来说明如何在 PHP 中使用 PDO 时避免 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()
函数检查结果。如果是这样,则显示所选行的 id
、firstname
和 lastname
。
下面的示例演示了预准备语句的用法。它将 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
变量中。显示所选行的 id
,firstname
和 lastname
。
示例代码:
#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);
?>
Subodh is a proactive software engineer, specialized in fintech industry and a writer who loves to express his software development learnings and set of skills through blogs and articles.
LinkedIn