egg框架在安全方面做了处理,自带安全验证。
不是简单请求都会视为不安全的,报错如下:
2021-11-13 10:23:18,264 WARN 37367 [-/127.0.0.1/-/17ms POST /users] invalid csrf token.
See https://eggjs.org/zh-cn/core/security.html#安全威胁csrf的防范
2021-11-13 10:23:18,266 WARN 37367 [-/127.0.0.1/-/18ms POST /users] nodejs.ForbiddenError: invalid csrf token
Cross-site request forgery 跨站请求伪造
eggjs xsrf
https://eggjs.org/zh-cn/core/security.html#%E5%AE%89%E5%85%A8%E5%A8%81%E8%83%81-csrf-%E7%9A%84%E9%98%B2%E8%8C%83
服务端无法接受 post 请求,并且前台报错 403 ,服务端自动返回信息:message: ‘invalid csrf token’
参考 https://blog.csdn.net/weixin_43704471/article/details/90763103
直接在 config.default.js 文件中加入以下代码
// 安全验证
config.security = {
csrf: {
enable: true, // 关闭 csrf 不推荐
ignoreJSON: true,
},
// 允许跨域访问, 添加白名单 domainWhiteList: ['*'],
domainWhiteList: [ 'http://localhost:3000' ],
};
以上方法确实可以解决此方案,但是不推荐,因为:
egg 框架内置了安全系统,默认开启防止 XSS 攻击 和 CSRF 攻击,以上设置只是将内置的安全系统关闭了而已。
csrfToken
前端发送请求的话,cookies里面会生成一个秘钥对,每次请求后秘钥都会变的,
所以,前端要获取到 csrf,以全局的方式放在headers请求头里
egg 的默认,每次在前端发送 post 请求的时候必须读取一个 cookie 字段 : csrfToken 放在 header 请求头里面,
每次请求的时候 egg 会帮我们验证一次,所以需要重新配置一下 config.default.js 文件
// 安全验证
config.security = {
csrf: {
// 通过 header 传递 CSRF token 的默认字段为 x-csrf-token
headerName: 'x-csrf-token', // 自定义请求头
// queryName: '_csrf', // 通过 query 传递 CSRF token 的默认字段为 _csrf
// bodyName: '_csrf', // 通过 body 传递 CSRF token 的默认字段为 _csrf
},
};
客户端请求
发送请求必须要携带 x-csrf-token,例如 postman发送 post请求就必须要带上 x-csrf-token
x-csrf-token
// 封装获取 cookie 的方法
function getCookie(name){
let arr;
const reg = new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg)) {
return unescape(arr[2])
}
return null;
}
axios.post('/user/list', {id: 23}, {
headers: {
'x-csrf-token': getCookie('csrfToken');
}
})
正则匹配token
export const matchToken = key => new RegExp(`(^| )${key}=([^;]*)(;|$)`);
// 获取 cookie
document.cookie
// 服务端从 header里面获取 cookie
ctx.request.header.cookie.match(matchToken('_csrfToken_'))