2013-03-18 58 views
12

我負責維護和擴展PHP代碼庫,該代碼庫始於2007年,並使用原始的mysql模塊。所有的用戶輸入都使用鑄造轉義爲期望爲數值的值,mysql_real_escape_string()使用單引號字符串引用,可能通過in_array()ENUM字段進行進一步過濾,或array_intersect()SET字段進行進一步過濾。輸出HTML時,所有不受約束的字符串字段都將通過htmlspecialchars()htmlentities()。如果一個值代表一個外鍵,那麼該鍵現在首先被驗證。
我相信,通過嚴格遵循這些程序,應用程序就像它可以抵禦注入和其他形式的攻擊一樣安全。 (獎勵積分:我是否正確?如果不是,我錯過了什麼?)PHP(已棄用)mysql模塊與MySQLi和PDOs的漏洞

將此應用程序轉換爲mysqli或PDO將是一項相當大的任務(並且爲了避免意外中斷,我不希望自動化) 。所以最後到我的問題:使用舊的mysql模塊時是否有任何特定的漏洞無法緩解,這些漏洞需要遷移到較新的模塊?

賞金信息:
需要明確的是,我希望從PHP開發人員的mysql模塊對所有已知漏洞補丁爲CVE編號列表或語句,和 - 這樣的日期。我還假設按照使用模塊的最佳實踐不會將我暴露給其他攻擊媒介。在將數據插入新語句之前,BCP已經包含從數據庫中獲取的轉義數據。繼續下去並沒有真正解決這個問題。

+3

如果你看看['mysql_real_escape_string()']頁面(http://php.net/mysql_real_escape_string),有一個黃色的橫幅表示你需要設置字符集(直接在服務器上或者通過使用[ mysql_set_charset()'](http://www.php.net/manual/en/function.mysql-set-charset.php))以使mysql_real_escape_string生效。 – MarcDefiant 2013-03-18 09:21:45

+1

我建議把這個問題分成2個單獨的問題。已棄用的mysql模塊與XSS(以及XSRF和其他幾十種)的攻擊完全無關。 – 2013-03-18 09:36:28

+0

@Mogria請加你的評論作爲一個完整的答案,所以我可以表決它:) – 2013-03-22 12:58:01

回答

7

我只有2異議

  • All user input is escaped是一個重要的故障,導致second order injection。 「對於SQL所有動態數據」是正確的做法和措辭
  • 有在您的文章中沒有提到identifiers,但我不能相信你沒有在代碼中動態識別碼查詢2007年以來

也有一個小小的不便:在幾年(大概3-4個),你的PHP將開始發出E_DEPRECATED級別的錯誤。但他們可以簡單地關閉。

無論如何,從一個API到另一個API的機械移動不會有太大意義。
僅重構SQL處理代碼以利用一些抽象機制,無論是ORM,AR,QueryBuilder還是其他任何可以從應用程序代碼中清除原始API調用的技術。它不僅會讓你的代碼變得更加臃腫,而且還會使它獨立於任何未來會觸發PHP開發人員的奇想。

回答編輯的問題。

在舊的mysql分機中沒有基本的漏洞。通常使用的唯一的方式易受攻擊且容易出錯。
因此,不要在模塊上尋找應變,更好地審覈您的代碼。如果它沒有使用集中式庫用於利用準備好的語句進行數據庫交互,那麼它很可能是易受攻擊的。

+0

感謝您的回覆。你能否擴展這些子彈點?通過「用戶輸入」,我的意思是「沒有硬編碼的東西」。這種數據的唯一來源我可以想到的是$ _POST變量(或者非POST,非安全[在HTTP意義上]方法中的php://輸入流)。請提供「二階」來源的例子。另外,我不確定'標識符'和'動態標識符'是什麼意思(它們是同一個東西嗎?)。你指的是主鍵? – 2013-03-18 09:35:23

+0

我認爲通過「二次注入」,他意味着已經存儲在服務器上的數據的SQL注入。例如:從數據庫中過濾用戶名的文本。用戶名恰好包含'''和一些討厭的代碼。 – MarcDefiant 2013-03-18 09:50:46

+0

我敢打賭,如果你可以提供一個Blind或Second Order Injection的例子,以防應用程序使用mysql_real_escape_string()+正確的字符集等等。 – 2013-08-06 07:35:14

1

我不覺得有資格完全回答您的問題,所以請謹慎使用我提供的信息,但我在管理您可能正在查看的這些更改方面有一些經驗。然而,如果你所說的話是真實的,那麼你的語句應該可以保護你免受XSS和SQL注入攻擊。

我最近已經開始了將整個大型應用程序從mysql_遷移到mysqli_的過程,並且在此過程中我還設定了所有用戶輸入應通過預準備語句的目標。

爲了迴應下面的YC公平評論進行編輯:爲了避免歧義,我總是把用戶通過準備好的語句生成的任何東西,即使它已經存儲在數據庫中。儘可能避免使用重新插入用戶數據,因爲它是不可靠的,所以系統函數往往依賴於自動生成的索引。

公平地說,頁面很短(不超過1000行),所以修復不會每頁花費很長時間,而且他們的查詢也很少,所以性能下降並不明顯,而且肯定會因服務器技術的改進而吃光了,因爲我寫了原來的代碼。我懷疑你會發現,儘管你必須檢查它是否危急,但是逃避等等的減少遠遠超過了對準備語句的任何性能影響。

令我感到沮喪的是,在執行此評論時,我在代碼中發現了多少個漏洞(我在寫入時包含安全性儘可能最好,並且自己的規則與您的規則大致相同),最終我發現需要重寫大代碼塊以提高安全性。由於更豐富的經驗和代碼調整,性能得到顯着改善。

我正在進行的改變的方式是添加一個mysqli連接到我的數據庫頭文件。所有新代碼都使用這個。當我發現時,我正在更新舊代碼並使用沒有舊的mysql連接的頭文件測試每個頁面。在開發環境中很快找到你錯過的部分,這可能是一種非常好的方式,因爲每個頁面只需要幾分鐘更新就可以浪費時間,因此可以在腦衰落期間完成周期。

第二順序噴射順便說一句,因爲這是我所建在最常見的漏洞的說明:

大多數SQL注入預防樣的假設注入攻擊只會發生在登錄時,從一個惡意的非曾經挫敗的註冊用戶永遠不會返回,並且註冊用戶可以被信任。並非如此。

可以想象,代碼可以通過您的保護注入,然後使用。由於它嚴重依賴於笨拙的數據庫和應用程序設計,因此這種方法最不可能奏效,但世界上一些最聰明的人是黑客。爲什麼讓他們的生活更輕鬆

如果你的sql很簡單,並且你的應用程序使用之前從數據庫中獲得的數據執行任何subquerying,那麼攻擊就會變得更加可能。請記住,

' OR 1=1 gets converted to 
\' OR 1=1 by mysql_real_escape_string but is stored as 
' OR 1=1 in the db 

所以如果檢索並放置到一個PHP變量,然後在SQL查詢中使用轉義,它就可以引起問題一樣的,就好像它從來沒有逃脫。如果您僅對所有查詢使用準備語句,則風險會永久消失,但請記住準備語句仍會存儲惡意代碼,因此當您下次需要使用已輸入的數據時,您仍然必須再次使用準備好的語句。

This Blog給出了一個體面的討論和示例,所以我不會進一步擴展,但如果確保所有用戶輸入數據都通過準備好的語句,如果它被用作查詢的一部分,即使它已經存儲在數據庫中,你應該是安全的。

在重複的風險下,它也值得對OWASP site非常友好,它具有重要的安全性討論。

+0

-1爲矛盾的「**用戶輸入**應通過準備好的語句」與「二次注入」,並提及OWASP網站實際上倡導不安全的解決方案。 – 2013-08-04 11:56:43

+0

恕我直言,不矛盾,但我不配得到-1。糾正和你的意見總是讚賞!你會建議哪個安全網站? – 2013-08-04 20:03:14

+0

因此,您將數據劃分爲「用戶提供」和「非用戶提供」,並始終牢記數據源,並以不同方式對待它。 – 2013-08-04 20:05:04

1

好了,所以我做了一個小小的研究,唯一的弱點,我對於mysql擴展發現似乎也影響同樣mysqli的擴展CVE-2007-4889 這是一個「安全模式旁路」的漏洞,並已定長前段時間 什麼更多的是,這兩個mysql.so和mysqli.so模塊共享幾乎相同的進口可以看出 -

/usr/lib/php5/20090626/mysql.so:

0x0000000000000001 (NEEDED)    Shared library: [libmysqlclient.so.18] 
0x0000000000000001 (NEEDED)    Shared library: [libc.so.6] 
0x000000000000000e (SONAME)    Library soname: [mysqli.so] 

/usr/lib/php5/20090626/mysqli.so:

0x0000000000000001 (NEEDED)    Shared library: [libmysqlclient.so.18] 
0x0000000000000001 (NEEDED)    Shared library: [libc.so.6] 
0x000000000000000e (SONAME)    Library soname: [mysql.so] 

也有某種可能性,其中新漏洞可能是因爲他們共同的進口性質 的兩個模塊提高並且有總在那裏一個獨特的缺陷就是源於這些模塊中的一個實際的代碼有機會的。 但到目前爲止,它看起來像兩個模塊的漏洞紀錄是幾乎相同的,以這個日期

如此地我會在審計PHP源代碼,確保幾件事情投入更多的時間 -

  1. SQL注入 - Parametrized SQL查詢是針對這種缺陷的最佳解決方案。

  2. XSS(跨站腳本) - 使用用htmlspecialchars()來過濾危險字符

  3. CSRF(跨站請求僞造) - 總是對的形式進行引用檢查,以確保將數據從正確的地方

    到達
  4. 文件包含 - 確保沒有用戶輸入,可直接影響納入(需要(),require_once(),包括(),include_once()的)文件

  5. 文件上傳的 - 在情況下文件上傳啓用出於某種原因請務必不要讓用戶控制文件擴展名或保存文件並將其設置爲「不執行」。這是爲了防止攻擊者上傳惡意文件並在您的服務器上執行代碼。

+0

引用程序檢查對CSRF無效。只有令牌有幫助。 – 2013-08-06 15:24:15

+0

我喜歡「Froggery」:) – 2013-08-06 15:29:01

+0

哈哈。 和yeah令牌可能會更好 – Xeus 2013-08-06 15:33:34

2

我的答案會有些偏離,而不是回答你的具體問題,我寧願建議這種方法能夠真正幫助你。

無論使用mysql的將來可能會出現什麼漏洞或者可能會出現什麼漏洞,並且無論您的當前代碼庫如何接近(避免使用)SQL注入(儘管它看起來都很好),我可以獲得感覺你仍然寧願遷移到mysqli,但是目的是通過看到短期的可能性來進一步破解不安全和未完全棄用的mysql,從而拖延實現目標。

我建議重構。期。只要做到這一點。請記住要重構,而不要在更改或擴展代碼庫時這麼做 - 這是一個令人討厭的陷阱。儘管這將是一些工作 - 重構,只需開始重構過程(當然是分支)。完成它將會非常令人滿意。期待一些長尾問題。

我假定你描述的每個功能都已經被封裝了,所以重構應該是相當可行的。如果事情沒有被包裝......($#@!),找出一種方法來在項目範圍內唯一地追蹤你的函數調用(包括上下文)(可能使用正則表達式來找到它們),並用新的獨特的 - 被使用的包裝函數。首先徹底探索這一點。在半天時間裏,您將能夠列出您需要的所有正則表達式。所以先計劃一下,首先探索你的路線。

用當前(舊)功能代碼填充新的包裝,看看是否仍然按原樣工作。

然後開始遷移到mysqli,並在內部重建您的包裝。

似乎是一個儘可能簡單的方法,避免了所有的事情和問題,即使你試圖在通常的MySQL中更深入地攻擊你的方法,也會留在你的腦海裏。我不需要告訴你mysqli會帶來的好處,你已經知道這些好處。更重要的是,每一次都是一次良好的實踐,而實際上一勞永逸地承擔這些問題。計劃,討論,分支,嘗試,做,測試,完成和征服!最重要的一點是:確保在重構​​過程中不會有機會擴展您的代碼庫和功能範圍 - 您將會嘗試這樣做:只是重構。稍後添加,擴展或改進。

+0

沒有人的答案接近我正在尋找的東西,但這一個既符合我要去的地方,而且作者得分最低,因此可以用賞金點。 :-) – 2013-08-07 19:35:07