安全|常見的Web攻擊手段之CSRF攻擊
對於常規的Web攻擊手段,如XSS、CRSF、SQL注入、(常規的不包括檔案上傳漏洞、DDoS攻擊)等,防範措施相對來說比較容易,對症下藥即可,比如XSS的防範需要轉義掉輸入的尖括號,防止CRSF攻擊需要將cookie設定為httponly,以及增加session相關的Hash token碼 ,SQL注入的防範需要將分號等字元轉義,等等做起來雖然筒單,但卻容易被忽視,更多的是需要從開發流程上來予以保障(這句話是給技術管理者的建議),以免因人為的疏忽而造成損失。
一、CSRF介紹
CSRF攻擊的全稱是跨站請求偽造( cross site request forgery),是一種對網站的惡意利用,儘管聽起來跟XSS跨站指令碼攻擊有點相似,但事實上CSRF與XSS差別很大,XSS利用的是站點內的信任使用者,而CSRF則是通過偽裝來自受信任使用者的請求來利用受信任的網站。你可以這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義向第三方網站傳送惡意請求。 CRSF能做的事情包括利用你的身份發郵件、發簡訊、進行交易轉賬等,甚至盜取你的賬號。
1.1、CRSF攻擊原理
CRSF攻擊原理- 首先使用者C瀏覽並登入了受信任站點A;
- 登入資訊驗證通過以後,站點A會在返回給瀏覽器的資訊中帶上已登入的cookie,cookie資訊會在瀏覽器端儲存一定時間(根據服務端設定而定);
- 完成這一步以後,使用者在沒有登出(清除站點A的cookie)站點A的情況下,訪問惡意站點B;
- 這時惡意站點 B的某個頁面向站點A發起請求,而這個請求會帶上瀏覽器端所儲存的站點A的cookie;
- 站點A根據請求所帶的cookie,判斷此請求為使用者C所傳送的。
因此,站點A會報據使用者C的許可權來處理惡意站點B所發起的請求,而這個請求可能以使用者C的身份傳送 郵件、簡訊、訊息,以及進行轉賬支付等操作,這樣惡意站點B就達到了偽造使用者C請求站點 A的目的。
受害者只需要做下面兩件事情,攻擊者就能夠完成CSRF攻擊:
- 登入受信任站點 A,並在本地生成cookie;
- 在不登出站點A(清除站點A的cookie)的情況下,訪問惡意站點B。
很多情況下所謂的惡意站點,很有可能是一個存在其他漏洞(如XSS)的受信任且被很多人訪問的站點,這樣,普通使用者可能在不知不覺中便成為了受害者。
1.2、攻擊舉例
假設某銀行網站A以GET請求來發起轉賬操作,轉賬的地址為www.xxx.com/transfer.do?accountNum=l000l&money=10000
,引數accountNum表示轉賬的賬戶,引數money表示轉賬金額。
而某大型論壇B上,一個惡意使用者上傳了一張圖片,而圖片的位址列中填的並不是圖片的地址,而是前而所說的磚賬地址:<img src="http://www.xxx.com/transfer.do?accountNum=l000l&money=10000">
當你登入網站A後,沒有及時登出,這時你訪問了論壇B,不幸的事情發生了,你會發現你的賬號裡面少了10000塊...
為什麼會這樣呢,在你登入銀行A時,你的瀏覽器端會生成銀行A的cookie,而當你訪問論壇B的時候,頁面上的<img>標籤需要瀏覽器發起一個新的HTTP請求,以獲得圖片資源,當瀏覽器發起請求時,請求的卻是銀行A的轉賬地址
www.xxx.com/transfer.do?accountNum=l000l&money=10000
,並且會帶上銀行A的cookie資訊,結果銀行的伺服器收到這個請求後,會以為是你發起的一次轉賬操作,因此你的賬號裡邊便少了10000塊。當然,絕大多數網站都不會使用GET請求來進行資料更新,因此,攻擊者也需要改變思路,與時俱進。
假設銀行將其轉賬方式改成POST提交,而論壇B恰好又存在一個XSS漏洞,惡意使用者在它的頁面上植入如下程式碼:
<form id="aaa" action="http://www.xxx.com/transfer.do" metdod="POST" display="none">
<input type="text" name="accountNum" value="10001"/>
<input type="text" name="money" value="10000"/>
</form>
<script>
var form = document.forms('aaa');
form.submit();
</script>
如果你此時恰好登入了銀行A,且沒有登出,當你開啟上述頁面後,指令碼會將表單aaa提交,把accountNum和money引數傳遞給銀行的轉賬地址http://www.xxx.com/transfer.do
,同樣的,銀行以為是你發起的一次轉賬會從你的賬戶中扣除10000塊。
當然,以上只是舉例,正常來說銀行的交易付款會有USB key、驗證碼、登入密碼和支付密碼等一系列屏障,流程比上述流程複雜得多,因此安全係數也高得多。
1.3、CSRF的防禦
1、儘量使用POST,限制GET
GET介面太容易被拿來做CSRF攻擊,看上面示例就知道,只要構造一個img標籤,而img標籤又是不能過濾的資料。介面最好限制為POST使用,GET則無效,降低攻擊風險。
當然POST並不是萬無一失,攻擊者只要構造一個form就可以,但需要在第三方頁面做,這樣就增加暴露的可能性。
2、將cookie設定為HttpOnly
CRSF攻擊很大程度上是利用了瀏覽器的cookie,為了防止站內的XSS漏洞盜取cookie,需要在cookie中設定“HttpOnly”屬性,這樣通過程式(如JavaScript指令碼、Applet等)就無法讀取到cookie資訊,避免了攻擊者偽造cookie的情況出現。
在Java的Servlet的API中設定cookie為HttpOnly的程式碼如下:
response.setHeader( "Set-Cookie", "cookiename=cookievalue;HttpOnly");
3、增加token
CSRF攻擊之所以能夠成功,是因為攻擊者可以偽造使用者的請求,該請求中所有的使用者驗證資訊都存在於cookie中,因此攻擊者可以在不知道使用者驗證資訊的情況下直接利用使用者的cookie來通過安全驗證。由此可知,抵禦CSRF攻擊的關鍵在於:在請求中放入攻擊者所不能偽造的資訊,並且該信總不存在於cookie之中。鑑於此,系統開發人員可以在HTTP請求中以引數的形式加入一個隨機產生的token,並在服務端進行token校驗,如果請求中沒有token或者token內容不正確,則認為是CSRF攻擊而拒絕該請求。
假設請求通過POST方式提交,則可以在相應的表單中增加一個隱藏域:
<input type="hidden" name="_toicen" value="tokenvalue"/>
token的值通過服務端生成,表單提交後token的值通過POST請求與引數一同帶到服務端,每次會話可以使用相同的token,會話過期,則token失效,攻擊者因無法獲取到token,也就無法偽造請求。
在session中新增token的實現程式碼:
HttpSession session = request.getSession();
Object token = session.getAttribute("_token");
if(token == null I I "".equals(token)) {
session.setAttribute("_token", UUID.randomUUIDO .toString());
}
4、通過Referer識別
根據HTTP協議,在HTTP頭中有一個欄位叫Referer,它記錄了該HTTP請求的來源地址。在通常情況下,訪問一個安全受限的頁面的請求都來自於同一個網站。比如某銀行的轉賬是通過使用者訪問http://www.xxx.com/transfer.do
頁面完成的,使用者必須先登入www.xxx.com
,然後通過單擊頁面上的提交按鈕來觸發轉賬事件。當用戶提交請求時,該轉賬請求的Referer值就會是
提交按鈕所在頁面的URL(本例為www.xxx. com/transfer.do)。如果攻擊者要對銀行網站實施CSRF攻擊,他只能在其他網站構造請求,當用戶通過其他網站傳送請求到銀行時,該請求的Referer的值是其他網站的地址,而不是銀行轉賬頁面的地址。因此,要防禦CSRF攻擊,銀行網站只需要對於每一個轉賬請求驗證其Referer值即可,如果是以www.xx.om
域名開頭的地址,則說明該請求是來自銀行網站自己的請求,是合法的;如果Referer是其他網站,就有可能是CSRF攻擊,則拒絕該請求。
取得HTTP請求Referer:
String referer = request.getHeader("Referer");
二、總結
CSRF攻擊是攻擊者利用使用者的身份操作使用者帳戶的一種攻擊方式,通常使用Anti CSRF Token來防禦CSRF攻擊,同時要注意Token的保密性和隨機性。
並且CSRF攻擊問題一般是由服務端解決。
注:文章大部分內容來源於《大型分散式網站架構 設計與實踐》一書。
作者:小怪聊職場
連結:https://www.jianshu.com/p/67408d73c66d
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。