ホームページ  >  記事  >  ウェブフロントエンド  >  実用的な Nodejs npm パッケージを共有します: koa-csrf

実用的な Nodejs npm パッケージを共有します: koa-csrf

青灯夜游
青灯夜游転載
2021-04-25 10:09:292731ブラウズ

この記事では、実用的な Nodejs npm パッケージ ---koa-csrf を紹介します。一定の参考値があるので、困っている友達が参考になれば幸いです。

実用的な Nodejs npm パッケージを共有します: koa-csrf

koa-csrf は、csrf 攻撃を防ぐために使用される koa ミドルウェアです。

もちろん、CSRF とは何か、およびそれを防ぐ方法についてはここでは詳しく説明しません。興味のある方は、 Understanding-csrf を読んでください。 egg は csrf ソリューションを処理します

最初に簡単な例を見てみましょう:

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;

ワークフローの簡単な理解:

クライアント リクエスト ページ:

  • サーバーはuser 現在のセッションはシークレット値を生成し、それをセッションに保存します;
  • シークレットに基づいて csrf トークンを生成し、ctx._csrf に保存します;
  • csrf トークンをクライアントに送信します

投稿リクエストの送信時などのユーザー書き込み操作:

  • サーバーはクライアントから渡された csrf トークンを取得します;
  • サーバーは次の情報を見つけます現在のセッションのシークレット値;
  • サーバーはシークレットを使用して、受信した csrf トークンを検証します;

#koa-csrf

koa-csrf のトークン作成および検証ロジック これらはすべて、この

csrf パッケージに含まれています。

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;

次回は、より関連したロジックを処理する csrf ライブラリを見ていきます。

はい、今日はここまでです。また次回お会いしましょう。

ps: ノードにも興味がある場合は、私の公式アカウント「xyz プログラミング日記」をフォローしてください。

関連する推奨事項:「

nodejs チュートリアル

以上が実用的な Nodejs npm パッケージを共有します: koa-csrfの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。