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
image.png
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 文件中加入以下代码

  1. // 安全验证
  2. config.security = {
  3. csrf: {
  4. enable: true, // 关闭 csrf 不推荐
  5. ignoreJSON: true,
  6. },
  7. // 允许跨域访问, 添加白名单 domainWhiteList: ['*'],
  8. domainWhiteList: [ 'http://localhost:3000' ],
  9. };

以上方法确实可以解决此方案,但是不推荐,因为:
egg 框架内置了安全系统,默认开启防止 XSS 攻击 和 CSRF 攻击,以上设置只是将内置的安全系统关闭了而已。

csrfToken

前端发送请求的话,cookies里面会生成一个秘钥对,每次请求后秘钥都会变的,
所以,前端要获取到 csrf,以全局的方式放在headers请求头里
image.png

egg 的默认,每次在前端发送 post 请求的时候必须读取一个 cookie 字段 : csrfToken 放在 header 请求头里面,
每次请求的时候 egg 会帮我们验证一次,所以需要重新配置一下 config.default.js 文件

  1. // 安全验证
  2. config.security = {
  3. csrf: {
  4. // 通过 header 传递 CSRF token 的默认字段为 x-csrf-token
  5. headerName: 'x-csrf-token', // 自定义请求头
  6. // queryName: '_csrf', // 通过 query 传递 CSRF token 的默认字段为 _csrf
  7. // bodyName: '_csrf', // 通过 body 传递 CSRF token 的默认字段为 _csrf
  8. },
  9. };

客户端请求

发送请求必须要携带 x-csrf-token,例如 postman发送 post请求就必须要带上 x-csrf-token
image.png

x-csrf-token

  1. // 封装获取 cookie 的方法
  2. function getCookie(name){
  3. let arr;
  4. const reg = new RegExp("(^| )"+name+"=([^;]*)(;|$)");
  5. if(arr=document.cookie.match(reg)) {
  6. return unescape(arr[2])
  7. }
  8. return null;
  9. }
  10. axios.post('/user/list', {id: 23}, {
  11. headers: {
  12. 'x-csrf-token': getCookie('csrfToken');
  13. }
  14. })

正则匹配token

  1. export const matchToken = key => new RegExp(`(^| )${key}=([^;]*)(;|$)`);
  2. // 获取 cookie
  3. document.cookie
  4. // 服务端从 header里面获取 cookie
  5. ctx.request.header.cookie.match(matchToken('_csrfToken_'))