Egg Csrf 安全配置

开启与关闭配置

注意:除非清楚地确认后果,否则不建议擅自关闭安全插件提供的功能。

框架的安全插件是默认开启的,如果我们想关闭其中一些安全防范,直接设置该项的 enable 属性为 false 即可。

exports.security = {
  csrf: {
    enable: false,
  },
};

开启 CSRF 也很简单,在上述的 enable 变更为 true 即可。

通常来说,对于 CSRF 攻击有一些通用的防范方案,简单的介绍几种常用的防范方案:

  • Synchronizer Tokens:通过响应页面时将 token 渲染到页面上,在 form 表单提交的时候通过隐藏域提交上来。
  • Double Cookie Defense:将 token 设置在 Cookie 中,在提交(POST、PUT、PATCH、DELETE 等)请求时提交 Cookie,并通过 header 或者 body 带上 Cookie 中的 token,服务端进行对比校验。
  • Custom Header:信任带有特定的 header(例如 X-Requested-With: XMLHttpRequest)的请求。这个方案可以被绕过,所以 rails 和 django 等框架都放弃了该防范方式

框架结合了上述几种防范方式,提供了一个可配置的 CSRF 防范策略。

使用方式

同步表单的 CSRF 校验

在同步渲染页面时,在表单请求中增加一个 name 为 _csrf 的 url query,值为 ctx.csrf,这样用户在提交这个表单的时候会将 CSRF token 提交上来:

<form
  method="POST"
  action="/upload?_csrf={{ ctx.csrf | safe }}"
  enctype="multipart/form-data"
>
  title: <input name="title" /> file: <input name="file" type="file" />
  <button type="submit">upload</button>
</form>

传递 CSRF token 的字段可以在配置中改变:

// config/config.default.js
module.exports = {
  security: {
    csrf: {
      queryName: '_csrf', // 通过 query 传递 CSRF token 的默认字段为 _csrf
      bodyName: '_csrf', // 通过 body 传递 CSRF token 的默认字段为 _csrf
    },
  },
};

为了防范 BREACH 攻击,通过同步方式渲染到页面上的 CSRF token 在每次请求时都会变化,egg-view-nunjucks 等 View 插件会自动对 Form 进行注入,对应用开发者无感知。

AJAX 请求

在 CSRF 默认配置下,token 会被设置在 Cookie 中,在 AJAX 请求的时候,可以从 Cookie 中取到 token,放置到 query、body 或者 header 中发送给服务端。

var csrftoken = Cookies.get('csrfToken');

function csrfSafeMethod(method) {
  // these HTTP methods do not require CSRF protection
  return /^(GET|HEAD|OPTIONS|TRACE)$/.test(method);
}
$.ajaxSetup({
  beforeSend: function (xhr, settings) {
    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
      xhr.setRequestHeader('x-csrf-token', csrftoken);
    }
  },
});

通过 header 传递 CSRF token 的字段也可以在配置中改变:

// config/config.default.js
module.exports = {
  security: {
    csrf: {
      headerName: 'x-csrf-token', // 通过 header 传递 CSRF token 的默认字段为 x-csrf-token
    },
  },
};

Session vs Cookie 存储

默认配置下,框架会将 CSRF token 存在 Cookie 中,以方便 AJAX 请求获取到。但是所有的子域名都可以设置 Cookie,因此当我们的应用处于无法保证所有的子域名都受控的情况下,存放在 Cookie 中可能有被 CSRF 攻击的风险。框架提供了一个配置项,可以将 token 存放到 Session 中。
// config/config.default.js
module.exports = {
  security: {
    csrf: {
      useSession: true, // 默认为 false,当设置为 true 时,将会把 csrf token 保存到 Session 中
      cookieName: 'csrfToken', // Cookie 中的字段名,默认为 csrfToken
      sessionName: 'csrfToken', // Session 中的字段名,默认为 csrfToken
    },
  },
};
posted @ 2022-05-29 20:38  我就丶是逗比  阅读(514)  评论(0)    收藏  举报