今天早些時候,有人問到有關input validation strategies in web apps的問題。做htmlspecialchars和mysql_real_escape_string保持我的PHP代碼安全注入?
在撰寫本文時,頂部的答案建議在PHP
只使用htmlspecialchars
和mysql_real_escape_string
。
我的問題是:這足夠嗎?我們應該知道更多嗎?這些功能在哪裏分解?
今天早些時候,有人問到有關input validation strategies in web apps的問題。做htmlspecialchars和mysql_real_escape_string保持我的PHP代碼安全注入?
在撰寫本文時,頂部的答案建議在PHP
只使用htmlspecialchars
和mysql_real_escape_string
。
我的問題是:這足夠嗎?我們應該知道更多嗎?這些功能在哪裏分解?
當涉及到數據庫查詢時,總是嘗試使用準備好的參數化查詢。 mysqli
和PDO
庫支持這一點。這比使用轉義函數如mysql_real_escape_string
更安全。
是的,mysql_real_escape_string
實際上只是一個字符串轉義函數。這不是一個神奇的子彈。它所要做的就是轉義危險字符,以便它們可以安全地在單個查詢字符串中使用。但是,如果您沒有事先清理您的輸入,那麼您將很容易受到某些攻擊媒介的攻擊。
想象一下以下SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
你應該能夠看到,這是容易被利用。
想象id
參數包含了常見的攻擊向量:
1 OR 1=1
那裏面有沒有風險的字符編碼,因此它會通過直通過逃避過濾器。離開我們:
SELECT fields FROM table WHERE id= 1 OR 1=1
這是一個可愛的SQL注入載體,將允許攻擊者返回所有行。 或者
1 or is_admin=1 order by id limit 1
產生
SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1
,允許攻擊者在這個完全虛構的例子返回第一個管理員的詳細信息。
雖然這些功能很有用,但必須小心使用。您需要確保所有網頁輸入在某種程度上得到驗證。在這種情況下,我們看到我們可以被利用,因爲我們沒有檢查我們用作數字的變量,實際上是數字。在PHP中,您應該廣泛使用一組函數來檢查輸入是整數,浮點數,字母數字等。但是對於SQL,請注意準備語句的大部分值。如果數據庫函數已知道1 OR 1=1
不是有效的文字,則上述代碼將是安全的。對於htmlspecialchars()
。這是它自己的一個雷區。
在PHP中存在一個真正的問題,它具有不同的與html相關的轉義函數的全部選擇,並且沒有明確的指導哪些函數會做什麼。首先,如果你在一個HTML標籤內,你真的很麻煩。看看
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
我們已經是一個HTML標記內,因此我們不需要<或>做任何危險。我們的攻擊媒介可能僅僅是javascript:alert(document.cookie)
現在產生的HTML看起來像
<img src= "javascript:alert(document.cookie)" />
攻擊直通得到。
它變得更糟。爲什麼?因爲htmlspecialchars
(當這樣調用時)只能編碼雙引號而不是單引號。所以,如果我們有
echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";
我們的邪惡攻擊者現在可以注入全新的參數
pic.png' onclick='location.href=xxx' onmouseover='...
給我們
<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />
在這種情況下,也沒有神奇的子彈,你只需要自己調整輸入。如果你嘗試過濾出不好的字符,你肯定會失敗。採取白名單的方式,只允許通過良好的字符。查看XSS cheat sheet,瞭解各種向量可能的示例
即使您在HTML標記之外使用htmlspecialchars($string)
,仍然容易受到多字節字符集攻擊媒介的攻擊。
您可以最有效地使用mb_convert_encoding和htmlentities的組合,如下所示。
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
即使這樣也會讓IE6容易受到攻擊,因爲它處理UTF。但是,在IE6使用率下降之前,您可能會回退到更有限的編碼,例如ISO-8859-1。
爲了更深入的研究,多字節的問題,請參見https://stackoverflow.com/a/12118602/1820
除了Cheekysoft的出色答卷:
是不是真的爲了防止HTML注入(如跨站腳本)銀彈,但你可以如果您使用庫或模板系統輸出HTML,則可以更輕鬆地實現它。閱讀有關如何正確轉義事物的文檔。
在HTML中,事情需要根據上下文以不同的方式轉義。對於放入Javascript的字符串尤其如此。
我肯定會與上述職位同意,但我有一個小的事情在回答增加Cheekysoft的回答,特別是:
當涉及到數據庫查詢, 總是試圖用準備 參數化查詢。 mysqli和PDO庫支持這一點。這是 比使用轉義 功能如 mysql_real_escape_string更安全。
是的,mysql_real_escape_string是 有效只是一個字符串轉義 函數。這不是一個神奇的子彈。 它會做的只是逃脫危險 字符,以便它們可以安全地在單個查詢字符串中使用 。 但是,如果您沒有事先對您的 輸入進行消毒,那麼您將成爲 容易受到某些攻擊媒介的攻擊。
想象以下SQL:
$結果= 「選擇FROM表 字段WHERE ID = 」 .mysql_real_escape_string($ _ POST [ 'ID']);
您應該能夠看到這是易受攻擊的 。試想ID 參數包含了常見的攻擊向量 :
1 OR 1 = 1
那裏面有沒有風險的字符來 編碼,因此它會直接 通過逃避過濾器。離開 我們:
選擇字段FROM表WHERE ID = 1 OR 1 = 1
我編寫了一個小巧的功能,我把我的數據庫類,將去掉任何心不是一個數量。它使用了preg_replace,所以概率更優化的一點作用,但在緊要關頭的作品...
function Numbers($input) {
$input = preg_replace("/[^0-9]/","", $input);
if($input == '') $input = 0;
return $input;
}
因此,而不是使用
$結果=「選擇字段FROM表WHERE ID =「.mysqlrealescapestring(」1 OR 1 = 1「);
我會用
$結果= 「選擇字段FROM表WHERE ID =」。數字(「1或1 = 1」);
,它會安全地運行查詢從表
選擇字段WHERE ID = 111
當然,這只是停止了它無法顯示正確的行,但我不認爲是誰試圖注入到您的網站的SQL是一個大問題;)
這個難題的一個重要部分是上下文。
SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"
導致:
SELECT fields FROM table WHERE id='1 OR 1=1'
這是無效的,如果你在引用查詢的每個論點有人發送 「1 OR 1 = 1」 的ID是沒有問題的。由於您正在轉義字符串,所以輸入無法脫離字符串上下文。我已經測試過MySQL的版本5.0.45,並且使用整數列的字符串上下文不會導致任何問題。
$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];
在64位系統上工作良好,甚至更好。儘管如此,請注意您的系統在處理大量數據時的限制,但對於數據庫ID來說,這在99%的時間內很有效。
您應該使用單個函數/方法來清理您的值。即使這個函數只是mysql_real_escape_string()的包裝器。爲什麼?因爲有一天,如果發現利用您的首選清理數據的方法,您只需將其更新到一個地方,而不是在系統範圍內找到並替換。
爲什麼,哦爲什麼,你會而不是包括用戶輸入在您的SQL語句周圍引號?似乎很愚蠢的不!包括你的sql語句中的引號會使「1或1 = 1」成爲毫無結果的嘗試,不是嗎?
所以現在,你會說,「如果用戶在輸入中包含引號(或雙引號)會怎麼樣?」
好吧,簡單的解決方法:只需刪除用戶輸入的報價。例如:。現在,無論如何,在我看來,用戶輸入將是安全的...
這裏唯一遺漏的是,DB查詢的第一個例子...一個簡單的intval()將解決注入。需要數字而不是字符串時,始終使用intval()代替mysqlescape ...()。 – 2009-04-09 03:15:58
並記住使用參數化查詢將允許您始終將數據視爲數據而不是代碼。儘可能使用PDO等庫並使用參數化查詢。 – Cheekysoft 2009-04-14 10:47:37
優秀的答案! – joedevon 2009-06-12 07:06:02