为什么在koa上需要多个密钥?

Mas*_*gol 7 secret-key koa koa2

对不起,我不太明白秘密密钥在koa中是如何工作的.在koa中,对象keys上有一个字段app,将使用如下:

const app = new Koa();
app.keys = ['some secret', 'another secret', 'or more ...']; // it's an
                                                             // array right?
Run Code Online (Sandbox Code Playgroud)

然后,在使用koa-csrf中间件时,默认情况下内置程序csrf.middleware不使用提供的密钥app.keys.如果我使用默认中间件,我需要创建另一个在会话上设置密钥的中间件.

app.use(session()); // koa-generic-session
app.use(async (ctx, next) => {               // without this custom middleware
  ctx.session.secret = 'yet another secret'; // POST /protected-route
  await next();                              // will give 403
});                                          // missing secret
csrf(app);
app.use(csrf.middleware);
Run Code Online (Sandbox Code Playgroud)

当我使用Flask时,我只需要提供一个由string非设置的密钥array.为什么需要多个密钥?只使用一个整个应用程序还不够?

dan*_*neu 8

好像你在这里问了很多东西.

  1. 您可以app.keys = [...]为键旋转提供Koa 多个键.

    例如,如果您希望每月生成一个新密钥,则可以使用它来签署新密钥,而不会立即使所有旧cookie无效.相反,您更愿意让旧的Cookie自然过期.

    如果关键旋转不是你关心的事情,那么你只需使用app.keys = ['mysecret']你永远不会改变的东西.

  2. koa-csrf的中间件实际上确实使用了你设置的密钥app.keys=.

    兴亚传递app.keys到它的饼干实例(https://github.com/pillarjs/cookies),使内置this.cookies.get()this.cookies.set()将使用键(如果有的话).

    koa-session使用Koa的内置功能this.cookies.{get,set}.

    koa-csrf用途koa-session.

但所有这一切都无关紧要.

403回复并没有抱怨您没有设置app.keys=机密.它抱怨你没有提供CSRF令牌(也就是秘密)而不是有效令牌.

您手动设置的"修复" this.session.secret只是手动设置koa-csrf查找CSRF令牌的值.您绕过了CSRF系统的整个安全措施.

CSRF令牌系统的重点是确保击中受保护端点的人实际上源自,例如,<form>从您控制的页面发布到该端点.

它通过生成令牌,将其保存在cookie中,将令牌附加到表单,然后在提交时确保表单令牌与会话令牌匹配来实现此目的.

你似乎缺少的是你必须:

  1. 生成CSRF令牌
  2. 将其设置secret为客户端的cookie
  3. 将CSRF令牌公开给客户端,以便将它们提交给受保护的端点.
  4. 在受保护的端点上,确保客户端在其"秘密"cookie中发送与CSRF令牌匹配的CSRF令牌.以下是 koa-csrf检查找到该令牌的地方.

koa-csrf的this.csrf电话会议#1和#2.你必须实现#3.koa-csrf的this.assertCSRF#4.

所以,总之,这是它的外观(未经测试):

var koa = require('koa')
var csrf = require('koa-csrf')
var session = require('koa-session')
var Router = require('koa-router');
var bodyParser = require('koa-bodyparser');

var app = koa()
app.keys = ['session secret']
app.use(session())
app.use(bodyParser())
csrf(app)
app.use(csrf.middleware)

var router = new Router();

router.get('/messages', function*() {
  this.render('new_message_form.html', {
    token: this.csrf   // this call also sets `this.session.secret` for you
  });
});

router.post('/messages', function*() {
  this.assertCSRF(this.request.body);

  // If we get this far, then the CSRF check passed
  yield database.insertMessage(this.body.message);
});

app.use(router.routes());
app.listen(3000, () => console.log('server listening on 3000'));
Run Code Online (Sandbox Code Playgroud)

这就是'new_message_form.html'的样子.请注意,我正在设置一个隐藏字段,_csrf以便在用户提交时,生成的令牌this.csrf被发送到我的受保护端点,该_csrf字段是koa-csrf检查以查找提交的令牌的位置之一.

<form action="/messages" method="POST">
  <input type="hidden" name="_csrf" value="{{ token }}">
  <input type="message" name="message" placeholder="Write your message here...">
  <button type="submit">Save Message<button>
</form>
Run Code Online (Sandbox Code Playgroud)