談談CSRF

CSRF介紹前端

  • 英文:Cross Site Request Forgy
  • 中文:跨站請求僞造
  • 攻擊者在其餘的網站對目標網站產生了影響

CSRF攻擊危害

  • 利用用戶登陸態
  • 用戶不知情
  • 完成業務請求
  • 盜取用戶資金(轉帳,消費)

    就算警察尋找是誰,也只能找到用戶,找不到攻擊者,由於攻擊者用的ip和cookie都是用戶的。node

CSRF攻擊防護

csrf防護核心思想就是利用攻擊者不會訪問目標網站的前端,只會去訪問目標網站的後端,因此若是在目標網站的前端增長驗證信息,那就會有效防護csrf攻擊,由於csrf沒法獲取這個驗證信息,也就沒法獲得後端的正確響應。ajax

第一種方法

禁止第三方網站攜帶cookie後端

在cookie中加一個same-site屬性 可是兼容性不好,只有不多的瀏覽器兼容。瀏覽器

第二種方法

在前端頁面加入驗證信息,好比:cookie

  1. 驗證碼
    1. 加入token

驗證碼

這須要先後端協同
1:前端加入驗證碼輸入框。
2:後端爲前端提供這個驗證碼,而且在提交的時候進行驗證,還有後端還要記住這個驗證碼是什麼,也就是保存下來,以便有第三方進行csrf攻擊時進行判斷。
node.js開發後端的話,有ccap這個插件能夠用,它能夠生成圖形驗證碼。併發

這個能夠有效防護csrf,可是每次都要讓用戶輸入驗證碼進行驗證,下降了用戶體驗。並且前端提交後,後端還要再校驗一下驗證碼對不對。dom


token

token就是一個隨機字符串,放在前端的請求內容中,也能夠放在cookie中。post

token生成機制:網站

 1 // 後端要作的事情
 2 // 隨機生成token
 3 var csrfToken = parseInt(Math.random() * 9999999, 10);
 4  
 5 // 後端生成token而且保存在cookie中
 6 ctx.cookies.set('csrfToken', csrfToken);
 7  
 8  
 9 // 前端要作的事情
10 // 放置一個表單,不會顯示出來,設置隱藏
11 <input name="csrfToken" value=csrfToken><input>

 


而後在相應的動做裏進行判斷: 

 1 function action(req, res){
 2 var data;
 3 if(req.method.toLowerCase() === 'post'){
 4 data = req.body;
 5 }else{
 6 data = req.query;
 7 }
 8 if(!data.crsfToken){
 9 throw new('csrf token is null');
10 }else if(data.csrfToken !== req.cookies.get('csrfToken')){
11 throw new('csrfToken 錯誤');
12 }
13 }

 


使用token須要注意的地方
 

  • 若是是經過表單提交,則能夠直接將token值放在表單裏面提交。
  • 若是是ajax請求,則通常是經過將token放在頁面的另一個地方,好比放在meta中。
meta{name="csrf_token", content=csrfToken}

 

刷新後,在頁面的head中多了一個meta,在ajax請求以前,就能夠經過js把這個meta中的toke值取出來,一併發到後臺去。

注意:

若是用戶打開了不少頁面或者不少提交表單,每一個頁面和表單都是對應不一樣的token,由於cookies裏面只能放置一個token,用戶提交只能是提交最後一個頁面的token或者是最後一個表單的token,因此這個問題也比較特殊,如何處理。須要思考。


CSRF中的referer

referer是http協議中的一個請求頭,來自攻擊網站。因此還有一個防護方式:驗證referer,禁止來自第三方網站的請求。

 1 // 在相應的動做裏
 2 function action(req, res){
 3 var data;
 4 if(req.method.toLowerCase() === 'post'){
 5 data = req.body;
 6 }else{
 7 data = req.query;
 8 }
 9 var referer = res.headers.referer;
10 // 經過使用indexOf判斷
11 if(referer indexOf('localhost') === '-1'){
12 throw new('請求非法');
13 }
14  
15 // 更好的作法是下面這個,由於referer是http://整個url地址,若是url其餘部分有localhost,上面的表達式也能夠被匹配到
16 if(!/^http:\/\/localhost/.test(referer)){
17 throw new('請求非法');
18 }
19 }

 


這裏面有幾個注意的點: 

  • 從本地磁盤訪問,沒有refere,由於是同域,能夠將ftp改爲http形式,好比http://127.0.0.1/
  • 經過http訪問,有referer。

 參考

http://godkun.me/2018/01/10/CSRF%E7%A0%94%E7%A9%B6/

相關文章
相關標籤/搜索