2016-07-08 69 views
-1

是否有東西可能會逃脫我的腳本中的衛生設施,或者是否安全?大多數 SQL注入?我理解它的方式,如果您將查詢作爲準備好的參數傳遞,則查詢的構建方式並不重要,對嗎?這個動態SQL查詢生成是否安全注入?

EDIT2:我編輯的代碼,以反映的結合$ _ POST值

$q = $pdo->prepare('SHOW COLUMNS FROM my_table'); 
$q->execute(); 
$data = $q->fetchAll(PDO::FETCH_ASSOC); 
$key = array(); 
foreach ($data as $word){ 
    array_push($key,$word['Field']); 
    } 
$sqlSub= "INSERT INTO other_table("; 
$n = 0; 
foreach ($key as $index){ 
    $sqlSub = $sqlSub.$index.", "; 
    $n = $n + 1; 
} 
$sqlSub = $sqlSub.") VALUES ("; 
for ($i=1; $i<$n;$i++){ 
    $sqlSub = $sqlSub."?, "; 
} 
$sqlSub = $sqlSub.."?)"; 
$keyValues = array(); 
for($i=0;i<n;$i++){ 
    array_push($keyValues,$_POST[$key[$i]]); 
} 
$q->$pdo->prepare($sqlSub); 
q->execute($keyValues); 

編輯建議:這是最終的查詢的樣子建議後修改

INSERT INTO other_table($key[0],...,$key[n]) VALUES (?,...,nth-?); 
+4

'如果您將查詢作爲準備好的參數傳遞,那麼查詢的構建方式如何......錯誤並不重要。是的,這仍然是脆弱的。事實上,就像您沒有準備查詢一樣,您也同樣脆弱。使這個sql注入安全的方法不是僅準備查詢,而是使用佔位符準備查詢並將值綁定到這些佔位符。 –

+2

不!如果你不使用綁定你的值,你是不安全的。 – aynber

+1

不,如果你想使它安全的話,使用'Describe'或'Explain'數組鍵的列表可以被改變,如果它們是表單輸入的名字,例如列表中的列可以交叉檢查它們。然後使用準備好的語句來獲取這些值,並使用白色的鍵列表。 – ArtisticPhoenix

回答

0

否。顯示的示例代碼是而不是從大多數SQL注入中都是安全的。

你的理解是完全錯誤的。

重要的是SQL文本。如果這是使用潛在的不安全值動態生成的,那麼SQL文本就很脆弱。


該代碼在多個地方容易受到攻擊。即使列的名稱也可能不安全。

CREATE TABLE foo 
(`Robert'; DROP TABLE Students; --` VARCHAR(2) 
, `O``Reilly`       VARCHAR(2) 
); 

SHOW COLUMNS FROM foo 

FIELD        TYPE  NULL 
-------------------------------- ---------- ---- 
Robert'; DROP TABLE Students; -- varchar(2) YES 
O`Reilly       varchar(2) YES 

您將需要封閉列標識符在反引號,與另一反引號列標識符中逸出的任何反引號之後。

+0

這些列的名稱是不安全的,因爲這些列是直接從不可變表的服務器端獲取的,無需用戶輸入?另外我編輯了我的文章 –

+2

我演示瞭如何列標識符可能不安全以包含在SQL文本中,並需要特殊處理才能使它們安全的示例。這就是爲什麼你會看到mysqldump和各種MySQL工具在反引號中包裝標識符,即使反引號不是必需的。 (總是這樣做要快,而不是檢查是否需要檢查。) – spencer7593

+0

現在我明白了。如果我也允許用戶創建他們自己的表模式,然後允許他們運行這個腳本,他們可以完全按照您所說的通過列名進行操作。有道理,好點。 –

-1

恰好有一個的方式來防止SQL注入:確保您的查詢字符串文本從未包括用戶提供的內容,無論你多麼嘗試「的sanitize」吧。

當您使用「佔位符」的建議,SQL字符串的文本包含(可能是...)問號... VALUES (?, ?, ?)來表示每個地方的參數是要插入。 參數值的相應列表分別提供,每次查詢被執行。

因此,即使last_name提供的值是"tables; DROP TABLE STUDENTS;",SQL將永遠認爲這是「SQL字符串的一部分。」它會簡單地將「最不尋常的last_name插入到數據庫中。

如果你正在做批量操作,事實上,你需要準備只一次可以節省大量的時間發言。然後,您可以根據需要多次執行該語句,並且每次都將不同(或相同)的參數值傳遞給它。

0

正如其他人所指出的,確保您的列名是安全的。

SQL注入可能發生在任何外部輸入,而不僅僅是http請求輸入。如果您使用從文件,Web服務或其他代碼的函數參數或其他代碼的返回值,甚至從您自己的數據庫中讀取內容,則可能會面臨風險... 不信任任何東西! :-)

你可以確保列名本身逃脫。不幸的是,在大多數API或框架中沒有內置的功能。所以你必須用正則表達式自己做。

我也建議你瞭解PHP的內置陣列功能(http://php.net/manual/en/ref.array.php)。很多代碼可能會更快地開發代碼,並且它也可能會有更好的運行時性能。

下面是一個例子:

function quoteId($id) { 
    return '`' . str_replace($id, '`', '``') . '`'; 
} 

$q = $pdo->query("SHOW COLUMNS FROM my_table"); 
while ($field = $q->fetchColumn()) { 
    $fields[] = $field; 
} 

$params = array_intersect_key($_POST, array_flip($fields)); 
$fieldList = implode(",", array_map("quoteId", array_keys($params))); 
$placeholderList = implode(",", array_fill(1, count($params), "?")); 
$sqlSub = "INSERT INTO other_table ($fieldList) VALUES ($placeholderList)"; 

$q = $pdo->prepare($sqlSub); 
$q->execute($params); 

在本例中,我相交從與柱的請求參數的表中的列。這樣我只使用那些也在列集中的後置參數。它最終可能會在SQL中產生一個少於所有列的INSERT語句,但如果缺少的列有缺省值或允許NULL,那沒關係。