在用户登陆某个网站后,看到某篇文章高兴之余,挥手打字,忽然有人发来一个连接,登陆者打开连接后什么都没有操做或者只是好奇的点击了某个按钮,在原登陆网站评论页多出了一条本身的评论记录???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攻击更是安全防护的重中之中。 本文记录的是笔者在开发过程当中遇到的问题及处理的思路。可供有相似问题的读者参考。 其余安全方面的文章笔者会持续更新,欢迎各位读者提出意见和建议。