亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

如何保護(hù) PHP 免受 SQL 注入?
P粉909476457
P粉909476457 2023-10-08 15:42:46
0
2
900

如果使用者輸入未經(jīng)修改就插入到 SQL 查詢(xún)中,則應(yīng)用程式很容易受到 SQL 注入的攻擊,如下例所示:

$unsafe_variable = $_POST['user_input']; 

mysql_query("INSERT INTO `table` (`column`) VALUES ('$unsafe_variable')");

這是因?yàn)槭褂谜呖梢暂斎腩?lèi)似 value') 的內(nèi)容; DROP TABLE table;--,查詢(xún)變成:

INSERT INTO `table` (`column`) VALUES('value'); DROP TABLE table;--')

可以採(cǎi)取什麼措施來(lái)防止這種情況發(fā)生?

P粉909476457
P粉909476457

全部回覆(2)
P粉754477325

要使用參數(shù)化查詢(xún),您需要使用 Mysqli 或 PDO。要使用 mysqli 重寫(xiě)您的範(fàn)例,我們需要如下內(nèi)容。

prepare("INSERT INTO table (column) VALUES (?)");
// "s" means the database expects a string
$stmt->bind_param("s", $variable);
$stmt->execute();

您需要閱讀的關(guān)鍵函數(shù)是 mysqli::prepare.

此外,正如其他人所建議的,您可能會(huì)發(fā)現(xiàn)使用諸如 PDO.

請(qǐng)注意,您詢(xún)問(wèn)的案例相當(dāng)簡(jiǎn)單,更複雜的案例可能需要更複雜的方法。特別是:

  • 如果您想根據(jù)使用者輸入來(lái)變更 SQL 結(jié)構(gòu),參數(shù)化查詢(xún)不會(huì)有幫助,且 mysql_real_escape_string 不包含所需的轉(zhuǎn)義。在這種情況下,您最好透過(guò)白名單傳遞使用者的輸入,以確保只允許「安全」值通過(guò)。
P粉285587590

無(wú)論您使用哪種資料庫(kù),避免SQL 注入攻擊的正確方法都是將資料與SQL 分離,這樣資料仍然是數(shù)據(jù),並且 >永遠(yuǎn)不會(huì)被SQL 解析器解釋為指令??梢允褂酶袷秸_的資料部分建立 SQL 語(yǔ)句,但如果您完全不了解詳細(xì)信息,則應(yīng)始終使用準(zhǔn)備好的語(yǔ)句和參數(shù)化查詢(xún)。 是與任何參數(shù)分開(kāi)傳送到資料庫(kù)伺服器並由資料庫(kù)伺服器解析的 SQL 語(yǔ)句。這樣攻擊者就不可能注入惡意SQL。

您基本上有兩個(gè)選項(xiàng)來(lái)實(shí)現(xiàn)此目的:

  1. 使用PDO(用於任何支援的資料庫(kù)驅(qū)動(dòng)程式):

    $stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');
    $stmt->execute([ 'name' => $name ]);
    
    foreach ($stmt as $row) {
        // Do something with $row
    }
    
  2. 使用MySQLi(用於MySQL):
    從 PHP 8.2 開(kāi)始,我們可以使用 execute_query() 在一個(gè)方法中準(zhǔn)備、綁定參數(shù)並執(zhí)行 SQL 語(yǔ)句:

    $result = $db->execute_query('SELECT * FROM employees WHERE name = ?', [$name]);
     while ($row = $result->fetch_assoc()) {
         // Do something with $row
     }
    

    最高可達(dá) PHP8.1:

     $stmt = $db->prepare('SELECT * FROM employees WHERE name = ?');
     $stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'
     $stmt->execute();
     $result = $stmt->get_result();
     while ($row = $result->fetch_assoc()) {
         // Do something with $row
     }
    

如果您要連接到MySQL 以外的資料庫(kù),則可以參考特定於驅(qū)動(dòng)程式的第二個(gè)選項(xiàng)(例如,pg_prepare()pg_execute() 對(duì)於PostgreSQL) 。 PDO 是通用選項(xiàng)。


正確設(shè)定連接

PDO

請(qǐng)注意,當(dāng)使用PDO存取MySQL資料庫(kù)時(shí),真正的準(zhǔn)備好的語(yǔ)句預(yù)設(shè)不使用。要解決此問(wèn)題,您必須停用準(zhǔn)備語(yǔ)句的模擬。使用 PDO 建立連接的範(fàn)例是:

$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8mb4', 'user', 'password');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

在上面的範(fàn)例中,錯(cuò)誤模式並不是絕對(duì)必要的,但建議添加它。這樣,PDO 將透過(guò)拋出 PDOException 的方式通知您所有 MySQL 錯(cuò)誤。

但是,強(qiáng)制是第一行setAttribute() 行,它告訴PDO 禁用模擬準(zhǔn)備好的語(yǔ)句並使用真實(shí)準(zhǔn)備好的語(yǔ)句聲明。這可以確保語(yǔ)句和值在傳送到 MySQL 伺服器之前不會(huì)被 PHP 解析(讓可能的攻擊者沒(méi)有機(jī)會(huì)注入惡意 SQL)。

雖然您可以在建構(gòu)函數(shù)的選項(xiàng)中設(shè)定字元集,但請(qǐng)務(wù)必注意,「較舊」版本的PHP(5.3.6 之前)默默地忽略了DSN 中的字符集參數(shù)。

Mysqli

對(duì)於 mysqli,我們必須遵循相同的例程:

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); // error reporting
$dbConnection = new mysqli('127.0.0.1', 'username', 'password', 'test');
$dbConnection->set_charset('utf8mb4'); // charset

說(shuō)明

您傳遞給prepare的SQL語(yǔ)句由資料庫(kù)伺服器解析和編譯。透過(guò)指定參數(shù)(? 或命名參數(shù),如上例中的 :name),您可以告訴資料庫(kù)引擎您要過(guò)濾的位置。然後,當(dāng)您呼叫 execute 時(shí),準(zhǔn)備好的語(yǔ)句將與您指定的參數(shù)值結(jié)合。

這裡重要的是參數(shù)值與編譯後的語(yǔ)句結(jié)合在一起,而不是 SQL 字串。 SQL 注入的工作原理是在腳本建立要傳送到資料庫(kù)的 SQL 時(shí)欺騙腳本包含惡意字串。因此,透過(guò)將實(shí)際的 SQL 與參數(shù)分開(kāi)傳送,您可以限制最終出現(xiàn)意外結(jié)果的風(fēng)險(xiǎn)。

您在使用準(zhǔn)備好的語(yǔ)句時(shí)發(fā)送的任何參數(shù)都會(huì)被視為字串(儘管資料庫(kù)引擎可能會(huì)進(jìn)行一些最佳化,因此參數(shù)當(dāng)然也可能最終被視為數(shù)字)。在上面的範(fàn)例中,如果$name 變數(shù)包含'Sarah'; DELETE FROMEmployees 結(jié)果只是搜尋字串"'Sarah'; DELETE FROMEmployees",並且最終不會(huì)得到一個(gè)空表。

使用準(zhǔn)備好的語(yǔ)句的另一個(gè)好處是,如果您在同一個(gè)會(huì)話中多次執(zhí)行相同的語(yǔ)句,它只會(huì)被解析和編譯一次,從而提高速度。

哦,既然您詢(xún)問(wèn)瞭如何進(jìn)行插入,這裡有一個(gè)範(fàn)例(使用 PDO):

$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute([ 'column' => $unsafeValue ]);

準(zhǔn)備好的語(yǔ)句可以用於動(dòng)態(tài)查詢(xún)嗎?

雖然您仍然可以對(duì)查詢(xún)參數(shù)使用準(zhǔn)備好的語(yǔ)句,但動(dòng)態(tài)查詢(xún)本身的結(jié)構(gòu)無(wú)法參數(shù)化,而且某些查詢(xún)功能也無(wú)法參數(shù)化。

對(duì)於這些特定場(chǎng)景,最好的方法是使用白名單過(guò)濾器來(lái)限制可能的值。

// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}
最新下載
更多>
網(wǎng)站特效
網(wǎng)站源碼
網(wǎng)站素材
前端模板