在用戶登陸某個網站後,看到某篇文章高興之餘,揮手打字,忽然有人發來一個連接,登陸者打開連接後什麼都沒有操做或者只是好奇的點擊了某個按鈕,在原登陸網站評論頁多出了一條本身的評論記錄???what happened?
若是您或者您的朋友發生了這樣的事情,那麼請第一時間郵件反饋給網站維護者,您大機率多是被攻擊了,而這種攻擊就是CSRF,下面逐步介紹其攻擊原理和防範措施。html
利用用戶登陸態前端
用戶不知情ios
完成業務請求正則表達式
...shell
盜取用戶資金(轉帳、消費)axios
冒充用戶發帖背鍋後端
我的隱私泄露跨域
samesite
是HTTP響應頭Set-Cookie
的屬性之一。它容許您聲明該Cookie是否僅限於第一方或者同一站點的訪問。
SameSite
接受下面三個值:瀏覽器
Cookies容許與當前網頁的URL與請求目標一致時發送,而且與第三方網站發起的GET請求也會發送。瀏覽器默認值。安全
Set-Cookie: userId=123; SameSite=Lax;
複製代碼
Cookies只會在當前網頁的URL與請求目標一致時發送,不會與第三方網站發起的請求一塊兒發送。
Set-Cookie:userId=123;SameSite=Strict
複製代碼
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實際上是一段隨機的字符串,它的做用是讓攻擊者發起請求時沒有辦法獲取這個字符串,也就是必需要通過咱們的頁面,通過目標網站的前端。
//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;
複製代碼
// 校驗代碼
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攻擊更是安全防護的重中之中。 本文記錄的是筆者在開發過程當中遇到的問題及處理的思路。可供有相似問題的讀者參考。 其餘安全方面的文章筆者會持續更新,歡迎各位讀者提出意見和建議。