轉(zhuǎn) web安全——CSRF漏洞原理和解決方案

轉(zhuǎn)自這里:http://blog.csdn.net/fengyinchao/article/details/50775121

1 匹涮、CSRF攻擊原理

CSRF攻擊原理比較簡單孵户,如圖1所示宵距。其中Web A為存在CSRF漏洞的網(wǎng)站,Web B為攻擊者構(gòu)建的惡意網(wǎng)站略荡,User C為Web A網(wǎng)站的合法用戶庵佣。

1. 用戶C打開瀏覽器,訪問受信任網(wǎng)站A汛兜,輸入用戶名和密碼請求登錄網(wǎng)站A巴粪;

2.在用戶信息通過驗證后,網(wǎng)站A產(chǎn)生Cookie信息并返回給瀏覽器,此時用戶登錄網(wǎng)站A成功肛根,可以正常發(fā)送請求到網(wǎng)站A辫塌;

3. 用戶未退出網(wǎng)站A之前,在同一瀏覽器中派哲,打開一個TAB頁訪問網(wǎng)站B臼氨;

4. 網(wǎng)站B接收到用戶請求后,返回一些攻擊性代碼芭届,并發(fā)出一個請求要求訪問第三方站點A储矩;

5. 瀏覽器在接收到這些攻擊性代碼后,根據(jù)網(wǎng)站B的請求褂乍,在用戶不知情的情況下攜帶Cookie信息椰苟,向網(wǎng)站A發(fā)出請求。網(wǎng)站A并不知道該請求其實是由B發(fā)起的树叽,所以會根據(jù)用戶C的Cookie信息以C的權(quán)限處理該請求舆蝴,導致來自網(wǎng)站B的惡意代碼被執(zhí)行。

2题诵、 CSRF漏洞防御

CSRF漏洞防御主要可以從三個層面進行洁仗,即服務(wù)端的防御、用戶端的防御和安全設(shè)備的防御性锭。

2.1 ? ? ?服務(wù)端的防御

2.1.1 ?驗證HTTP Referer字段

根據(jù)HTTP協(xié)議赠潦,在HTTP頭中有一個字段叫Referer,它記錄了該HTTP請求的來源地址草冈。在通常情況下她奥,訪問一個安全受限頁面的請求必須來自于同一個網(wǎng)站。比如某銀行的轉(zhuǎn)賬是通過用戶訪問http://bank.test/test?page=10&userID=101&money=10000頁面完成怎棱,用戶必須先登錄bank.test哩俭,然后通過點擊頁面上的按鈕來觸發(fā)轉(zhuǎn)賬事件。當用戶提交請求時拳恋,該轉(zhuǎn)賬請求的Referer值就會是轉(zhuǎn)賬按鈕所在頁面的URL(本例中凡资,通常是以bank. test域名開頭的地址)。而如果攻擊者要對銀行網(wǎng)站實施CSRF攻擊谬运,他只能在自己的網(wǎng)站構(gòu)造請求隙赁,當用戶通過攻擊者的網(wǎng)站發(fā)送請求到銀行時,該請求的Referer是指向攻擊者的網(wǎng)站梆暖。因此伞访,要防御CSRF攻擊,銀行網(wǎng)站只需要對于每一個轉(zhuǎn)賬請求驗證其Referer值轰驳,如果是以bank. test開頭的域名厚掷,則說明該請求是來自銀行網(wǎng)站自己的請求弟灼,是合法的。如果Referer是其他網(wǎng)站的話蝗肪,就有可能是CSRF攻擊,則拒絕該請求蠕趁。

2.1.2 在請求地址中添加token并驗證

CSRF攻擊之所以能夠成功薛闪,是因為攻擊者可以偽造用戶的請求,該請求中所有的用戶驗證信息都存在于Cookie中俺陋,因此攻擊者可以在不知道這些驗證信息的情況下直接利用用戶自己的Cookie來通過安全驗證豁延。由此可知,抵御CSRF攻擊的關(guān)鍵在于:在請求中放入攻擊者所不能偽造的信息腊状,并且該信息不存在于Cookie之中诱咏。鑒于此,系統(tǒng)開發(fā)者可以在HTTP請求中以參數(shù)的形式加入一個隨機產(chǎn)生的token缴挖,并在服務(wù)器端建立一個攔截器來驗證這個token袋狞,如果請求中沒有token或者token內(nèi)容不正確,則認為可能是CSRF攻擊而拒絕該請求映屋。

2.1.3 在HTTP頭中自定義屬性并驗證

自定義屬性的方法也是使用token并進行驗證苟鸯,和前一種方法不同的是,這里并不是把token以參數(shù)的形式置于HTTP請求之中棚点,而是把它放到HTTP頭中自定義的屬性里早处。通過XMLHttpRequest這個類,可以一次性給所有該類請求加上csrftoken這個HTTP頭屬性瘫析,并把token值放入其中砌梆。這樣解決了前一種方法在請求中加入token的不便,同時贬循,通過這個類請求的地址不會被記錄到瀏覽器的地址欄咸包,也不用擔心token會通過Referer泄露到其他網(wǎng)站。

3 其他防御方法

1. ?CSRF攻擊是有條件的杖虾,當用戶訪問惡意鏈接時诉儒,認證的cookie仍然有效,所以當用戶關(guān)閉頁面時要及時清除認證cookie亏掀,對支持TAB模式(新標簽打開網(wǎng)頁)的瀏覽器尤為重要忱反。

2. ?盡量少用或不要用request()類變量,獲取參數(shù)指定request.form()還是request. querystring ()滤愕,這樣有利于阻止CSRF漏洞攻擊温算,此方法只不能完全防御CSRF攻擊,只是一定程度上增加了攻擊的難度间影。

Java代碼示例

下文將以 Java 為例注竿,對上述三種方法分別用代碼進行示例。無論使用何種方法,在服務(wù)器端的攔截器必不可少巩割,它將負責檢查到來的請求是否符合要求裙顽,然后視結(jié)果而決定是否繼續(xù)請求或者丟棄。在 Java 中宣谈,攔截器是由 Filter 來實現(xiàn)的愈犹。我們可以編寫一個 Filter,并在 web.xml 中對其進行配置闻丑,使其對于訪問所有需要 CSRF 保護的資源的請求進行攔截漩怎。

在 filter 中對請求的 Referer 驗證代碼如下

清單 1. 在 Filter 中驗證 Referer

?// 從 HTTP 頭中取得 Referer 值

?String referer=request.getHeader("Referer");

?// 判斷 Referer 是否以 bank.example 開頭

?if((referer!=null) &&(referer.trim().startsWith(“bank.example”))){

? ? chain.doFilter(request, response);

?}else{

request.getRequestDispatcher(“error.jsp”).forward(request,response);

?}?

以上代碼先取得 Referer 值,然后進行判斷嗦嗡,當其非空并以 bank.example 開頭時勋锤,則繼續(xù)請求,否則的話可能是 CSRF 攻擊侥祭,轉(zhuǎn)到 error.jsp 頁面叁执。

如果要進一步驗證請求中的 token 值,代碼如下

清單 2. 在 filter 中驗證請求中的 token

HttpServletRequest req = (HttpServletRequest)request;

?HttpSession s = req.getSession();

?// 從 session 中得到 csrftoken 屬性

?String sToken = (String)s.getAttribute(“csrftoken”);

?if(sToken == null){

? ? // 產(chǎn)生新的 token 放入 session 中

? ? sToken = generateToken();

? ? s.setAttribute(“csrftoken”,sToken);

? ? chain.doFilter(request, response);

?} else{

? ? // 從 HTTP 頭中取得 csrftoken

? ? String xhrToken = req.getHeader(“csrftoken”);

? ? // 從請求參數(shù)中取得 csrftoken

? ? String pToken = req.getParameter(“csrftoken”);

? ? if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){

? ? ? ? chain.doFilter(request, response);

? ? }else if(sToken != null && pToken != null && sToken.equals(pToken)){

? ? ? ? chain.doFilter(request, response);

? ? }else{

request.getRequestDispatcher(“error.jsp”).forward(request,response);

? ? }

?}?

首先判斷 session 中有沒有 csrftoken矮冬,如果沒有徒恋,則認為是第一次訪問,session 是新建立的欢伏,這時生成一個新的 token入挣,放于 session 之中,并繼續(xù)執(zhí)行請求硝拧。如果 session 中已經(jīng)有 csrftoken径筏,則說明用戶已經(jīng)與服務(wù)器之間建立了一個活躍的 session,這時要看這個請求中有沒有同時附帶這個 token障陶,由于請求可能來自于常規(guī)的訪問或是 XMLHttpRequest 異步訪問滋恬,我們分別嘗試從請求中獲取 csrftoken 參數(shù)以及從 HTTP 頭中獲取 csrftoken 自定義屬性并與 session 中的值進行比較,只要有一個地方帶有有效 token抱究,就判定請求合法恢氯,可以繼續(xù)執(zhí)行,否則就轉(zhuǎn)到錯誤頁面鼓寺。生成 token 有很多種方法勋拟,任何的隨機算法都可以使用,Java 的 UUID 類也是一個不錯的選擇妈候。

除了在服務(wù)器端利用 filter 來驗證 token 的值以外敢靡,我們還需要在客戶端給每個請求附加上這個 token,這是利用 js 來給 html 中的鏈接和表單請求地址附加 csrftoken 代碼苦银,其中已定義 token 為全局變量啸胧,其值可以從 session 中得到赶站。

清單 3. 在客戶端對于請求附加 token

function appendToken(){

? ? updateForms();

? ? updateTags();

?}

?function updateForms() {

? ? // 得到頁面中所有的 form 元素

? ? var forms = document.getElementsByTagName('form');

? ? for(i=0; i

? ? ? ? var url = forms[i].action;

? ? ? ? // 如果這個 form 的 action 值為空,則不附加 csrftoken

? ? ? ? if(url == null || url == "" ) continue;

? ? ? ? // 動態(tài)生成 input 元素纺念,加入到 form 之后

? ? ? ? var e = document.createElement("input");

? ? ? ? e.name = "csrftoken";

? ? ? ? e.value = token;

? ? ? ? e.type="hidden";

? ? ? ? forms[i].appendChild(e);

? ? }

?}

?function updateTags() {

? ? var all = document.getElementsByTagName('a');

? ? var len = all.length;

? ? // 遍歷所有 a 元素

? ? for(var i=0; i

? ? ? ? var e = all[i];

? ? ? ? updateTag(e, 'href', token);

? ? }

?}

?function updateTag(element, attr, token) {

? ? var location = element.getAttribute(attr);

? ? if(location != null && location != '' '' ) {

? ? ? ? var fragmentIndex = location.indexOf('#');

? ? ? ? var fragment = null;

? ? ? ? if(fragmentIndex != -1){

? ? ? ? ? ? //url 中含有只相當頁的錨標記

? ? ? ? ? ? fragment = location.substring(fragmentIndex);

? ? ? ? ? ? location = location.substring(0,fragmentIndex);

? ? ? ? }


? ? ? ? var index = location.indexOf('?');

? ? ? ? if(index != -1) {

? ? ? ? ? ? //url 中已含有其他參數(shù)

? ? ? ? ? ? location = location + '&csrftoken=' + token;

? ? ? ? } else {

? ? ? ? ? ? //url 中沒有其他參數(shù)

? ? ? ? ? ? location = location + '?csrftoken=' + token;

? ? ? ? }

? ? ? ? if(fragment != null){

? ? ? ? ? ? location += fragment;

? ? ? ? }

? ? ? ? element.setAttribute(attr, location);

? ? }

?}?

在客戶端 html 中贝椿,主要是有兩個地方需要加上 token,一個是表單 form陷谱,另一個就是鏈接 a烙博。這段代碼首先遍歷所有的 form,在 form 最后添加一隱藏字段叭首,把 csrftoken 放入其中习勤。然后踪栋,代碼遍歷所有的鏈接標記 a焙格,在其 href 屬性中加入 csrftoken 參數(shù)。注意對于 a.href 來說夷都,可能該屬性已經(jīng)有參數(shù)眷唉,或者有錨標記。因此需要分情況討論囤官,以不同的格式把 csrftoken 加入其中冬阳。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市党饮,隨后出現(xiàn)的幾起案子肝陪,更是在濱河造成了極大的恐慌,老刑警劉巖刑顺,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氯窍,死亡現(xiàn)場離奇詭異,居然都是意外死亡蹲堂,警方通過查閱死者的電腦和手機狼讨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柒竞,“玉大人政供,你說我怎么就攤上這事⌒嗷” “怎么了布隔?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長稼虎。 經(jīng)常有香客問我执泰,道長,這世上最難降的妖魔是什么渡蜻? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任术吝,我火速辦了婚禮计济,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘排苍。我一直安慰自己沦寂,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布淘衙。 她就那樣靜靜地躺著传藏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彤守。 梳的紋絲不亂的頭發(fā)上毯侦,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音具垫,去河邊找鬼侈离。 笑死,一個胖子當著我的面吹牛筝蚕,可吹牛的內(nèi)容都是我干的卦碾。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼起宽,長吁一口氣:“原來是場噩夢啊……” “哼洲胖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起坯沪,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤绿映,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后腐晾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叉弦,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年赴魁,在試婚紗的時候發(fā)現(xiàn)自己被綠了卸奉。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡颖御,死狀恐怖榄棵,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情潘拱,我是刑警寧澤疹鳄,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站芦岂,受9級特大地震影響瘪弓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜禽最,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一腺怯、第九天 我趴在偏房一處隱蔽的房頂上張望袱饭。 院中可真熱鬧,春花似錦呛占、人聲如沸虑乖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疹味。三九已至,卻和暖如春帜篇,著一層夾襖步出監(jiān)牢的瞬間糙捺,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工笙隙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留洪灯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓逃沿,卻偏偏與公主長得像婴渡,于是被迫代替她去往敵國和親幻锁。 傳聞我的和親對象是個殘疾皇子凯亮,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容