成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

跨站請(qǐng)求偽造CSRF防護(hù)方法

安全 應(yīng)用安全
CSRF(Cross-site request forgery跨站請(qǐng)求偽造,也被稱成為“one click attack”或者session riding,通??s寫為CSRF或者XSRF,是一種對(duì)網(wǎng)站的惡意利用。

CSRF(Cross-site request forgery跨站請(qǐng)求偽造,也被稱成為“one click attack”或者session riding,通??s寫為CSRF或者XSRF,是一種對(duì)網(wǎng)站的惡意利用。 

一、CSRF攻擊原理

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

 

跨站請(qǐng)求偽造CSRF防護(hù)方法

圖1 CSRF攻擊原理

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

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

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

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

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

二、CSRF漏洞防御

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

1、 服務(wù)端的防御

.1.1 驗(yàn)證HTTP Referer字段

根據(jù)HTTP協(xié)議,在HTTP頭中有一個(gè)字段叫Referer,它記錄了該HTTP請(qǐng)求的來源地址。在通常情況下,訪問一個(gè)安全受限頁(yè)面的請(qǐng)求必須來自于同一個(gè)網(wǎng)站。比如某銀行的轉(zhuǎn)賬是通過用戶訪問http://bank.test/test?page=10&userID=101&money=10000頁(yè)面完成,用戶必須先登錄bank.test,然后通過點(diǎn)擊頁(yè)面上的按鈕來觸發(fā)轉(zhuǎn)賬事件。當(dāng)用戶提交請(qǐng)求時(shí),該轉(zhuǎn)賬請(qǐng)求的Referer值就會(huì)是轉(zhuǎn)賬按鈕所在頁(yè)面的URL(本例中,通常是以bank. test域名開頭的地址)。而如果攻擊者要對(duì)銀行網(wǎng)站實(shí)施CSRF攻擊,他只能在自己的網(wǎng)站構(gòu)造請(qǐng)求,當(dāng)用戶通過攻擊者的網(wǎng)站發(fā)送請(qǐng)求到銀行時(shí),該請(qǐng)求的Referer是指向攻擊者的網(wǎng)站。因此,要防御CSRF攻擊,銀行網(wǎng)站只需要對(duì)于每一個(gè)轉(zhuǎn)賬請(qǐng)求驗(yàn)證其Referer值,如果是以bank. test開頭的域名,則說明該請(qǐng)求是來自銀行網(wǎng)站自己的請(qǐng)求,是合法的。如果Referer是其他網(wǎng)站的話,就有可能是CSRF攻擊,則拒絕該請(qǐng)求。

1.2 在請(qǐng)求地址中添加token并驗(yàn)證

CSRF攻擊之所以能夠成功,是因?yàn)楣粽呖梢詡卧煊脩舻恼?qǐng)求,該請(qǐng)求中所有的用戶驗(yàn)證信息都存在于Cookie中,因此攻擊者可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的Cookie來通過安全驗(yàn)證。由此可知,抵御CSRF攻擊的關(guān)鍵在于:在請(qǐng)求中放入攻擊者所不能偽造的信息,并且該信息不存在于Cookie之中。鑒于此,系統(tǒng)開發(fā)者可以在HTTP請(qǐng)求中以參數(shù)的形式加入一個(gè)隨機(jī)產(chǎn)生的token,并在服務(wù)器端建立一個(gè)攔截器來驗(yàn)證這個(gè)token,如果請(qǐng)求中沒有token或者token內(nèi)容不正確,則認(rèn)為可能是CSRF攻擊而拒絕該請(qǐng)求。

1.3 在HTTP頭中自定義屬性并驗(yàn)證

自定義屬性的方法也是使用token并進(jìn)行驗(yàn)證,和前一種方法不同的是,這里并不是把token以參數(shù)的形式置于HTTP請(qǐng)求之中,而是把它放到HTTP頭中自定義的屬性里。通過XMLHttpRequest這個(gè)類,可以一次性給所有該類請(qǐng)求加上csrftoken這個(gè)HTTP頭屬性,并把token值放入其中。這樣解決了前一種方法在請(qǐng)求中加入token的不便,同時(shí),通過這個(gè)類請(qǐng)求的地址不會(huì)被記錄到瀏覽器的地址欄,也不用擔(dān)心token會(huì)通過Referer泄露到其他網(wǎng)站。

2、 其他防御方法

1. CSRF攻擊是有條件的,當(dāng)用戶訪問惡意鏈接時(shí),認(rèn)證的cookie仍然有效,所以當(dāng)用戶關(guān)閉頁(yè)面時(shí)要及時(shí)清除認(rèn)證cookie,對(duì)支持TAB模式(新標(biāo)簽打開網(wǎng)頁(yè))的瀏覽器尤為重要。

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

代碼示例:

Java 代碼示例

下文將以 Java 為例,對(duì)上述三種方法分別用代碼進(jìn)行示例。無論使用何種方法,在服務(wù)器端的攔截器必不可少,它將負(fù)責(zé)檢查到來的請(qǐng)求是否符合要求,然后視結(jié)果而決定是否繼續(xù)請(qǐng)求或者丟棄。在 Java 中,攔截器是由 Filter 來實(shí)現(xiàn)的。我們可以編寫一個(gè) Filter,并在 web.xml 中對(duì)其進(jìn)行配置,使其對(duì)于訪問所有需要 CSRF 保護(hù)的資源的請(qǐng)求進(jìn)行攔截。

在 filter 中對(duì)請(qǐng)求的 Referer 驗(yàn)證代碼如下

清單 1. 在 Filter 中驗(yàn)證 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 值,然后進(jìn)行判斷,當(dāng)其非空并以 bank.example 開頭時(shí),則繼續(xù)請(qǐng)求,否則的話可能是 CSRF 攻擊,轉(zhuǎn)到 error.jsp 頁(yè)面。

如果要進(jìn)一步驗(yàn)證請(qǐng)求中的 token 值,代碼如下

清單 2. 在 filter 中驗(yàn)證請(qǐng)求中的 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”);
    // 從請(qǐng)求參數(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,如果沒有,則認(rèn)為是第一次訪問,session 是新建立的,這時(shí)生成一個(gè)新的 token,放于 session 之中,并繼續(xù)執(zhí)行請(qǐng)求。如果 session 中已經(jīng)有 csrftoken,則說明用戶已經(jīng)與服務(wù)器之間建立了一個(gè)活躍的 session,這時(shí)要看這個(gè)請(qǐng)求中有沒有同時(shí)附帶這個(gè) token,由于請(qǐng)求可能來自于常規(guī)的訪問或是 XMLHttpRequest 異步訪問,我們分別嘗試從請(qǐng)求中獲取 csrftoken 參數(shù)以及從 HTTP 頭中獲取 csrftoken 自定義屬性并與 session 中的值進(jìn)行比較,只要有一個(gè)地方帶有有效 token,就判定請(qǐng)求合法,可以繼續(xù)執(zhí)行,否則就轉(zhuǎn)到錯(cuò)誤頁(yè)面。生成 token 有很多種方法,任何的隨機(jī)算法都可以使用,Java 的 UUID 類也是一個(gè)不錯(cuò)的選擇。

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

清單 3. 在客戶端對(duì)于請(qǐng)求附加 token

function appendToken(){
    updateForms();
    updateTags();
 }

 function updateForms() {
    // 得到頁(yè)面中所有的 form 元素
    var forms = document.getElementsByTagName('form');
    for(i=0; i<forms.length; i++) {
        var url = forms[i].action;
        // 如果這個(gè) form 的 action 值為空,則不附加 csrftoken
        if(url == null || url == "" ) continue;
        // 動(dòng)態(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<len; 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 中含有只相當(dāng)頁(yè)的錨標(biāo)記
            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 中,主要是有兩個(gè)地方需要加上 token,一個(gè)是表單 form,另一個(gè)就是鏈接 a。這段代碼首先遍歷所有的 form,在 form 最后添加一隱藏字段,把 csrftoken 放入其中。然后,代碼遍歷所有的鏈接標(biāo)記 a,在其 href 屬性中加入 csrftoken 參數(shù)。注意對(duì)于 a.href 來說,可能該屬性已經(jīng)有參數(shù),或者有錨標(biāo)記。因此需要分情況討論,以不同的格式把 csrftoken 加入其中。

如果你的網(wǎng)站使用 XMLHttpRequest,那么還需要在 HTTP 頭中自定義 csrftoken 屬性,利用 dojo.xhr 給 XMLHttpRequest 加上自定義屬性代碼如下:

清單 4. 在 HTTP 頭中自定義屬性

var plainXhr = dojo.xhr;// 重寫 dojo.xhr 方法
 dojo.xhr = function(method,args,hasBody) {
    // 確保 header 對(duì)象存在
    args.headers = args.header || {};
    tokenValue = '<%=request.getSession(false).getAttribute("csrftoken")%>';
    var token = dojo.getObject("tokenValue");
    // 把 csrftoken 屬性放到頭中
    args.headers["csrftoken"] = (token) ? token : "  ";
    return plainXhr(method,args,hasBody);
 }; 

這里改寫了 dojo.xhr 的方法,首先確保 dojo.xhr 中存在 HTTP 頭,然后在 args.headers 中添加 csrftoken 字段,并把 token 值從 session 里拿出放入字段中。

PHP代碼示例:

請(qǐng)看下面一個(gè)簡(jiǎn)單的應(yīng)用,它允許用戶購(gòu)買鋼筆或鉛筆。界面上包含下面的表單:

<form action="buy.php" method="POST">
  <p>
  Item:
  <select name="item">
    <option name="pen">pen</option>
    <option name="pencil">pencil</option>
  </select><br />
  Quantity: <input type="text" name="quantity" /><br />
  <input type="submit" value="Buy" />
  </p></form> 

下面的buy.php程序處理表單的提交信息:

<?php
  session_start();
  $clean = array();
  if (isset($_REQUEST['item'] && isset($_REQUEST['quantity']))
  {
    /* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */
    if (buy_item($clean['item'], $clean['quantity']))
    {
      echo '<p>Thanks for your purchase.</p>';
    }
    else
    {
      echo '<p>There was a problem with your order.</p>';
    }
  }?> 

攻擊者會(huì)首先使用這個(gè)表單來觀察它的動(dòng)作。例如,在購(gòu)買了一支鉛筆后,攻擊者知道了在購(gòu)買成功后會(huì)出現(xiàn)感謝信息。注意到這一點(diǎn)后,攻擊者會(huì)嘗試通過訪問下面的URL以用GET方式提交數(shù)據(jù)是否能達(dá)到同樣的目的:

http://store.example.org/buy.php?item=pen&quantity=1

如果能成功的話,攻擊者現(xiàn)在就取得了當(dāng)合法用戶訪問時(shí),可以引發(fā)購(gòu)買的URL格式。在這種情況下,進(jìn)行跨站請(qǐng)求偽造攻擊非常容易,因?yàn)楣粽咧灰l(fā)受害者訪問該URL即可。

請(qǐng)看下面對(duì)前例應(yīng)用更改后的代碼:

php
  session_start();
  $token = md5(uniqid(rand(), TRUE));
  $_SESSION['token'] = $token;
  $_SESSION['token_time'] = time();?> 

表單:

<form action="buy.php" method="POST">
  <input type="hidden" name="token" value="<?php echo $token; ?>" />
  <p>
  Item:
  <select name="item">
    <option name="pen">pen</option>
    <option name="pencil">pencil</option>
  </select><br />
  Quantity: <input type="text" name="quantity" /><br />
  <input type="submit" value="Buy" />
  </p></form> 

通過這些簡(jiǎn)單的修改,一個(gè)跨站請(qǐng)求偽造攻擊就必須包括一個(gè)合法的驗(yàn)證碼以完全模仿表單提交。由于驗(yàn)證碼的保存在用戶的session中的,攻擊者必須對(duì)每個(gè)受害者使用不同的驗(yàn)證碼。這樣就有效的限制了對(duì)一個(gè)用戶的任何攻擊,它要求攻擊者獲取另外一個(gè)用戶的合法驗(yàn)證碼。使用你自己的驗(yàn)證碼來偽造另外一個(gè)用戶的請(qǐng)求是無效的。

該驗(yàn)證碼可以簡(jiǎn)單地通過一個(gè)條件表達(dá)式來進(jìn)行檢查:

<?php
  if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token'])
  {
    /* Valid Token */
  }?> 

你還能對(duì)驗(yàn)證碼加上一個(gè)有效時(shí)間限制,如5分鐘:

<?php
  $token_age = time() - $_SESSION['token_time'];
  if ($token_age <= 300)
  {
    /* Less than five minutes has passed. */
  }?> 

通過在你的表單中包括驗(yàn)證碼,你事實(shí)上已經(jīng)消除了跨站請(qǐng)求偽造攻擊的風(fēng)險(xiǎn)??梢栽谌魏涡枰獔?zhí)行操作的任何表單中使用這個(gè)流程。 

責(zé)任編輯:藍(lán)雨淚 來源: FreebuF
相關(guān)推薦

2011-04-19 13:40:27

2013-05-22 18:32:57

2017-11-02 15:28:52

2017-11-02 14:39:54

2012-12-10 10:32:22

2010-09-27 17:37:10

2015-09-15 10:52:52

2013-04-24 15:56:40

2023-01-15 17:50:39

2021-12-09 09:51:30

插件安全工具lazyCSRF

2012-04-12 15:27:44

2011-05-10 09:55:14

2016-09-30 15:59:41

2013-01-17 09:39:17

2013-07-03 11:28:47

2021-07-13 15:21:19

MozillaFirefox 90攻擊

2021-06-03 10:16:12

CSRF攻擊SpringBoot

2013-01-04 13:54:49

2015-12-03 17:41:07

2009-03-09 17:19:53

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产在线中文字幕 | 97超碰免费 | 国产美女在线精品免费 | 美女久久 | 成人不卡视频 | 精品在线观看一区 | 久久久久久久久久久久久九 | 日韩视频精品在线 | 伊人久久综合 | 九九色综合 | 日韩成人免费视频 | 久久久久久久久久一区 | 亚洲在线一区 | 日韩高清国产一区在线 | 亚洲综合无码一区二区 | 成人精品鲁一区一区二区 | 国产黄色网址在线观看 | 激情五月婷婷丁香 | 午夜电影合集 | 亚洲成人福利在线观看 | av黄色片在线观看 | 亚洲视频精品在线 | 亚洲国产一区二区视频 | 欧美久久久久久久 | 欧美综合一区二区三区 | 国产日韩欧美 | 五月激情婷婷在线 | 午夜精品一区 | 国产精品欧美一区二区三区不卡 | 日韩中文在线观看 | 97超碰在线播放 | 亚洲欧美成人在线 | 国产成人精品午夜 | 中文字幕一区在线观看视频 | 欧美一区二区视频 | 国产精品一区二区无线 | 欧美中文字幕在线观看 | 国产亚洲一区二区三区在线观看 | 一级片在线观看视频 | 亚洲成人免费 | 黄网站在线播放 |