CSRF攻防基礎講解

CSRF攻擊

  • Cross-site request forgery
  • 跨站請求僞造

場景模擬

在用戶登陸某個網站後,看到某篇文章高興之餘,揮手打字,忽然有人發來一個連接,登陸者打開連接後什麼都沒有操做或者只是好奇的點擊了某個按鈕,在原登陸網站評論頁多出了一條本身的評論記錄???what happened?
若是您或者您的朋友發生了這樣的事情,那麼請第一時間郵件反饋給網站維護者,您大機率多是被攻擊了,而這種攻擊就是CSRF,下面逐步介紹其攻擊原理和防範措施。html

攻擊原理

  1. 用戶登陸A網站
  2. A網站登陸成功後返回用戶身份信息
  3. B網站獲取A網站的用戶登陸身份信息向A網站發起請求,而且攜帶了A網站的用戶身份信息

CSRF攻擊原理.png

攻擊危害

  • 利用用戶登陸態前端

  • 用戶不知情ios

  • 完成業務請求正則表達式

  • ...shell

  • 盜取用戶資金(轉帳、消費)axios

  • 冒充用戶發帖背鍋後端

  • 我的隱私泄露跨域

CSRF 攻擊防護

禁止第三方網站帶Cookies

sameSite

samesite是HTTP響應頭Set-Cookie的屬性之一。它容許您聲明該Cookie是否僅限於第一方或者同一站點的訪問。
SameSite接受下面三個值:瀏覽器

  • Lax

Cookies容許與當前網頁的URL與請求目標一致時發送,而且與第三方網站發起的GET請求也會發送。瀏覽器默認值。安全

Set-Cookie: userId=123; SameSite=Lax;
複製代碼
  • Strict

Cookies只會在當前網頁的URL與請求目標一致時發送,不會與第三方網站發起的請求一塊兒發送。

Set-Cookie:userId=123;SameSite=Strict
複製代碼
  • None

Cookie將在全部上下文中發送,即容許跨域發送。
使用None時,必須同時設置Secure屬性(Cookie只能經過HTTPS協議發送),不然無效。

如下的設置無效:

Set-Cookie: userId=123; SameSite=None
複製代碼

下面的設置有效:

Set-Cookie: userId=123; SameSite=None;Secure
複製代碼

更多用法能夠參考阮一峯老師SameSite屬性介紹MDN-SameSite,到此讀者可能會疑惑 sameSite難道能夠解決全部的CSRF攻擊嗎?
答案:固然不是,sameSite受瀏覽器兼容性的影響,並不能解決防護全部攻擊。兼容性列表在MDN的連接中。
再按照攻擊原理所理解,CSRF的攻擊是不通過目標網站的前端的,那麼咱們是否是能夠在此處「動手腳」尼?

在前端頁面加入驗證信息

驗證碼


處理思路:後端生成驗證碼保存並傳遞給前端;在前端提交表單數據中加入驗證碼並提交,在後端校驗驗證碼存在和正確與否;

//驗證碼生成
var captcha = {};
var cache = {};
captcha.captcha = async function (ctx, next) {
    var ccpa = require('ccap');//驗證碼生成模塊
    var capt = ccpa();
    var data = capt.get();
    captcha.setCache(ctx.cookies.get('userId'), data[0]);
    ctx.body = data[1]
}
captcha.setCache = function (uid, data) {
    cache[uid] = data;
}
captcha.validCache = function (uid, data) {
    return cache[uid] === data;
}
module.exports = captcha;
複製代碼
//驗證碼校驗
...
const data = ctx.request.body;
if(!data.captcha){
	throw new Error('驗證碼錯誤')
}
var captcha = require('../tools/captcha')
var resultCaptche = captcha.validCache(ctx.cookies.get('userId'),data.captche);
if(!resultCaptche){
	throw new Error('驗證碼錯誤')
}
...
複製代碼

加入圖形驗證碼對防護攻擊能夠起到很好的做用,可是每一個表單都須要輸入圖形驗證碼且還要保證每次輸入的驗證碼都正確。這對於用戶來講是很是痛苦的一件事,因而可知這種方式在實際的使用中並不受用,那麼有沒有其餘的更好的方案尼?

token驗證


token實際上是一段隨機的字符串,它的做用是讓攻擊者發起請求時沒有辦法獲取這個字符串,也就是必需要通過咱們的頁面,通過目標網站的前端。

  • 在 HTTP 請求中以參數的形式添加一個隨機產生的 token,並在服務器端驗證這個 token,假設請求中沒有token 或者 token 內容不對,拒絕該請求。
  • 在HTTP請求頭中,經過axios的配置參數,給全部的fetch請求所有加上Token這個HTTP請求頭屬性,並把Token值也放入請求頭中。
//fetch.js
import axios from 'axios';

function getToken() {
    return localStorage.getItem('Token') ||'';
}
const fetch = axios.create({
    timeout: 60000 
});
fetch.interceptors.request.use(
    config => {
        config.headers['X-Token'] = getToken(); 
        return config;
    },
    error => {
        closeLoding();
        Promise.reject(error);
    }
);
...
export default fetch;
複製代碼

關於Token

  1. Token能夠保存在localStorage中
  2. Token加密且簽名
  3. Token生成與過時機制
  4. 將 JSON Web Tokens 應用到 OAuth 2

Referer

  • 驗證referer
  • 禁止第三方網站的請求
// 校驗代碼
const referer = ctx.request.headers.referer;
// 簡易防護
if(referer.indexOf('localhost')=== -1){
	throw new Error('非法請求')
}
上面的防護對這個地址是無效的:http:xx.xx.xx?name="張三"&uid='112'&localhost=='哈哈哈'
// 正則表達式防護
if(!/^https?:\/\/localhost/.test(referer)){
	throw new Error('非法請求')
}
複製代碼

固然這裏還要考慮沒有referer的狀況哈

結語

安全做爲系統的壁壘,重要程度不用多說。 CSRF攻擊更是安全防護的重中之中。 本文記錄的是筆者在開發過程當中遇到的問題及處理的思路。可供有相似問題的讀者參考。 其餘安全方面的文章筆者會持續更新,歡迎各位讀者提出意見和建議。

相關文章
相關標籤/搜索