2016-03-03 97 views
1

目前我正在研究一個簡單工具的概念,以執行一些用PHP編寫的「維護」數據庫操作(drop/truncate/copy tables等)。PHP PDO:保護針對SQL注入的動態標識符

這必然要求SQL語句中的標識符是動態用戶輸入。儘管預處理語句對於任何比較值的SQL語句與用戶輸入的分離都是完美的,但它們並不意味着用於表名或列名等標識符。 (也就是說,I can't use準備了用於準備標識符的語句。)

保護動態標識符的常用方法是將白名單列入白名單,但這需要靜態和已知的數據庫結構。例如,我想執行一個像Copy table A and name it B這樣的命令。這裏有趣的部分是B

假設用戶通過身份驗證並被允許執行此操作,如何防止SQL注入?這甚至有可能嗎?

我發現an approach這表明,在任何這樣的標識符簡單地引用重音符(`):

$table_name  = 'origin_table'; // can be checked against existing tables 
$copy_table_name = 'user_input'; 
$quoted_table_name = '`' . str_replace('`', '``', $copy_table_name) . '`'; 
$sql_statement  = "CREATE TABLE {$quoted_table_name} LIKE {$table_name}"; 

那是一個足夠的保護,防止可能的SQL注入?

更新

PDO::quote()(在回答中提到的)是不是一種選擇。它不會逃避重音符(`):

$user_input = 'table`; TRUNCATE TABLE users --'; 
var_dump($pdo->quote($user_input)); 
//string(33) "'table`; TRUNCATE TABLE users --'" 

更新2 PostgreSQL的擴展具有的功能正是出於這個目的:https://secure.php.net/manual/en/function.pg-escape-identifier.php

+0

是的,但只要完整的字符串被認爲是標識符,像'CHAR(96)'這樣的函數不會被MySQL解釋。 (編輯:我回答的評論已被刪除) – David

+0

大聲思考:我會讓用戶在表單中輸入表格和列名。現在,這些可以驗證爲無意義的字符和代碼。然後可以很容易地檢查它們與'mysql數據字典'的匹配。任何不匹配,然後錯誤。我還會有一個表格和/或列的「白名單」。從提供的信息中生成所需的SQL是一項相當簡單的任務。即。想'查詢建設者'? –

+0

@RyanVincent謝謝,我會處理這些問題。一個最佳的解決方案將是像'TableCopier :: copyTables($ src,$ dest)'這樣的方法。我肯定可以給這個方法寫一個評論:«不要讓它過分的價值!»。但是這並不能保護它不被使用,並在野外造成SQL漏洞。 – David

回答

-1

至於你提到的報價()爲PDO功能,可用於轉義列名以及數據。或者使用預先準備的語句,例如CREATE TABLE?喜歡 ?然後只執行查詢。

+0

PDO預處理語句不可行[因爲](https://secure.php.net/manual/en/pdo.prepare.php):»參數標記只能表示一個完整的數據文字«(但不是標識符)。 'quote()'方法需要從字符串中去掉第一個和最後一個''',這表明我不是用它的方式來使用它。此外,我在我的問題中鏈接的評論指出,轉義標識符和轉義字符串«有所不同。 – David

0

你總是想逃避`標識符,甚至表名和字段名稱,因爲也許明天他們將被保留字和打破你的查詢。只要你正在使用準備好的語句(PDO,mysqli,或其他),你會沒事的。請注意,PDO不允許轉義表或字段名稱。

你只需要細化你的過濾機制,至於什麼表名等是允許的,而不是。你可以這樣做:「CREATE TABLE {$ quoted_table_name} LIKE {$ table_name}」; ..用戶使用佔位符(?,或:name等)準備語句

編輯: 既然你需要保護的標識符,我看到2種方式:

  1. 圍繞他們(')
  2. 過濾&轉義傳入值(mysql_real_escape_string或更好)。過濾將包括刪除任何不必要的字符(您可能希望只允許使用字母[a-z] +或帶數字的字母。
+0

PDO準備好的語句不可行[因爲](https://secure.php.net/manual/en/pdo.prepare.php):»參數標記只能表示一個完整的數據文字«(但不是標識符)。 – David

+0

然後在普通的mysql中逃脫,PDO負責參數和查詢分離。但回到你的問題,明白你正在執行的查詢是什麼?你不只是把表名稱作爲輸入並執行查詢?我不明白問題在哪裏? –

+0

該查詢實際上並不相關。問題是,如何在SQL查詢中安全地使用_identifiers_(表名,列名)的用戶輸入。 – David