【问题标题】:Why need more than one secret key on koa?为什么在 koa 上需要多个密钥?
【发布时间】:2016-05-23 14:19:54
【问题描述】:

抱歉,我不太明白密钥在 koa 中是如何工作的。在koa中,有 app 对象上的 keys 字段将像这样使用:

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

然后,在使用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);

当我使用 Flask 时,我只需要提供一个密钥,即 由string 而不是array 设置。为什么需要多个密钥?整个应用只使用一个还不够吗?

【问题讨论】:

    标签: koa secret-key koa2


    【解决方案1】:

    好像你在这里问了很多事情。

    1. 您可以提供 Koa app.keys = [...] 多个密钥用于密钥轮换。

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

      如果您不关心密钥轮换,那么您只需使用永远不会更改的 app.keys = ['mysecret']

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

      Koa 将 app.keys 传递到其 Cookie 实例 (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>,该<form> 从您控制的页面发布到该端点。

    它通过生成一个令牌,将其保存在一个 cookie 中,将令牌附加到表单上,然后在提交时确保表单令牌与会话令牌匹配。

    你似乎缺少的是你必须:

    1. 生成 CSRF 令牌
    2. 将其设置为客户端的secret cookie
    3. 向客户端公开 CSRF 令牌,以便他们将其提交到受保护的端点。
    4. 在受保护的端点上,确保客户端发送的 CSRF 令牌与其“秘密”cookie 中的 CSRF 令牌相匹配。 Here are the places那个 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'));
    

    这就是“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>
    

    【讨论】:

    • 感谢您的回答。我明白你在那里解释什么。但是,(对不起,如果我不太清楚),实际上我使用 ajax post 在服务器上休息 API 并在使用 javascript 的 meta 标记上公开 csrf 令牌。我已经测试过 403 消息不是关于缺少令牌,而是关于密钥设置不正确,消息不同。您可以使用 koa-generic-session 而不是 koa-session 重现我的问题,这是不同的。我怀疑koa-generic-sessionkoa-csrf 之间存在通信缺失。顺便说一句,谢谢,我现在明白了该键数组的用途。
    猜你喜欢
    • 1970-01-01
    • 2010-09-10
    • 1970-01-01
    • 2019-08-17
    • 2020-06-19
    • 1970-01-01
    • 2021-08-02
    • 2011-10-06
    • 1970-01-01
    相关资源
    最近更新 更多