在 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