1.關於SQL Injection
迄今為止,我基本沒有看到誰寫出一篇很完整的文章,或者說很成熟的 解決方案(能做到 的人肯定很多,問題是沒有流傳開來,很遺憾) 我簡單的說幾點,希望啟發大家思考,起到拋磚引玉的作用
一、SQL Injection的原理
SQL Injection的實現方法和破壞作 用有很多,但萬變不離其宗,其原理可以概括為一句話 :SQL Injection就是向服務器端提交事先准備好的數據,拼湊出攻擊者想要的SQL語句,以改變數據庫操作執行計劃。
我想,這麼說也許不算精煉,但意思應該很明確了,這句話主要包含這麼三層意思:
1.攻擊者通過何種途徑注入?
存在SQL Injection漏洞的地方都是應用程序需要根據客戶端環境構造SQL語句的地方。由此可以 推論,只要存在"客戶端數據替換預定義變量"的地方,就有可能被注入。
客戶端提交 數據可以有很多種方式:GET,POST,Client-Agent,Cookie,Server Enviroment...
2.攻擊者 為什麼可以將它想要的語句"注入"?
因為服務器端應用程序采用拼湊(請特別留意這 個詞)SQL語句的方式,這使得攻擊者有機會在提交的數據中包含SQL關鍵字或者運算符,來構造他們想 要的語句。
3.SQL Injection最終結果是什麼?
改變數據庫操作執行計劃。
這個 結果不一定是惡意的,只要你的SQL語句沒有按照你預期的計劃(plan)執行,那麼就 可以視為被注入 了,不管提交數據的人是不是惡意的。
設有這樣的sql語句:
update tableName set columnName1 = " $Client_Submit_Data " where PK_ID = 1234
$Client_Submit_Data是一個變量,它代表客戶端提交的數據,這裡我就不管環境是ASP還 是PHP還是其他什麼東西了。
假設這個操作是要更新一篇文章的標題,很多人是不是會這麼構造 SQL語句?我們看看$Cl ient_Submit_Data包含引號的情況,令$Client_Submit_Data = 誰能告訴我 "sql injecti on"是什麼?
那麼sql語句將被拼湊成這樣:
update tableName set columnName1 = "誰能告訴我"sql injection"是什麼?" where PK_ID = 1234
執行結果很明顯,將執行這樣的語句:update tableName set columnName1 = "誰能 告訴我"
where子句被忽略掉了,很遺憾,你的數據庫中所有文章標題都會被update為 "誰能告訴我 "
在這個例子當中,用戶應該是無心的——標題裡面包括引 號應該很正常吧——但結果卻和SQL Injection無異。
好啦,說了半天廢話,言歸正 傳,說一下如何應對這種問題。
我相信這裡的朋友都看過很多防止SQL Injection的文章了,也 大都會通過replace來防范一些注入,問題是:你們知其然的時候是否知其所以然?
我認為,徹 底解決SQL Injection的最好方法是:避免拼湊SQL語句。這就是我在上面要大家特別注意拼湊這個詞的 原因。
SQL Injection之所以有機可乘,是因為絕大多數Server Application采用拼湊SQL語句的 方式來構建應用程序(閱讀這個帖子的諸位,你們回首想想自己的項目,有幾個不是通過拼湊SQL語句的 方式來操作數據庫?想想你們見過的被注入的案例,有幾個不是采用的拼湊SQL語句的應用),所謂拼湊 SQL語句,簡單一點說就是:用連接字符串操作(ASP中的&和PHP中的.)將SQL關鍵字和客戶端提交 的數據連接起來並發送給DBMS執行。這樣做直接導致 DBMS根本不知道你計劃(plan to)做什麼,而只 知道你要(is to)做什麼,不是嗎,服務器端腳本總是將要執行的SQL語句構造好,然後發給數據庫, DBMS根本不知道客戶端數據 替換了變量之後,這個語句的執行計劃是否有變化。服務器端腳本總是粗暴 的告訴DBMS:你只管這麼做好了,別問我為什麼。就像上面我提到的更新文章標題的例子,DBMS不知道 你只想更新第1234篇文章的標題,它以為你就是要把所有的標題都變成這個,因為你的語句就是沒有 where子句嘛!
說到這裡,可能大家都明白了,所謂的最好方法是Stored Procedure。Yes! That is!
要想做出安全可靠的Server application,你最好把自己當作兩個人,一個DBA,一個Coder (ASP Coder,PHP Coder or others),很多人往往只知道:我在做一個BBS,我在做一個留言本,我在 做一個新聞發布系統,我們的流程都是這樣的,給用戶一個表單,讓用戶提交,然後去寫數據庫,用的 時候根據條件把數據記錄找出來,然後顯示。沒事,如果你 是一個業余愛好者,只想自己寫點小東西玩 玩,這足夠了!如果你想把WebDev作為你的職業,或者說,你想成為一個非常專業的業余愛好者,你必 須當自己是一個DBA+Coder,至於要不要是一個Designer就看你的能力和精力咯!
好了,點到為 止,我就說這麼多,徹底的解決方法是要在DBMS上寫入你的數據操作計劃,讓服務器在開始執行之前知 道你的意圖,不要粗暴的告訴它:我就是要你執行這個命令,不要問我為什麼!
實現方法嘛,目前比較普遍的,也比較容易實現的就是存儲過程了,應用存儲過程不僅可以從根本上解決SQL Injection 這個安全問題,還會使得你的應用程序速度成倍增長(這個增長的幅度甚至可能達到一個數量級,這跟 很多因素有關,不好一概而論),還會使得你開發的系統更想大型系統,擁有更好的架構體系(例如MVC 模式)。
在MySQL 4.1.x及其後續版本和ODBC中,提供了一種叫做prepared statements的東西 ,它本質上也是一種存儲過程,一種系統預置(相對於用戶自定義)的存儲過程。