Heim  >  Artikel  >  Web-Frontend  >  Teilen Sie ein praktisches Nodejs npm-Paket: koa-csrf

Teilen Sie ein praktisches Nodejs npm-Paket: koa-csrf

青灯夜游
青灯夜游nach vorne
2021-04-25 10:09:292667Durchsuche

In diesem Artikel stellen wir Ihnen ein praktisches Nodejs npm-Paket vor: koa-csrf. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Teilen Sie ein praktisches Nodejs npm-Paket: koa-csrf

koa-csrf ist eine Koa-Middleware, die zur Verhinderung von CSRF-Angriffen verwendet wird.

Natürlich werde ich hier nicht näher darauf eingehen, was CSRF ist und wie man es verhindern kann. Wer sich dafür interessiert, kann understanding-csrf lesen. Egg kümmert sich um CSRF-Lösungen.

Zuerst schauen wir uns ein einfaches Beispiel an:

const router = require('koa-router')();
const CSRF = require('koa-csrf');
const csrfMD = new CSRF({
  invalidSessionSecretMessage: 'Invalid session secret',
  invalidTokenMessage: 'Invalid CSRF token',
  invalidTokenStatusCode: 403,
});

router
  .get('/',csrfMD,async (ctx, next) => {
    ctx.cookies.set('cid','1234', cookieSet);
    // 下发csrf token
    await ctx.render('index', {
      title: 'EJS !',
      csrf: ctx.csrf
    });
  })
  .post('/post', csrfMD ,async (ctx, next) => {
    console.log(ctx.method);
    ctx.session.email = ctx.request.body.email;
    ctx.session.name = ctx.request.body.name;
    ctx.redirect('/');
  })

module.exports = router;

Ein einfaches Verständnis seines Arbeitsablaufs:

Client-Anforderungsseite:

  • Der Server generiert einen geheimen Wert für die aktuelle Sitzung des Benutzers und speichert ihn in der Sitzung
  • Generiert Ein CSRF-Token basierend auf dem Geheimnis, speichern Sie es in ctx._csrf.
  • Senden Sie das CSRF-Token an den Client Client;
Der Server erhält das CSRF-Token aus der aktuellen Sitzung. Finden Sie den geheimen Wert.

Der Server verwendet das Geheimnis, um das empfangene CSRF-Token zu überprüfen.
  • koa-csrf-Token-Erstellung und -Verifizierung Logik sind alle in diesem
  • csrf
  • -Paket enthalten.
  • const csrf = require('csrf');
    
    class CSRF {
      constructor(opts = {}) {
        // opts配置对象、并且有提供默认配置
        // 允许自定义配置对象进行覆盖
        this.opts = Object.assign(
          {
            // 使 koa 抛出的错误信息内容,默认值为:'Invalid CSRF token'。
            // 它可以是一个接收 ctx 作为参数的函数,函数最后返回错误信息内容。
            invalidTokenMessage: 'Invalid CSRF token',
            // 验证失败时的响应状态码,默认值为:403(Forbidden)
            // 跟 invalidTokenMessage 参数一样,它也会被传递给 ctx.throw,用于抛出错误和拒绝请求。
            invalidTokenStatusCode: 403,
            // 排除的请求方法,默认值为:['GET', 'HEAD', 'OPTIONS']。
            excludedMethods: ['GET', 'HEAD', 'OPTIONS'],
            // 是否禁止通过查询字符串传递 _csrf 校验 token,默认值为 false
            // 如果校验 token 出现在 URL 中,则可能会通过 Referer 泄露,应尽量把 Token 放在表单中,把敏感操作由 GET 改为 POST。
            disableQuery: false
          },
          opts
        );
    
        // 生成token generation/verification instance
        this.tokens = csrf(opts);
        // 早期很多这样的中间件写法、对接koa中间件
        return this.middleware.bind(this);
      }
    
      // koa中间件
      middleware(ctx, next) {
        // __defineGetter__ API已经不推荐使用
        // 在ctx上挂载csrf属性。
        // 当读取ctx.csrf会执行该回调
        ctx.__defineGetter__('csrf', () => {
          // 如果已经存在直接返回、避免多次生成
          if (ctx._csrf) {
            return ctx._csrf;
          }
          // csrf依赖于koa session
          if (!ctx.session) {
            return null;
          }
    
          // 生成一个secret存储在ctx.session.secret
          if (!ctx.session.secret) {
            ctx.session.secret = this.tokens.secretSync();
          }
          // 根据上述的secret生成csrf toke存到ctx._csrf
          // 一般非框架本身属性,都建议_xx表示私有
          ctx._csrf = this.tokens.create(ctx.session.secret);
          // 返回
          return ctx._csrf;
        });
    
        // 挂栽ctx.response.csrf属性
        ctx.response.__defineGetter__('csrf', () => ctx.csrf);
    
        // 如果是请求方法黑名单直接不处理
        if (this.opts.excludedMethods.indexOf(ctx.method) !== -1) {
          return next();
        }
    
        if (!ctx.session.secret) {
          ctx.session.secret = this.tokens.secretSync();
        }
    
        // 从ctx.request.body取出客户端传递过来的_csrf token
        // 因此依赖于koa-bodyparser类库
        const bodyToken =
          ctx.request.body && typeof ctx.request.body._csrf === 'string'
            ? ctx.request.body._csrf
            : false;
    
        // 除了从body获取token
        // 支持从ctx.query._csrf即get方法查询字符串
        // 支持从请求头获取 'csrf-token'、'xsrf-token'、'x-csrf-token'、'x-xsrf-token'
        const token =
          bodyToken ||
          (!this.opts.disableQuery && ctx.query && ctx.query._csrf) ||
          ctx.get('csrf-token') ||
          ctx.get('xsrf-token') ||
          ctx.get('x-csrf-token') ||
          ctx.get('x-xsrf-token');
    
          // 如果获取失败、根据配置对象的信息、抛出异常
        if (!token) {
          return ctx.throw(
            this.opts.invalidTokenStatusCode,
            typeof this.opts.invalidTokenMessage === 'function'
              ? this.opts.invalidTokenMessage(ctx)
              : this.opts.invalidTokenMessage
          );
        }
    
        // 校验token失败
        if (!this.tokens.verify(ctx.session.secret, token)) {
          return ctx.throw(
            this.opts.invalidTokenStatusCode,
            typeof this.opts.invalidTokenMessage === 'function'
              ? this.opts.invalidTokenMessage(ctx)
              : this.opts.invalidTokenMessage
          );
        }
        // 校验成功
        return next();
      }
    }
    
    module.exports = CSRF;
In der nächsten Ausgabe werfen wir einen Blick auf die CSRF-Bibliothek, die weitere verwandte Logik verwaltet.

Okay, das war's für heute, bis zum nächsten Mal.

ps: Wenn Sie auch an Node interessiert sind, folgen Sie bitte meinem offiziellen Konto: xyz Programming Diary.

Verwandte Empfehlungen: „nodejs-Tutorial

Das obige ist der detaillierte Inhalt vonTeilen Sie ein praktisches Nodejs npm-Paket: koa-csrf. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen