九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
實(shí)例講解 SQL 注入攻擊

一位客戶讓我們針對只有他們企業(yè)員工和顧客能使用的企業(yè)內(nèi)網(wǎng)進(jìn)行滲透測試。這是安全評估的一個(gè)部分,所以盡管我們之前沒有使用過SQL注入來滲透網(wǎng)絡(luò),但對其概念也相當(dāng)熟悉了。最后我們在這項(xiàng)任務(wù)中大獲成功,現(xiàn)在來回顧一下這個(gè)過程的每一步,將它記錄為一個(gè)案例。

 

“SQL注入”是一種利用未過濾/未審核用戶輸入的攻擊方法(“緩存溢出”和這個(gè)不同),意思就是讓應(yīng)用運(yùn)行本不應(yīng)該運(yùn)行的SQL代碼。如果應(yīng)用毫無防備地創(chuàng)建了SQL字符串并且運(yùn)行了它們,就會(huì)造成一些出人意料的結(jié)果。

 

我們記錄下了在多次錯(cuò)誤的轉(zhuǎn)折后經(jīng)歷的曲折過程,而一個(gè)更有經(jīng)驗(yàn)的人會(huì)有這不同的 — 甚至更好的 — 方法。但事實(shí)上我們成功以后才明白,我們并沒有完全被誤導(dǎo)。

其他的SQL文章包含了更多的細(xì)節(jié),但是這篇文章不僅展示了漏洞利用的過程,還講述了發(fā)現(xiàn)漏洞的原理。

 

目標(biāo)內(nèi)網(wǎng)

 

展現(xiàn)在我們眼前的是一個(gè)完整定制網(wǎng)站,我們之前沒見過這個(gè)網(wǎng)站,也無權(quán)查看它的源代碼:這是一次“黑盒”攻擊?!烫健Y(jié)果顯示這臺(tái)服務(wù)器運(yùn)行在微軟的IIS6上,并且是ASP.NET架構(gòu)。這就暗示我們數(shù)據(jù)庫是微軟的SQL server:我們相信我們的技巧可以應(yīng)用在任何web應(yīng)用上,無論它使用的是哪種SQL 服務(wù)器。

登陸頁有傳統(tǒng)的用戶-密碼表單,但多了一個(gè) “把我的密碼郵給我”的鏈接;后來,這個(gè)地方被證實(shí)是整個(gè)系統(tǒng)陷落的關(guān)鍵。

 

當(dāng)鍵入郵件地址時(shí),系統(tǒng)假定郵件存在,就會(huì)在用戶數(shù)據(jù)庫里查詢郵件地址,然后郵寄一些內(nèi)容給這個(gè)地址。但我的郵件地址無法找到,所以它什么也不會(huì)發(fā)給我。

 

對于任何SQL化的表單而言,第一步測試,是輸入一個(gè)帶有單引號(hào)的數(shù)據(jù):目的是看看他們是否對構(gòu)造SQL的字符串進(jìn)行了過濾。當(dāng)把單引號(hào)作為郵件地址提交以后,我們得到了500錯(cuò)誤(服務(wù)器錯(cuò)誤),這意味著“有害”輸入實(shí)際上是被直接用于SQL語句了。就是這了!

 

我猜測SQL代碼可能是這樣:

 

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE field = '$EMAIL';  
 

 

 $EMAIL 是用戶從表單提交的地址,并且這段查詢在字符串末端$EMAIL上提供了引號(hào)。我們不知道字段或表的確切名字,但是我們了解他們的本質(zhì),這有助于我們做正確的猜測。

 

 

當(dāng)我們鍵入steve@unixwiz.net‘ -注意這個(gè)末端的引號(hào) – 下面是這個(gè)SQL字段的構(gòu)成:

 

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE field = 'steve@unixwiz.net'';  
 

 

當(dāng)這段SQL開始執(zhí)行,SQL解析器就會(huì)發(fā)現(xiàn)多余的引號(hào)然后中斷執(zhí)行,并給出語法錯(cuò)誤的提示。這個(gè)錯(cuò)誤如何清楚的表述給用戶,基于應(yīng)用內(nèi)部的錯(cuò)誤恢復(fù)規(guī)程,但一般來說都不會(huì)提示“郵件地址不存在”。這個(gè)錯(cuò)誤響應(yīng)成了死亡之門,它告訴別人用戶輸入沒有被正確的處理,這就為應(yīng)用破解留下了可乘之機(jī)。

 

 

這個(gè)數(shù)據(jù)呈現(xiàn)在WHERE的從句中,讓我們以符合SQL規(guī)范的方式改變輸入試試,看看會(huì)發(fā)生什么。鍵入anything’ OR ‘x’=‘x, 結(jié)果如下:

 

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE field = 'anything' OR 'x'='x';  
 

 

因?yàn)閼?yīng)用不會(huì)思考輸入 – 僅僅構(gòu)造字符串 - 我們使用單引號(hào)把WHERE從句的單一組成變成了雙組成,’x'=‘x’從句是恒成立的,無論第一個(gè)從句是什么。(有一種更好的方式來確?!笆冀K為真”,我們隨后會(huì)接觸到)。

 

 

但與每次只返回單一數(shù)據(jù)的“真實(shí)”查詢不同,上面這個(gè)構(gòu)造必須返回這個(gè)成員數(shù)據(jù)庫的所有數(shù)據(jù)。要想知道在這種情況下應(yīng)用會(huì)做什么,唯一的方法就是嘗試,嘗試,再嘗試。我們得到了這個(gè):


你的登錄信息已經(jīng)被郵寄到了 random.person@example.com.


我們猜測這個(gè)地址是查詢到的第一條記錄。這個(gè)家伙真的會(huì)在這個(gè)郵箱里收到他忘記的密碼,想必他會(huì)很吃驚也會(huì)引起他的警覺。

 

我們現(xiàn)在知道可以根據(jù)自己的需要來篡改查詢語句了,盡管對于那些看不到的部分還不夠了解,但是我們注意到了在多次嘗試后得到了三條不同的響應(yīng):

 

  • “你的登錄信息已經(jīng)被郵寄到了郵箱”
  • “我們不能識(shí)別你的郵件地址”
  • 服務(wù)器錯(cuò)誤

前兩個(gè)響應(yīng)是有效的SQL,最后一個(gè)響應(yīng)是無效的SQL:當(dāng)猜測查詢語句結(jié)構(gòu)的時(shí)候,這種區(qū)別非常有用。

 

模式字段映射

 

第一步是猜測字段名:我們合理的推測了查詢包含“email address”和“password”,可能也會(huì)有“US Mail address”或者“userid”或“phone number”這樣的字段。我們特別想執(zhí)行 SHOW TABLE語句, 但我們并不知道表名,現(xiàn)在沒有比較明顯的辦法可以拿到表名。

 

我們進(jìn)行了下一步。在每次測試中,我們會(huì)用我們已知的部分加上一些特殊的構(gòu)造語句。我們已經(jīng)知道這個(gè)SQL的執(zhí)行結(jié)果是email地址的比對,因此我們來猜測email的字段名:

 

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE field = 'x' AND email IS NULL; --';  
 

 

目的是假定的查詢語句的字段名(email),來試試SQL是不是有效。我不關(guān)心匹配的郵件地址是啥(我們用了個(gè)偽名’x’),’——’這個(gè)符號(hào)表示SQL注釋的起始。對于去除應(yīng)用末尾提供的引號(hào),這是一個(gè)很有效的方式,我們不用在乎我們屏蔽掉的是啥。

 

 

如果我們得到了服務(wù)器錯(cuò)誤,意味著SQL有不恰當(dāng)?shù)牡胤剑⑶艺Z法錯(cuò)誤會(huì)被拋出:更有可能是字段名有錯(cuò)。如果我們得到了任何有效的響應(yīng),我們就可以猜測這個(gè)字段名是正確的。這就是我們得到“email unknown”或“password was sent”響應(yīng)的過程。

 

我們也可以用AND連接詞代替OR:這是有意義的。在SQL的模式映射階段,我們不需要為猜一個(gè)特定的郵件地址而煩惱,我們也不想應(yīng)用隨機(jī)的泛濫的給用戶發(fā)“這是你的密碼”的郵件 - 這不太好,有可能引起懷疑。而使用AND連接郵件地址,就會(huì)變的無效,我們就可以確保查詢語句總是返回0行,永遠(yuǎn)不會(huì)生成密碼提醒郵件。

提交上面的片段的確給了我們“郵件地址未知”的響應(yīng),現(xiàn)在我們知道郵件地址的確是存儲(chǔ)在email字段名里。如果沒有生效,我們可以嘗試email_address或mail這樣的字段名。這個(gè)過程需要相當(dāng)多的猜測。

 

接下來,我們猜測其他顯而易見的名字:password,user ID, name等等。每次只猜一個(gè)字段,只要響應(yīng)不是“server failure”,那就意味著我們猜對了。

 

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE email = 'x' AND userid IS NULL; --';  
 

 

在這個(gè)過程中,我們找到了幾個(gè)正確的字段名:

 

 

  • email
  • passwd
  • login_id
  • full_name

無疑還有更多(有一個(gè)線索是表單中的字段名),一陣挖掘后沒有發(fā)現(xiàn)更多了。但是我們依然不知道這些字段名的表名,它們在哪找到的?

 

尋找數(shù)據(jù)庫表名

 

應(yīng)用的內(nèi)建查詢指令已經(jīng)建立了表名,但是我們不知道是啥:有幾個(gè)方法可以找到表名。其中一個(gè)是依靠subselect(字查詢)。

 

一個(gè)獨(dú)立的查詢

 

Sql代碼
  1. SELECT COUNT(*) FROM tabname  
 

 

 返回表里記錄的數(shù)量,如果表名無效,查詢就會(huì)失敗。我們可以建立自己的字符串來探測表名:

 

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM table  
  3.  WHERE email = 'x' AND 1=(SELECT COUNT(*) FROM tabname); --';  
 

 

我們不關(guān)心到底有多少條記錄,只關(guān)心表名是不是正確。重復(fù)多次猜測以后,我們終于發(fā)現(xiàn)members是這個(gè)數(shù)據(jù)庫里的有效表名。但它是用在這個(gè)查詢里的么?所以我們需要另一個(gè)測試,使用table.field:實(shí)際查詢的部分只工作在這個(gè)表中,而不是只要表存在就執(zhí)行。

 

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x' AND members.email IS NULL; --';  
 

 

當(dāng)返回“Email unknown”時(shí),就意味著我們的SQL注入成功了,并且我們正確的猜測出了表名。這對后面的工作很重要,但是我們暫時(shí)先試試其他的方法。

找用戶賬號(hào)

 

我們對members表的結(jié)構(gòu)有了一個(gè)局部的概念,但是我們僅知道一個(gè)用戶名:任意用戶都可能得到“Here is your password”的郵件?;叵肫饋恚覀儚奈吹玫竭^信息本身,只有它發(fā)送的地址。我們得再弄幾個(gè)用戶名,這樣就能得到更多的數(shù)據(jù)。

 

首先,我們從公司網(wǎng)站開始找?guī)讉€(gè)人:“About us”或者“Contact”頁通常提供了公司成員列表。通常都包含郵件地址,即使它們沒有提供這個(gè)列表也沒關(guān)系,我們可以根據(jù)某些線索用我們的工具找到它們。

 

LIKE從句可以進(jìn)行用戶查詢,允許我們在數(shù)據(jù)庫里局部匹配用戶名或郵件地址,每次提交如果顯示“We sent your password”的信息并且郵件也真發(fā)了,就證明生效了。

 

警告:這么做拿到了郵件地址,但也真的發(fā)了郵件給對方,這有可能引起懷疑,小心使用。

 

我們可以查詢email name或者full name(或者推測出來的其他信息),每次放入%通配符進(jìn)行如下查詢:

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x' OR full_name LIKE '%Bob%';  

 

記住盡管可能不只有一個(gè)“Bob”,但我們只能看到一條信息:建議精煉LIKE從句。

 

密碼暴力破解

 

可以肯定的是,我們能在登陸頁進(jìn)行密碼的暴力破解,但是許多系統(tǒng)都針對此做了監(jiān)測甚至防御。可能有的手段有操作日志,賬號(hào)鎖定,或者其他能阻礙我們行動(dòng)的方式,但是因?yàn)榇嬖谖催^濾的輸入,我們就能繞過更多的保護(hù)措施。

 

我們在構(gòu)造的字符串里包含進(jìn)郵箱名和密碼來進(jìn)行密碼測試。在我們的例子中,我們用了受害者bob@example.com 并嘗試了多組密碼。

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x' OR full_name LIKE '%Bob%';  

 

這是一條很好使的SQL語句,我們不會(huì)得到服務(wù)器錯(cuò)誤的提示,只要我們得到“your password has been mailed to you”的提示信息,就證明我們已經(jīng)得到密碼了。這時(shí)候受害人可能會(huì)警覺起來,但誰關(guān)心他呢,我們已經(jīng)得到密碼了。

 

這個(gè)過程可以使用perl腳本自動(dòng)完成,然而,我們在寫腳本的過程中,發(fā)現(xiàn)了另一種方法來破解系統(tǒng)。

 

數(shù)據(jù)庫不是只讀的

 

迄今為止,我們沒做查詢數(shù)據(jù)庫之外的事,盡管SELECT是只讀的,但不代表SQL只能這樣。SQL使用分號(hào)表示結(jié)束,如果輸入沒有正確過濾,就沒有什么能阻止我們在字符串后構(gòu)造與查詢無關(guān)的指令。

 

The most drastic example is:

 

這劑猛藥是這樣的:

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x'; DROP TABLE members; --';  -- Boom!  

 

第一部分我們準(zhǔn)備了一個(gè)偽造的email地址——‘X’——我們不關(guān)心查詢結(jié)果返回什么:我們想要得到的只是我們自己構(gòu)造的SQL指令。這次攻擊刪除了整個(gè)members表,這就不太好玩了。

 

這表明我們不僅僅可以切分SQL指令,而且也可以修改數(shù)據(jù)庫。這是被允許的。

 

添加新用戶

 

我們已經(jīng)了解了members表的局部結(jié)構(gòu),添加一條新紀(jì)錄到表里視乎是一個(gè)可行的方法:如果這成功了,我們就能簡單的用我們新插入的身份登陸到系統(tǒng)了。

 

不要太驚訝,這條SQL有點(diǎn)長,我們把它分行顯示以便于理解,但它依然是一條語句:

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x';  
  4.         INSERT INTO members ('email','passwd','login_id','full_name')   
  5.         VALUES ('steve@unixwiz.net','hello','steve','Steve Friedl');--';  

 

即使我們得到了正確的字段名和表名,但在成功攻擊之前我們還有幾件事需要了解:

 

  1. 在web表單里,我們可能沒有足夠的空間鍵入這么多文本(盡管可以用腳本解決,但并不容易)。
  2. web應(yīng)用可能沒有members表的INSERT權(quán)限。
  3. 母庸置疑,members表里肯定還有其他字段,有一些可能需要初始值,否則會(huì)引起INSERT失敗。
  4. 即使我們插入了一條新紀(jì)錄,應(yīng)用也可能不正常運(yùn)行,因?yàn)槲覀儫o法提供值的字段名會(huì)自動(dòng)插入NULL。
  5. 一個(gè)正確的“member”可能額不僅僅只需要members表里的一條紀(jì)錄,而還要結(jié)合其他表的信息(如,訪問權(quán)限),因此只添加一個(gè)表可能不夠。

在這個(gè)案例里,我們遇到了問題#4或#5,我們無法確定到底是哪個(gè)—— 因?yàn)橛脴?gòu)造好的用戶名登陸進(jìn)去的時(shí)候,返回了服務(wù)器錯(cuò)誤的提示。盡管這就暗示了我們那些沒有構(gòu)造的字段是必須的,但我們沒有辦法正確處理。

 

一個(gè)可行的辦法是猜測其他字段,但這是一個(gè)勞力費(fèi)神的過程:盡管我們可以猜測其他“顯而易見”的字段,但要想得到整個(gè)應(yīng)用的組織結(jié)構(gòu)圖太難了。

 

我們最后嘗試了其他方式。

 

把密碼郵給我

 

我們意識(shí)到雖然我們無法添加新紀(jì)錄到members數(shù)據(jù)庫里,但我們可以修改已經(jīng)存在的,這被證明是可行的。

從上一步得知 bob@example.com 賬戶在這個(gè)系統(tǒng)里,我們用SQL注入把數(shù)據(jù)庫中的這條記錄改成我們自己的email地址:

Sql代碼
  1. SELECT email, passwd, login_id, full_name  
  2.   FROM members  
  3.  WHERE email = 'x';  
  4.       UPDATE members  
  5.       SET email = <a href="mailto:'steve@unixwiz.net">'steve@unixwiz.net</a>'  
  6.       WHERE email = <a href="mailto:'bob@example.com">'bob@example.com</a>';  

 

運(yùn)行之后,我們自然得到了“we didn’t know your email address”的提示,但這在預(yù)料之中,畢竟我們用了假的email地址。UPDATE操作不會(huì)通知應(yīng)用,因此它悄然執(zhí)行了。

 

之后,我們使用了“I lost my password”的功能,用我們剛剛更新的email地址,一分鐘后,我們收到了這封郵件:

Java代碼
  1. From: <a href="mailto:system@example.com">system@example.com</a>  
  2. To: <a href="mailto:steve@unixwiz.net">steve@unixwiz.net</a>  
  3. Subject: Intranet login  
  4. This email is in response to your request for your Intranet log in information.  
  5. Your User ID is: bob  
  6. Your password is: hello  

 

現(xiàn)在,我們要做的就是跟隨標(biāo)準(zhǔn)的登錄流程進(jìn)入系統(tǒng),這是一個(gè)高等級職員,有高級權(quán)限,比我們INSERT的用戶要好。

 

我們發(fā)現(xiàn)這個(gè)企業(yè)內(nèi)部站點(diǎn)內(nèi)容特別多,甚至包含了一個(gè)全用戶列表,我們可以合理的推出許多內(nèi)網(wǎng)都有同樣的企業(yè)Windows網(wǎng)絡(luò)賬號(hào),它們可能在所有地方都使用同樣的密碼。我們很容易就能得到任意的內(nèi)網(wǎng)密碼,并且我們找到了企業(yè)防火墻上的一個(gè)開放的PPTP協(xié)議的VPN端口,這讓登錄測試變得更簡單。

 

我們又挑了幾個(gè)賬號(hào)測試都沒有成功,我們無法知道是否是“密碼錯(cuò)誤”或者“企業(yè)內(nèi)部賬號(hào)是否與Windows賬號(hào)名不同”。但是我們覺得自動(dòng)化工具會(huì)讓這項(xiàng)工作更容易。

 

其他方法

 

在這次特定的滲透中,我們得到了足夠的權(quán)限,我們不需要更多了,但是還有其他方法。我們來試試我們現(xiàn)在想到的但不夠普遍的方法。

 

我們意識(shí)到不是所有的方法都與數(shù)據(jù)庫無關(guān),我們可以來試試。

 

調(diào)用xp_cmdshell

 

微軟的SQLServer支持存儲(chǔ)過程xp_cmdshell有權(quán)限執(zhí)行任意操作系統(tǒng)指令。如果這項(xiàng)功能允許web用戶使用,那webserver被滲透是無法避免的。

 

迄今為止,我們做的都被限制在了web應(yīng)用和數(shù)據(jù)庫這個(gè)環(huán)境下,但是如果我們能執(zhí)行任何操作系統(tǒng)指令,再厲害的服務(wù)器也禁不住滲透。xp_cmdshell通常只有極少數(shù)的管理員賬戶才能使用,但它也可能授權(quán)給了更低級的用戶。

 

繪制數(shù)據(jù)庫結(jié)構(gòu)

 

在這個(gè)登錄后提供了豐富功能應(yīng)用上,已經(jīng)沒必要做更深的挖掘了,但在其他限制更多的環(huán)境下可能還不夠。

能夠系統(tǒng)的繪制出數(shù)據(jù)庫可見結(jié)構(gòu),包含表和它們的字段結(jié)構(gòu),可能沒有直接幫助。但是這為網(wǎng)站滲透提供了一條林萌大道。

 

從網(wǎng)站的其他方面收集更多有關(guān)數(shù)據(jù)結(jié)構(gòu)的信息(例如,“留言板”頁?“幫助論壇”等?)。不過這對應(yīng)用環(huán)境依賴強(qiáng),而且還得靠你準(zhǔn)確的猜測。

 

減輕危害

 

我們認(rèn)為web應(yīng)用開發(fā)者通常沒考慮到“有害輸入”,但安全人員應(yīng)該考慮到(包括壞家伙),因此這有3條方法可以使用。

 

輸入過濾

 

過濾輸入是非常重要的事,以確保輸入不包含危險(xiǎn)代碼,無論是SQL服務(wù)器或HTM本身。首先想到的是剝掉“惡意字符”,像引號(hào)、分號(hào)或轉(zhuǎn)義符號(hào),但這是一種不太好的方式。盡管找到一些危險(xiǎn)字符很容易,但要把他們?nèi)页鰜砭碗y了。

 

web語言本身就充滿了特殊字符和奇怪的標(biāo)記(包括那些表達(dá)同樣字符的替代字符),所以想要努力識(shí)別出所有的“惡意字符”不太可能成功。

 

換言之,與其“移除已知的惡意數(shù)據(jù)”,不如移除“良好數(shù)據(jù)之外的所有數(shù)據(jù)”:這種區(qū)別是很重要的。在我們的例子中,郵件地址僅能包含如下字符:

Sql代碼
  1. abcdefghijklmnopqrstuvwxyz  
  2. ABCDEFGHIJKLMNOPQRSTUVWXYZ  
  3. 0123456789  
  4. @.-_+  

 

允許不正確的字符輸入是沒有任何好處的,應(yīng)該早點(diǎn)拒絕它們 - 可能會(huì)有一些錯(cuò)誤信息 – 不僅可以阻止SQL注入,也可以捕獲一些輸入錯(cuò)誤而不是把它們存入數(shù)據(jù)庫。

 

某個(gè)特殊的email地址會(huì)讓驗(yàn)證程序陷入麻煩,因?yàn)槊總€(gè)人對于“有效”的定義不同。由于email地址中出現(xiàn)了一個(gè)你沒有考慮到的字符而被拒絕,那真是糗大了。

 

真正的權(quán)威是RFC 2822(比RFC822內(nèi)容還多),它對于”允許使用的內(nèi)容“做了一個(gè)規(guī)范的定義。這種更學(xué)術(shù)的規(guī)范希望可以接受&和*(還有更多)作為有效的email地址,但其它人 - 包括作者 – 都樂于用一個(gè)合理的子集來包含更多的email地址。

 

那些采用更限制方法的人應(yīng)當(dāng)充分意識(shí)到?jīng)]有包含這些地址會(huì)帶來的后果,特別是限制有了更好的技術(shù)(預(yù)編譯/執(zhí)行,存儲(chǔ)過程)來避免這些“奇怪”的字符帶來的安全問題。

 

意識(shí)到“過濾輸入”并不意味著僅僅是“移除引號(hào)”,因?yàn)榧词挂粋€(gè)“正規(guī)”的字符也會(huì)帶來麻煩。在下面這個(gè)例子中,一個(gè)整型ID值被拿來和用戶的輸入作比較(數(shù)字型PIN):

Sql代碼
  1. SELECT fieldlist  
  2.   FROM table  
  3.  WHERE id = 23 OR 1=1;  -- Boom! Always matches!  

 

在實(shí)踐中,無論如何這個(gè)方法都有諸多限制,因?yàn)槟軌驈氐着懦形kU(xiǎn)字符的字段實(shí)在太少了。對于“日期”或者“email地址”或者“整型”,上面的辦法是有價(jià)值的,但對于真實(shí)的環(huán)境,我們不可避免地要使用其他方式

來減輕危害。

 

輸入項(xiàng)編碼/轉(zhuǎn)義

 

現(xiàn)在可以過濾電話號(hào)碼和郵件地址了,但你不能通過同樣的方法處理“name”字段,要不然可能會(huì)排除掉Bill O’Reilly這樣的名字:對于這個(gè)字段,這里的引號(hào)是合法的輸入。

 

有人就想到過濾到單引號(hào)的時(shí)候,再加上一個(gè)引號(hào),這樣就沒問題了 – 但是這么干要出事?。?/p>

 

預(yù)處理每個(gè)字符串來替換單引號(hào):

Sql代碼
  1. SELECT fieldlist  
  2.   FROM customers  
  3.  WHERE name = 'Bill O''Reilly';  -- works OK  

 

這個(gè)方法很容易出問題,因?yàn)榇蟛糠謹(jǐn)?shù)據(jù)庫都支持轉(zhuǎn)碼機(jī)制。像MySQL,允許輸入’來替代單引號(hào),因此如果輸入 ‘; DROP TABLE users; — 時(shí),通過兩次引號(hào)來“保護(hù)”數(shù)據(jù)庫,那我們將得到:

Sql代碼
  1. SELECT fieldlist  
  2.   FROM customers  
  3.  WHERE name = '\''; DROP TABLE users; --';  -- Boom!  

 

 ‘’’ 是一個(gè)完整的SQL語句(只包含一個(gè)引號(hào)),通常,惡意SQL代碼就會(huì)緊跟其后。不光是反斜線符號(hào)的情況:像Unicode編碼,其他的編碼或者解析規(guī)則都會(huì)無意中給程序員挖坑。完美的過濾的很困難的,這就是為什么許多的數(shù)據(jù)庫借口語言都提供函數(shù)給你使用。當(dāng)同樣的內(nèi)容給“string quoting”和“string parsing”處理過后,會(huì)好一些,也更安全一些。

比如MySQL的函數(shù)mysql_real_escape_string()和perl DBD 的 $dbh->quote($value)方法,這些方法都是必用的。

 

參數(shù)綁定 (預(yù)編譯語句)

 

盡管轉(zhuǎn)義是一個(gè)有用的機(jī)制,但我們?nèi)稳惶幱凇坝脩糨斎氡划?dāng)做SQL語句”這么一個(gè)循環(huán)里。更好的方法是:預(yù)編譯,本質(zhì)上所有的數(shù)據(jù)庫編程接口都支持預(yù)編譯。技術(shù)上來說,SQL聲明語句是用問號(hào)給每個(gè)參數(shù)占位創(chuàng)建的 – 然后在內(nèi)部表中進(jìn)行編譯。

 

預(yù)編譯查詢執(zhí)行時(shí)是按照參數(shù)列表來的:

 

Perl中的例子

Sql代碼
  1. $sth = $dbh->prepare("SELECT email, userid FROM members WHERE email = ?;");  
  2.    
  3. $sth->execute($email);  

 

感謝Stefan Wagner幫我寫了個(gè)java實(shí)現(xiàn):

 

不安全版

Sql代碼
  1. Statement s = connection.createStatement();  
  2. ResultSet rs = s.executeQuery("SELECT email FROM member WHERE name = "  
  3.                              + formField); // *boom*  

 

 安全版

Sql代碼
  1. PreparedStatement ps = connection.prepareStatement(  
  2.     "SELECT email FROM member WHERE name = ?");  
  3. ps.setString(1, formField);  
  4. ResultSet rs = ps.executeQuery();  

 

$email 是從用戶表單獲得的,它作為#1(第一個(gè)問號(hào)標(biāo)記的地方)位置的參數(shù)傳遞過來,在任何情況下這條SQL聲明都可以解析。引號(hào),分號(hào),反斜杠,SQL指令記號(hào) – 任何字符都不會(huì)產(chǎn)生特殊效果,因?yàn)樗鼈儭爸皇菙?shù)據(jù)”而已。這不會(huì)對其他東西造成破壞,因此這個(gè)應(yīng)用很大程度上防范了SQL注入攻擊。

 

如果預(yù)編譯查詢語句多次(只編譯一次)執(zhí)行,也會(huì)帶來性能上的提升,但是與大量安全方面的巨大提升相比,這顯得微不足道。這可能是我們保證web應(yīng)用安全最重要的一步。

 

限制數(shù)據(jù)庫權(quán)限和隔離用戶

 

在這個(gè)案例中,我們觀察到只有兩個(gè)交互動(dòng)作不在登錄用戶的上下文環(huán)境中:“登錄”和“發(fā)密碼給我”。web應(yīng)用應(yīng)該對數(shù)據(jù)庫連接做權(quán)限的限制:對于members表只能讀,并且無法操作其他表。

 

作用是即使一次“成功的”SQL注入攻擊也只能得到非常有限的成功。噢,我們將不能做有授權(quán)的UPDATE請求,我們要求 助于其他方法。

 

一旦web應(yīng)用確定登錄表單傳遞來的認(rèn)證是有效的,它就會(huì)切換會(huì)話到一個(gè)有更多權(quán)限的用戶上。

對任何web應(yīng)用而言,不使用sa權(quán)限幾乎是根本不用說的事。

 

對數(shù)據(jù)庫的訪問采用存儲(chǔ)過程

 

如果數(shù)據(jù)庫支持存儲(chǔ)過程,請使用存儲(chǔ)過程來執(zhí)行數(shù)據(jù)庫的訪問行為,這樣就不需要SQL了(假設(shè)存儲(chǔ)過程編程正確)。

 

把查詢,更新,刪除等動(dòng)作規(guī)則封裝成一個(gè)單獨(dú)的過程,就可以針對基礎(chǔ)規(guī)則和所執(zhí)行的商業(yè)規(guī)則來完成測試和歸檔(例如,如果客戶超過了信用卡限額,“添加新記錄”過程可能拒絕訂單)。

 

對于簡單的查詢這樣做可能僅僅能獲得很少的好處,不過一旦操作變復(fù)雜(或者被用在更多地方),給操作一個(gè)單獨(dú)的定義,功能將會(huì)變得更穩(wěn)健也更容易維護(hù)。

 

注意:動(dòng)態(tài)構(gòu)建一個(gè)查詢的存儲(chǔ)過程是可以做到的:這么做無法防止SQL注入 – 它只不過把預(yù)編譯/執(zhí)行綁定到了一起,或者是把SQL語句和提供保護(hù)的變量綁定到了一起。

 

隔離web服務(wù)器

 

實(shí)施了以上所有的防御措施,仍然可能有某些地方有遺漏,導(dǎo)致了服務(wù)器被滲透。設(shè)計(jì)者應(yīng)該在假定壞蛋已經(jīng)獲得了系統(tǒng)最高權(quán)限下來設(shè)計(jì)網(wǎng)絡(luò)設(shè)施,然后把它的攻擊對其他事情產(chǎn)生的影響限制在最小。

 

例如,把這臺(tái)機(jī)器放置在極度限制出入的DMZ網(wǎng)絡(luò)“內(nèi)部”,這么做意味著即便取得了web服務(wù)器的完全控制也不能自動(dòng)的獲得對其他一切的完全訪問權(quán)限。當(dāng)然,這么做不能阻止所有的入侵,不過它可以使入侵變的非常困難。

 

配置錯(cuò)誤報(bào)告

 

一些框架的錯(cuò)誤報(bào)告包含了開發(fā)的bug信息,這不應(yīng)該公開給用戶。想象一下:如果完整的查詢被現(xiàn)實(shí)出來了,并且指出了語法錯(cuò)誤點(diǎn),那要攻擊該有多容易。

 

對于開發(fā)者來說這些信息是有用的,但是它應(yīng)該禁止公開 – 如果可能 - 應(yīng)該限制在內(nèi)部用戶訪問。

 

注意:不是所有的數(shù)據(jù)庫都采用同樣的方式配置,并且不是所有的數(shù)據(jù)庫都支持同樣的SQL語法(“S”代表“結(jié)構(gòu)化”,不是“標(biāo)準(zhǔn)的”)。例如,大多數(shù)版本的MySQL都不支持子查詢,而且通常也不允許單行多條語句(multiple statements):當(dāng)你滲透網(wǎng)絡(luò)時(shí),實(shí)際上這些就是使問題復(fù)雜化的因素。


再強(qiáng)調(diào)一下,盡管我們選擇了“忘記密碼”鏈接來試試攻擊,但不是因?yàn)檫@個(gè)功能不安全。而是幾個(gè)易攻擊的點(diǎn)之一,不要把焦點(diǎn)聚集在“忘記密碼”上。

 

這個(gè)教學(xué)示例不準(zhǔn)備全面覆蓋SQL注入的內(nèi)容,甚至都不是一個(gè)教程:它僅僅是一篇我們花了幾小時(shí)做的滲透測試的記錄。我們看了其他的關(guān)于SQL注入文章的討論,但它們只給出了結(jié)果而沒有給出過程。

 

但是那些結(jié)果報(bào)告需要技術(shù)背景才能看懂,并且滲透細(xì)節(jié)也是有價(jià)值的。在沒有源代碼的情況下,滲透人員的黑盒測試能力也是有價(jià)值的。

 

感謝 David Litchfield 和 Randal Schwartz對本文的貢獻(xiàn),還有Chris Mospaw的排版(? 2005 by Chris Mospaw, used with permission).

 

其他資源

關(guān)于作者: zer0Black ( @lxtalx )

 

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
php防止SQL注入詳解及防范
SQL注入攻擊的種類和防范手段
如何進(jìn)行異構(gòu)數(shù)據(jù)庫同步(上篇)
再見,Navicat!
SQL Server數(shù)據(jù)庫設(shè)計(jì)規(guī)范(2)
SQL注入學(xué)習(xí)筆記
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服