1.關於SQL Injection
迄今爲止,我基本沒有看到誰寫出一篇很完整的文章,或者說很成熟的解決方案(能作到 的人確定不少,問題是沒有流傳開來,很遺憾) 我簡單的說幾點,但願啓發你們思考,起到拋磚引玉的做用
1、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的東西,它 本質上也是一種存儲過程,一種系統預置(相對於用戶自定義)的存儲過程。
若是你沒有條件用上存儲過程(好比數據庫不支持,MySQL,Access,SQLite等都不支持),那麼就只能將SQL Injection扼殺在搖籃裏了。解決方法,我也只簡單的說一句:不要相信任何來自客戶端的數據。這個客戶端的數據,能夠經過不少途徑被提交,好比get,post ,cookie,browser參數,IP地址,等等,只要不是服務器上獲取的就都算客戶端數據,只要是客戶端數據,都是不可信的,在TCP/IP這個大框架下,什麼都是能夠僞造的,包括IP地址。
凡是來自客戶端的數據,必須校驗——注意是校驗,不是過濾。基本上,無論你多聰明多細心(哪怕像我同樣,不準笑,不準笑,嚴肅點,嚴肅點,咱們這兒講SQL Injection呢) 也沒法窮舉可能被用於SQL Injection的符號和關鍵字,也沒法預知替換掉他們是否會有副 做用,最好的辦法是不去判斷什麼數據不符合條件,而改由判斷什麼數據符合條件,假設你的一個系統用戶名只能是字母數字和下劃線,那麼你就能夠用[0-9a-zA-Z_]+這個正則來匹配它,若是不符合條件,拒之便可,這比費盡心思去過濾單引號分號逗號空格什麼的要明瞭和簡潔的多。
春節前夕,數萬個用PHPBB做爲論壇的網站被攻陷,你們有印象嗎?罪魁禍首隻是一個單引 ,儘管PHP有magic_quotes_gpc,可仍是被幹掉了,緣由是%2527在url_decode函數中會被解析爲%27(由於%25就是百分號),%27正是引號,By the way,儘管博客中國的論壇也 是基於PHPBB的,可是那次咱們倖免於難,由於在那以前咱們被黑過一次了(汗),就是由於這個,哈哈! 其實,SQL Injection不是ASP編程領域特有的,Web開發最容易碰到,但Desktop Application也有,只要有數據庫的地方,只要採用拼湊SQL語句的方式,就可能存在Injection的機會,你們牢記,若是有條件,儘可能把數據DBMS職責範圍的事情交給DBMS去作,若是沒條件,必定要注意校驗客戶端提交的數據,固然,左右開弓也行,^_^
好了,最後,說句話給那些有志於從事WebDev工做的朋友,若是未來你進入這個領域,你把總結出來這篇文章,你應該會很順利的經過面試,並獲得一個不錯的薪水等級。
附:微軟發佈3款SQL Injection***檢測工具
隨着 SQL INJECTION ***的明顯增多,微軟近日發佈了三個免費工具,幫助網站管理員和檢測存在的風險並對可能的***進行攔截。
這個微軟和 HP合做開發的工具,會在網站中爬行,對全部網頁的查詢字符串進行分析並發現其中的 SQL INJECTION 風險。Scrawlr 使用了部分 HP WebInspect 相同的技術,但只檢測 SQL INJECTION 風險。Scrawlr 從一個起始 URL 入口,爬遍整個網站,並對站點中全部網頁進行分析以找到可能存在的漏洞。
這款被稱做 MSCASI 的工具能夠檢測 ASP 代碼並發現其中的 SQL INJECTION 漏洞(ASP 代碼以 SQL INJECTION 漏洞著稱),你須要向 MSCASI 提供原始代碼,MSCASI 會幫你找到存在風險的代碼位置。
該工具會讓 IIS 限制某些類型的 HTTP 請求,經過對特定 HTTP 請求進行限制,能夠防止某些有害的請求在服務器端執行。UrlScan 經過一系列關鍵詞發現惡意請求,並阻止惡意請求的執行。