SQL注入的原理解说,挺好!
原文地址:http://www.cnblogs.com/rush/archive/2011/12/31/2309203.html
1.1.1 總結(jié)
前幾天,國內(nèi)最大的程序猿社區(qū)CSDN網(wǎng)站的用戶數(shù)據(jù)庫的黑客公告。600登錄名和萬用戶password被公開泄露,隨后又有多家站點的用戶password被流傳于網(wǎng)絡(luò),連日來引發(fā)眾多網(wǎng)民對自己賬號、password等互聯(lián)網(wǎng)信息被盜取的普遍擔(dān)憂。
網(wǎng)絡(luò)安全成為了如今互聯(lián)網(wǎng)的焦點,這也恰恰觸動了每一位用戶的神經(jīng),因為設(shè)計的漏洞導(dǎo)致了不可收拾的惡果,驗證了一句話“出來混的,遲早是要還的”,所以我想通過專題博文介紹一些經(jīng)常使用的攻擊技術(shù)和防范策略。
SQL Injection或許非常多人都知道或者使用過,假設(shè)沒有了解或全然沒有聽過也沒有關(guān)系。由于接下來我們將介紹SQL Injection。
1.1.2 正文
SQL Injection:就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,終于達(dá)到欺騙server運行惡意的SQL命令。
詳細(xì)來說。它是利用現(xiàn)有應(yīng)用程序,將(惡意)的SQL命令注入到后臺數(shù)據(jù)庫引擎運行的能力。它能夠通過在Web表單中輸入(惡意)SQL語句得到一個存在安全漏洞的站點上的數(shù)據(jù)庫。而不是依照設(shè)計者意圖去運行SQL語句。
首先讓我們了解什么時候可能發(fā)生SQL Injection。
如果我們在瀏覽器中輸入URL www.sample.com,因為它僅僅是對頁面的簡單請求無需對數(shù)據(jù)庫動進(jìn)行動態(tài)請求。所以它不存在SQL Injection。當(dāng)我們輸入www.sample.com?testid=23時,我們在URL中傳遞變量testid,而且提供值為23。因為它是對數(shù)據(jù)庫進(jìn)行動態(tài)查詢的請求(當(dāng)中?testid=23表示數(shù)據(jù)庫查詢變量)。所以我們能夠該URL中嵌入惡意SQL語句。
如今我們知道SQL Injection適用場合。接下來我們將通過詳細(xì)的樣例來說明SQL Injection的應(yīng)用。這里我們以pubs數(shù)據(jù)庫作為樣例。
我們通過Web頁面查詢job表中的招聘信息,job表的設(shè)計例如以下:
圖1 jobs表
接著讓我們實現(xiàn)Web程序,它依據(jù)工作Id(job_id)來查詢對應(yīng)的招聘信息,示意代碼例如以下:
/// <summary> /// Handles the Load event of the Page control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> protected void Page_Load(object sender, EventArgs e) {if (!IsPostBack){// Gets departmentId from http request.string queryString = Request.QueryString["departmentID"];if (!string.IsNullOrEmpty(queryString)){// Gets data from database.gdvData.DataSource = GetData(queryString.Trim());// Binds data to gridview.gdvData.DataBind();}} }如今我們已經(jīng)完畢了Web程序。接下來讓我們查詢對應(yīng)招聘信息吧。
圖2 job表查詢結(jié)果
如圖所看到的。我們要查詢數(shù)據(jù)庫中工作Id值為1的工作信息,并且在頁面顯示了該工作的Id。Description,Min Lvl和Max Lvl等信息。
如今要求我們實現(xiàn)依據(jù)工作Id查詢對應(yīng)工作信息的功能,想必大家非常快能夠給出解決方式。SQL示意代碼例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE (job_id = 1)如果如今要求我們獲取Department表中的全部數(shù)據(jù)。并且必須保留WHERE語句,那我們僅僅要確保WHERE恒真就OK了。SQL示意代碼例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE (job_id = 1) OR 1 = 1上面我們使得WHERE恒真,所以該查詢中WHERE已經(jīng)不起作用了。其查詢結(jié)果等同于下面SQL語句。
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobsSQL查詢代碼實現(xiàn)例如以下:
string sql1 = string.Format("SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='{0}'", jobId);如今我們要通過頁面請求的方式,讓數(shù)據(jù)庫運行我們的SQL語句。我們要在URL中嵌入惡意表達(dá)式1=1(或2=2等等)。例如以下URL所看到的:
OR '1' = 1'
圖3 job表查詢結(jié)果
如今我們把job表中的全部數(shù)據(jù)都查詢出來了。只通過一個簡單的恒真表達(dá)式就能夠進(jìn)行了一次簡單的攻擊。
盡管我們把job表的數(shù)據(jù)都查詢出來了,但數(shù)據(jù)并沒有太大的價值。因為我們把該表暫時命名為job表。所以接著我們要找出該表真正表名。
首先我們?nèi)绻砻褪莏ob。然后輸入下面URL:
http://localhost:3452/ExcelUsingXSLT/Default.aspx?
jobid=1'or 1=(select count(*) from job)--
等效SQL語句例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='1'or 1=(select count(*) from job) --'圖4 job表查詢結(jié)果
當(dāng)我們輸入了以上URL后。結(jié)果server返回我們錯誤信息,這證明了我們的如果是錯誤的。那我們該感覺到挫敗嗎?不,事實上這里返回了非常多信息,首先它證明了該表名不是job,并且它還告訴我們后臺數(shù)據(jù)庫是SQL Server,不是MySQL或Oracle,這也設(shè)計一個漏洞把錯誤信息直接返回給了用戶。
接下假定表名是jobs。然后輸入下面URL:
http://localhost:3452/ExcelUsingXSLT/Default.aspx?
jobid=1'or1=(select count(*) from jobs) --
等效SQL語句例如以下:
SELECT job_id, job_desc, min_lvl, max_lvl FROM jobs WHERE job_id='1'or 1=(select count(*) from jobs) --'圖5 job表查詢結(jié)果
如今證明了該表名是jobs。這能夠邁向成功的一大步,因為我們知道了表名就能夠?qū)υ摫磉M(jìn)行增刪改操作了。并且我們還能夠推測出很多其它的表對它們作出改動,一旦改動成功那么這將是一場災(zāi)難。
如今大家已經(jīng)對SQL Injection的攻擊有了初步的了解了。接下讓我們學(xué)習(xí)怎樣防止SQL Injection。
總的來說有下面幾點:
1.永遠(yuǎn)不要信任用戶的輸入,要對用戶的輸入進(jìn)行校驗。能夠通過正則表達(dá)式,或限制長度,對單引號和雙"-"進(jìn)行轉(zhuǎn)換等。
2.永遠(yuǎn)不要使用動態(tài)拼裝SQL。能夠使用參數(shù)化的SQL或者直接使用存儲過程進(jìn)行數(shù)據(jù)查詢存取。
3.永遠(yuǎn)不要使用管理員權(quán)限的數(shù)據(jù)庫連接,為每一個應(yīng)用使用單獨的權(quán)限有限的數(shù)據(jù)庫連接。
4.不要把機密信息明文存放。請加密或者h(yuǎn)ash掉password和敏感的信息。
5.應(yīng)用的異常信息應(yīng)該給出盡可能少的提示,最好使用自己定義的錯誤信息對原始錯誤信息進(jìn)行包裝,把異常信息存放在獨立的表中。
通過正則表達(dá)校驗用戶輸入
首先我們能夠通過正則表達(dá)式校驗用戶輸入數(shù)據(jù)中是包括:對單引號和雙"-"進(jìn)行轉(zhuǎn)換等字符。
然后繼續(xù)校驗輸入數(shù)據(jù)中是否包括SQL語句的保留字。如:WHERE。EXEC,DROP等。
如今讓我們編寫正則表達(dá)式來校驗用戶的輸入吧。正則表達(dá)式定義例如以下:
private static readonly Regex RegSystemThreats =new Regex(@"\s?or\s*|\s?;\s?|\s?drop\s|\s?grant\s|^'|\s?--|\s?union\s|\s?delete\s|\s?truncate\s|"
+ @"\s?sysobjects\s?|\s?xp_.*?|\s?
syslogins\s?|\s?
sysremote\s?|\s?sysusers\s?|\s?
sysxlogins\s?
|\s?sysdatabases\s?|\s?aspnet_.*?|\s?exec\s?"
, RegexOptions.Compiled | RegexOptions.IgnoreCase);上面我們定義了一個正則表達(dá)式對象RegSystemThreats,而且給它傳遞了校驗用戶輸入的正則表達(dá)式。
因為我們已經(jīng)完畢了對用戶輸入校驗的正則表達(dá)式了,接下來就是通過該正則表達(dá)式來校驗用戶輸入是否合法了。因為.NET已經(jīng)幫我們實現(xiàn)了推斷字符串是否匹配正則表達(dá)式的方法——IsMatch(),所以我們這里僅僅需給傳遞要匹配的字符串就OK了。
示意代碼例如以下:
/// <summary> /// A helper method to attempt to discover [known] SqlInjection attacks. /// </summary> /// <param name="whereClause">string of the whereClause to check</param> /// <returns>true if found, false if not found </returns> public static bool DetectSqlInjection(string whereClause) {return RegSystemThreats.IsMatch(whereClause); }/// <summary> /// A helper method to attempt to discover [known] SqlInjection attacks. /// </summary> /// <param name="whereClause">string of the whereClause to check</param> /// <param name="orderBy">string of the orderBy clause to check</param> /// <returns>true if found, false if not found </returns> public static bool DetectSqlInjection(string whereClause, string orderBy) {return RegSystemThreats.IsMatch(whereClause) || RegSystemThreats.IsMatch(orderBy); }如今我們完畢了校驗用的正則表達(dá)式,接下來讓我們須要在頁面中加入校驗功能。
/// <summary> /// Handles the Load event of the Page control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> protected void Page_Load(object sender, EventArgs e) {if (!IsPostBack){// Gets departmentId from http request.string queryString = Request.QueryString["jobId"];if (!string.IsNullOrEmpty(queryString)){if (!DetectSqlInjection(queryString) && !DetectSqlInjection(queryString, queryString)){// Gets data from database.gdvData.DataSource = GetData(queryString.Trim());// Binds data to gridview.gdvData.DataBind();}else{throw new Exception("Please enter correct field");}}} }當(dāng)我們再次運行下面URL時。被嵌入的惡意語句被校驗出來了。從而在一定程度上防止了SQL Injection。
總結(jié)
以上是生活随笔為你收集整理的SQL注入的原理解说,挺好!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享web前端七款HTML5 Loadi
- 下一篇: 【差分+前缀和】BZOJ1637: [U