準備好的語句中的參數化表名:一個困境
儘管mysqli_stmt_bind_param 已被證明可以有效防止SQL 注入,但當當變數影響時,它會遇到限制涉及到表名。如提供的程式碼片段所示:
function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol ) { $statement = $mysqli->prepare("INSERT INTO " .$new_table . " VALUES (?,?,?,?,?,?,?);"); mysqli_stmt_bind_param( $statment, 'sssisss', $Partner, $Merchant, $ips, $score, $category, $overall, $protocol ); $statement->execute(); }
$new_table 的有問題的串聯引入了 SQL 注入漏洞。試著用另一個佔位符取代它,如以下程式碼片段所示,失敗:
function insertRow( $db, $mysqli, $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol ) { $statement = $mysqli->prepare("INSERT INTO (?) VALUES (?,?,?,?,?,?,?);"); mysqli_stmt_bind_param( $statment, 'ssssisss', $new_table, $Partner, $Merchant, $ips, $score, $category, $overall, $protocol ); $statement->execute(); }
準備語句的限制
核心問題在於無法準備好的語句來保護定義SQL 語句結構的參數,例如表名。這是因為準備好的語句只允許參數值不改變語句的意思。由於表名決定了 SQL 語句的有效性,因此在執行期間修改它們可能會使其無效。
即使使用像 PDO 這樣的資料庫接口,透過在將參數發送到資料庫之前替換參數來模擬準備好的語句,佔位符值仍然是SQL 語句中包含的字串。結果,SELECT FROM ?使用 mytable 作為參數最終會將 SELECT FROM 'mytable' 傳送到資料庫,使其無效。
降低風險
最安全的方法仍然是在字串中使用 $mytable,但它必須附帶一個用於檢查用戶輸入的表白名單。這可以防止惡意行為者在任意表上執行 SQL 語句。因此,以下程式碼示範了安全實作:
if (whitelisted_tables($mytable)) { $statement = $mysqli->prepare("INSERT INTO $mytable VALUES (?,?,?,?,?,?,?);"); mysqli_stmt_bind_param( $statment, 'sssisss', $Partner, $Merchant, $ips, $score, $category, $overall, $protocol ); $statement->execute(); }
以上是如何在準備語句中安全地使用參數化表名來防止 SQL 注入?的詳細內容。更多資訊請關注PHP中文網其他相關文章!