CSRF攻擊與防御

一、CSRF 背景與介紹

CSRF(Cross Site Request Forgery, 跨站域請求偽造)是一種網(wǎng)絡(luò)的攻擊方式,它在 2007 年曾被列為互聯(lián)網(wǎng) 20 大安全隱患之一堤撵。其他安全隱患毅待,比如 SQL 腳本注入饱溢,跨站域腳本攻擊等在近年來已經(jīng)逐漸為眾人熟知庭猩,很多網(wǎng)站也都針對他們進(jìn)行了防御。然而掂骏,對于大多數(shù)人來說轰驳,CSRF 卻依然是一個(gè)陌生的概念。即便是大名鼎鼎的 Gmail, 在 2007 年底也存在著 CSRF 漏洞弟灼,從而被黑客攻擊而使 Gmail 的用戶造成巨大的損失。

二冒黑、攻擊原理

2.1 攻擊原理

下面為CSRF攻擊原理圖:

CSRF攻擊原理

由上圖分析我們可以知道構(gòu)成CSRF攻擊是有條件的:

  • 客戶端必須一個(gè)網(wǎng)站并生成cookie憑證存儲在瀏覽器中
  • 該cookie沒有清除田绑,客戶端又tab一個(gè)頁面進(jìn)行訪問別的網(wǎng)站
2.2 攻擊實(shí)例

CSRF 攻擊可以在受害者毫不知情的情況下以受害者名義偽造請求發(fā)送給受攻擊站點(diǎn),從而在并未授權(quán)的情況下執(zhí)行在權(quán)限保護(hù)之下的操作抡爹。比如說掩驱,受害者 Bob 在銀行有一筆存款,通過對銀行的網(wǎng)站發(fā)送請求 http://bank.example/withdraw?account=bob&amount=1000000&for=bob2 可以使 Bob 把 1000000 的存款轉(zhuǎn)到 bob2 的賬號下冬竟。通常情況下欧穴,該請求發(fā)送到網(wǎng)站后,服務(wù)器會先驗(yàn)證該請求是否來自一個(gè)合法的 session泵殴,并且該 session 的用戶 Bob 已經(jīng)成功登陸涮帘。黑客 Mallory 自己在該銀行也有賬戶,他知道上文中的 URL 可以把錢進(jìn)行轉(zhuǎn)帳操作笑诅。Mallory 可以自己發(fā)送一個(gè)請求給銀行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory调缨。但是這個(gè)請求來自 Mallory 而非 Bob疮鲫,他不能通過安全認(rèn)證,因此該請求不會起作用弦叶。這時(shí)俊犯,Mallory 想到使用 CSRF 的攻擊方式,他先自己做一個(gè)網(wǎng)站伤哺,在網(wǎng)站中放入如下代碼: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”燕侠,并且通過廣告等誘使 Bob 來訪問他的網(wǎng)站。當(dāng) Bob 訪問該網(wǎng)站時(shí)立莉,上述 url 就會從 Bob 的瀏覽器發(fā)向銀行绢彤,而這個(gè)請求會附帶 Bob 瀏覽器中的 cookie 一起發(fā)向銀行服務(wù)器。大多數(shù)情況下桃序,該請求會失敗杖虾,因?yàn)樗?Bob 的認(rèn)證信息。但是媒熊,如果 Bob 當(dāng)時(shí)恰巧剛訪問他的銀行后不久奇适,他的瀏覽器與銀行網(wǎng)站之間的 session 尚未過期,瀏覽器的 cookie 之中含有 Bob 的認(rèn)證信息芦鳍。這時(shí)嚷往,悲劇發(fā)生了,這個(gè) url 請求就會得到響應(yīng)柠衅,錢將從 Bob 的賬號轉(zhuǎn)移到 Mallory 的賬號皮仁,而 Bob 當(dāng)時(shí)毫不知情。等以后 Bob 發(fā)現(xiàn)賬戶錢少了菲宴,即使他去銀行查詢?nèi)罩敬恚仓荒馨l(fā)現(xiàn)確實(shí)有一個(gè)來自于他本人的合法請求轉(zhuǎn)移了資金,沒有任何被攻擊的痕跡喝峦。而 Mallory 則可以拿到錢后逍遙法外势誊。

三、CSRF攻擊

3.1 簡單級別CSRF攻擊

假設(shè)某游戲網(wǎng)站的虛擬幣轉(zhuǎn)賬是采用GET方式進(jìn)行操作的谣蠢,樣式如:

 http://www.game.com/Transfer.jsp?toUserId=11&vMoney=1000

此時(shí)惡意攻擊者的網(wǎng)站也構(gòu)建一個(gè)相似的鏈接:

  • 可以是采用圖片隱藏粟耻,頁面一打開就自動進(jìn)行訪問第三方:<img src='攻擊鏈接'>

  • 也可以采用js進(jìn)行相應(yīng)的操作

http://www.game.com/Transfer.jsp?toUserId=20&vMoney=1000  
#toUserID為攻擊的賬號ID

具體操作如下:

  • 假若客戶端已經(jīng)驗(yàn)證并登陸www.game.com網(wǎng)站,此時(shí)客戶端瀏覽器保存了游戲網(wǎng)站的驗(yàn)證cookie
  • 客戶端再tab另一個(gè)頁面進(jìn)行訪問惡意攻擊者的網(wǎng)站眉踱,并從惡意攻擊者的網(wǎng)站構(gòu)造的鏈接來訪問游戲網(wǎng)站
  • 瀏覽器將會攜帶該游戲網(wǎng)站的cookie進(jìn)行訪問挤忙,刷一下就沒了1000游戲虛擬幣
3.2 中級別CSRF攻擊

游戲網(wǎng)站負(fù)責(zé)人認(rèn)識到了有被攻擊的漏洞,將進(jìn)行升級改進(jìn)谈喳。

將由鏈接GET提交數(shù)據(jù)改成了表單提交數(shù)據(jù)

//提交數(shù)據(jù)表單
<form action="./Transfer.jsp" method="POST">
    <p>toUserId: <input type="text" name="toUserId" /</p>
    <p>vMoney: <input type="text" name="vMoney" /></p>
    <p><input type="submit" value="Transfer" /></p>
</form>

Transfer.jsp

String toUserId = ParamUtil.getInt(beat.getRequest(), "toUserId", "");
String vMoney = ParamUtil.getInt(beat.getRequest(), "vMoney", "");

if (StringUtils.isNotBlack(toUserId) && StringUtils.isNotBlack(vMoney)){
   //相應(yīng)的轉(zhuǎn)賬操作
}

惡意攻擊者將會觀察網(wǎng)站的表單形式册烈,并進(jìn)行相應(yīng)的測試。

首先惡意攻擊者采用(http://www.game.com/Transfer.jsp?toUserId=20&vMoney=1000)進(jìn)行測試叁执,發(fā)現(xiàn)仍然可以轉(zhuǎn)賬茄厘。

那么此時(shí)游戲網(wǎng)站所做的更改沒起到任何的防范作用矮冬,惡意攻擊者只需要像上面那樣進(jìn)行攻擊即可達(dá)到目的。

總結(jié):

  • 網(wǎng)站開發(fā)者的錯(cuò)誤點(diǎn)在于沒有使用 POST進(jìn)行接收數(shù)據(jù)次哈。當(dāng)$_REQUEST可以接收POST和GET發(fā)來的數(shù)據(jù)胎署,因此漏洞就產(chǎn)生了。
3.3 高級別CSRF攻擊

這一次窑滞,游戲網(wǎng)站開發(fā)者又再一次認(rèn)識到了錯(cuò)誤琼牧,將進(jìn)行下一步的改進(jìn)與升級,將采用POST來接收數(shù)據(jù)

Transfer.jsp

String toUserId = ParamUtil.getInt(beat.getRequest(), "toUserId", "");
String vMoney = ParamUtil.getInt(beat.getRequest(), "vMoney", "");

if (StringUtils.isNotBlack(toUserId) && StringUtils.isNotBlack(vMoney)){
   //相應(yīng)的轉(zhuǎn)賬操作
}

此時(shí)惡意攻擊者就沒有辦法進(jìn)行攻擊了么哀卫?那是不可能的巨坊。

惡意攻擊者根據(jù)游戲虛擬幣轉(zhuǎn)賬表單進(jìn)行偽造了一份一模一樣的轉(zhuǎn)賬表單,并且嵌入到iframe中

嵌套頁面:(用戶訪問惡意攻擊者主機(jī)的頁面此改,即tab的新頁面)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>攻擊者主機(jī)頁面</title>
    <script type="text/javascript">
    function csrf()
    {
        window.frames['steal'].document.forms[0].submit();
    }
    </script>
</head>
<body onload="csrf()">
<iframe name="steal" display="none" src="./xsrf.html">
</iframe>
</body>
</html>

表單頁面:(csrf.html)

<!DOCTYPE html>
<html>
<head>
    <title>csrf</title>
</head>
<body>
<form display="none" action="http://www.game.com/Transfer.jsp" method="post" >
    <input type="hidden" name="toUserID" value="20">
    <input type="hidden" name="vMoney" value="1000">
</form>
</body>
</html>

客戶端訪問惡意攻擊者的頁面一樣會遭受攻擊萍膛。

總結(jié):

  • CSRF攻擊是源于Web的隱式身份驗(yàn)證機(jī)制觉增!Web的身份驗(yàn)證機(jī)制雖然可以保證一個(gè)請求是來自于某個(gè)用戶的瀏覽器,但卻無法保證該請求是用戶批準(zhǔn)發(fā)送的。

四打瘪、CSRF防御

在業(yè)界目前防御 CSRF 攻擊主要有三種策略:驗(yàn)證 HTTP Referer 字段桐玻;在請求地址中添加 token 并驗(yàn)證号杏;在 HTTP 頭中自定義屬性并驗(yàn)證瓤摧。下面就分別對這三種策略進(jìn)行詳細(xì)介紹。

4.1 驗(yàn)證 HTTP Referer 字段

根據(jù) HTTP 協(xié)議纵苛,在 HTTP 頭中有一個(gè)字段叫 Referer剿涮,它記錄了該 HTTP 請求的來源地址。在通常情況下攻人,訪問一個(gè)安全受限頁面的請求來自于同一個(gè)網(wǎng)站取试,比如需要訪問 http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory,用戶必須先登陸 bank.example怀吻,然后通過點(diǎn)擊頁面上的按鈕來觸發(fā)轉(zhuǎn)賬事件想括。這時(shí),該轉(zhuǎn)帳請求的 Referer 值就會是轉(zhuǎn)賬按鈕所在的頁面的 URL烙博,通常是以 bank.example 域名開頭的地址。而如果黑客要對銀行網(wǎng)站實(shí)施 CSRF 攻擊烟逊,他只能在他自己的網(wǎng)站構(gòu)造請求渣窜,當(dāng)用戶通過黑客的網(wǎng)站發(fā)送請求到銀行時(shí),該請求的 Referer 是指向黑客自己的網(wǎng)站宪躯。因此乔宿,要防御 CSRF 攻擊,銀行網(wǎng)站只需要對于每一個(gè)轉(zhuǎn)賬請求驗(yàn)證其 Referer 值访雪,如果是以 bank.example 開頭的域名详瑞,則說明該請求是來自銀行網(wǎng)站自己的請求掂林,是合法的。如果 Referer 是其他網(wǎng)站的話坝橡,則有可能是黑客的 CSRF 攻擊泻帮,拒絕該請求。

這種方法的顯而易見的好處就是簡單易行计寇,網(wǎng)站的普通開發(fā)人員不需要操心 CSRF 的漏洞锣杂,只需要在最后給所有安全敏感的請求統(tǒng)一增加一個(gè)攔截器來檢查 Referer 的值就可以。特別是對于當(dāng)前現(xiàn)有的系統(tǒng)番宁,不需要改變當(dāng)前系統(tǒng)的任何已有代碼和邏輯元莫,沒有風(fēng)險(xiǎn),非常便捷蝶押。

然而踱蠢,這種方法并非萬無一失。Referer 的值是由瀏覽器提供的棋电,雖然 HTTP 協(xié)議上有明確的要求茎截,但是每個(gè)瀏覽器對于 Referer 的具體實(shí)現(xiàn)可能有差別,并不能保證瀏覽器自身沒有安全漏洞离陶。使用驗(yàn)證 Referer 值的方法稼虎,就是把安全性都依賴于第三方(即瀏覽器)來保障,從理論上來講招刨,這樣并不安全霎俩。事實(shí)上,對于某些瀏覽器沉眶,比如 IE6 或 FF2打却,目前已經(jīng)有一些方法可以篡改 Referer 值。如果 bank.example 網(wǎng)站支持 IE6 瀏覽器谎倔,黑客完全可以把用戶瀏覽器的 Referer 值設(shè)為以 bank.example 域名開頭的地址柳击,這樣就可以通過驗(yàn)證,從而進(jìn)行 CSRF 攻擊片习。

即便是使用最新的瀏覽器捌肴,黑客無法篡改 Referer 值,這種方法仍然有問題藕咏。因?yàn)?Referer 值會記錄下用戶的訪問來源状知,有些用戶認(rèn)為這樣會侵犯到他們自己的隱私權(quán),特別是有些組織擔(dān)心 Referer 值會把組織內(nèi)網(wǎng)中的某些信息泄露到外網(wǎng)中孽查。因此饥悴,用戶自己可以設(shè)置瀏覽器使其在發(fā)送請求時(shí)不再提供 Referer。當(dāng)他們正常訪問銀行網(wǎng)站時(shí),網(wǎng)站會因?yàn)檎埱鬀]有 Referer 值而認(rèn)為是 CSRF 攻擊西设,拒絕合法用戶的訪問瓣铣。

4.2 在請求地址中添加 token 并驗(yàn)證

CSRF 攻擊之所以能夠成功,是因?yàn)楹诳涂梢酝耆珎卧煊脩舻恼埱蟠浚撜埱笾兴械挠脩趄?yàn)證信息都是存在于 cookie 中棠笑,因此黑客可以在不知道這些驗(yàn)證信息的情況下直接利用用戶自己的 cookie 來通過安全驗(yàn)證。要抵御 CSRF擒滑,關(guān)鍵在于在請求中放入黑客所不能偽造的信息腐晾,并且該信息不存在于 cookie 之中∝ひ唬可以在 HTTP 請求中以參數(shù)的形式加入一個(gè)隨機(jī)產(chǎn)生的 token藻糖,并在服務(wù)器端建立一個(gè)攔截器來驗(yàn)證這個(gè) token,如果請求中沒有 token 或者 token 內(nèi)容不正確库车,則認(rèn)為可能是 CSRF 攻擊而拒絕該請求巨柒。

這種方法要比檢查 Referer 要安全一些,token 可以在用戶登陸后產(chǎn)生并放于 session 之中柠衍,然后在每次請求時(shí)把 token 從 session 中拿出洋满,與請求中的 token 進(jìn)行比對,但這種方法的難點(diǎn)在于如何把 token 以參數(shù)的形式加入請求珍坊。對于 GET 請求牺勾,token 將附在請求地址之后,這樣 URL 就變成 http://url?csrftoken=tokenvalue阵漏。 而對于 POST 請求來說驻民,要在 form 的最后加上 <input type=”hidden” name=”csrftoken” value=”tokenvalue”/>,這樣就把 token 以參數(shù)的形式加入請求了履怯。但是回还,在一個(gè)網(wǎng)站中,可以接受請求的地方非常多叹洲,要對于每一個(gè)請求都加上 token 是很麻煩的柠硕,并且很容易漏掉,通常使用的方法就是在每次頁面加載時(shí)运提,使用 javascript 遍歷整個(gè) dom 樹蝗柔,對于 dom 中所有的 a 和 form 標(biāo)簽后加入 token。這樣可以解決大部分的請求民泵,但是對于在頁面加載之后動態(tài)生成的 html 代碼诫咱,這種方法就沒有作用,還需要程序員在編碼時(shí)手動添加 token洪灯。

該方法還有一個(gè)缺點(diǎn)是難以保證 token 本身的安全。特別是在一些論壇之類支持用戶自己發(fā)表內(nèi)容的網(wǎng)站,黑客可以在上面發(fā)布自己個(gè)人網(wǎng)站的地址签钩。由于系統(tǒng)也會在這個(gè)地址后面加上 token掏呼,黑客可以在自己的網(wǎng)站上得到這個(gè) token,并馬上就可以發(fā)動 CSRF 攻擊铅檩。為了避免這一點(diǎn)憎夷,系統(tǒng)可以在添加 token 的時(shí)候增加一個(gè)判斷,如果這個(gè)鏈接是鏈到自己本站的昧旨,就在后面添加 token拾给,如果是通向外網(wǎng)則不加。不過兔沃,即使這個(gè) csrftoken 不以參數(shù)的形式附加在請求之中蒋得,黑客的網(wǎng)站也同樣可以通過 Referer 來得到這個(gè) token 值以發(fā)動 CSRF 攻擊。這也是一些用戶喜歡手動關(guān)閉瀏覽器 Referer 功能的原因乒疏。

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

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

然而這種方法的局限性非常大爸业。XMLHttpRequest 請求通常用于 Ajax 方法中對于頁面局部的異步刷新其骄,并非所有的請求都適合用這個(gè)類來發(fā)起,而且通過該類請求得到的頁面不能被瀏覽器所記錄下扯旷,從而進(jìn)行前進(jìn)拯爽,后退,刷新钧忽,收藏等操作毯炮,給用戶帶來不便。另外耸黑,對于沒有進(jìn)行 CSRF 防護(hù)的遺留系統(tǒng)來說桃煎,要采用這種方法來進(jìn)行防護(hù),要把所有請求都改為 XMLHttpRequest 請求大刊,這樣幾乎是要重寫整個(gè)網(wǎng)站为迈,這代價(jià)無疑是不能接受的。

五、Java 代碼示例

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

在 filter 中對請求的 Referer 驗(yàn)證代碼如下

5.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ù)請求,否則的話可能是 CSRF 攻擊捏题,轉(zhuǎn)到 error.jsp 頁面玻褪。

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

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

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

5.3 在客戶端對于請求附加 token
function appendToken(){ 
   updateForms(); 
   updateTags(); 
} 
 
function updateForms() { 
   // 得到頁面中所有的 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; 
 
       // 動態(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)頁的錨標(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ù)。注意對于 a.href 來說约急,可能該屬性已經(jīng)有參數(shù)零远,或者有錨標(biāo)記。因此需要分情況討論厌蔽,以不同的格式把 csrftoken 加入其中牵辣。

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

5.4 在 HTTP 頭中自定義屬性
var plainXhr = dojo.xhr; 
 
// 重寫 dojo.xhr 方法
dojo.xhr = function(method,args,hasBody) { 
   // 確保 header 對象存在
   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 里拿出放入字段中逾条。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市投剥,隨后出現(xiàn)的幾起案子师脂,更是在濱河造成了極大的恐慌,老刑警劉巖薇缅,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件危彩,死亡現(xiàn)場離奇詭異,居然都是意外死亡泳桦,警方通過查閱死者的電腦和手機(jī)汤徽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來灸撰,“玉大人谒府,你說我怎么就攤上這事拼坎。” “怎么了完疫?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵泰鸡,是天一觀的道長。 經(jīng)常有香客問我壳鹤,道長盛龄,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任芳誓,我火速辦了婚禮余舶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘锹淌。我一直安慰自己匿值,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布赂摆。 她就那樣靜靜地躺著挟憔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪烟号。 梳的紋絲不亂的頭發(fā)上绊谭,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機(jī)與錄音褥符,去河邊找鬼龙誊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛喷楣,可吹牛的內(nèi)容都是我干的趟大。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼铣焊,長吁一口氣:“原來是場噩夢啊……” “哼逊朽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起曲伊,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤叽讳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后坟募,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岛蚤,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年懈糯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涤妒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赚哗,死狀恐怖她紫,靈堂內(nèi)的尸體忽然破棺而出硅堆,到底是詐尸還是另有隱情,我是刑警寧澤贿讹,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布渐逃,位于F島的核電站,受9級特大地震影響民褂,放射性物質(zhì)發(fā)生泄漏茄菊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一赊堪、第九天 我趴在偏房一處隱蔽的房頂上張望买羞。 院中可真熱鬧,春花似錦雹食、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至钝荡,卻和暖如春街立,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背埠通。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工赎离, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人端辱。 一個(gè)月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓梁剔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舞蔽。 傳聞我的和親對象是個(gè)殘疾皇子荣病,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355

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

  • 轉(zhuǎn)載地址:http://www.phpddt.com/reprint/csrf.html CSRF概念:CSRF跨...
    流光汐舞閱讀 257評論 0 1
  • 轉(zhuǎn)載地址:http://www.phpddt.com/reprint/csrf.htmlCSRF概念:CSRF跨站...
    matianhe閱讀 982評論 0 104
  • CSRF是什么? (Cross Site Request Forgery, 跨站域請求偽造)是一種網(wǎng)絡(luò)的攻擊方式渗柿,...
    謝澤閱讀 3,231評論 0 8
  • CSRF概念 CSRF跨站點(diǎn)請求偽造(Cross—Site Request Forgery)个盆。 攻擊者盜用了你的身...
    furuiyang閱讀 2,903評論 0 2
  • 它是只優(yōu)雅的貓 其實(shí)貓科動物都懂得優(yōu)雅 它們沒有上過一天詩意的課 野蠻他們不懂 冷傲似乎是天生的 它們沒有人類的粗...
    墨上城閱讀 583評論 12 23