【问题标题】:Is it safe to store a FaunaDB client secret in cookies?将 FaunaDB 客户端密码存储在 cookie 中是否安全?
【发布时间】:2021-07-15 01:30:36
【问题描述】:

许多 FaunaDB 身份验证指南都提倡将客户端密码存储为 cookie,以便将其附加到后续的数据库查询中,但它的安全性如何?实际上,秘密令牌百分百暴露在浏览器的 cookie 存储中。

假设这是 Next.JS 应用下的 /pages/api/login.js 处理程序:

    import { Client, query as q } from 'faunadb'
    import cookie from 'cookie'
    
    const client = new Client({ secret: 'YOUR_SERVER_SECRET_KEY_DO_NOT_EXPOSE_THIS_EVER' })
    
    const serializeFaunaCookie = secret => {
      const cookieSerialized = cookie.serialize('FAUNA_SECRET_COOKIE', secret, {
        sameSite: 'lax',
        secure: process.env.NODE_ENV === 'production',
        maxAge: 72576000,
        httpOnly: true,
        path: '/',
      })
      return cookieSerialized
    }
    
    export default async (req, res) => {
      client
        .query(q.Login(q.Match(q.Index('userByHandle'), req.body.handle), { password: req.body.password }))
        .then(({ secret }) => {
          res.setHeader('Set-Cookie', serializeFaunaCookie(secret))
          res.status(200).end()
        })
    }

这个结果相当明显,域将设置一个像FAUNA_SECRET_COOKIE whateverrandomUpperCaseandlOWERcASEalphanum3r1calstring 这样的cookie - 它没有加密。 谢谢!

【问题讨论】:

    标签: authentication session cookies faunadb


    【解决方案1】:

    这有点难以理解。 您的示例本身并不是不安全的,尽管这是一种非常糟糕的做法,没有必要并且可能会导致安全问题。

    在您的示例中,您使用的是YOUR_SERVER_SECRET_KEY_DO_NOT_EXPOSE_THIS_EVER,我假设它是serveradmin 角色 密钥。

    有几点需要了解:

    • 您的FAUNA_SECRET_COOKIE cookie 无法从浏览器访问,因为它使用httpOnly: true,这使得它只能从服务器读取。因此,任何人都无法访问该秘密,只有您才能访问。
    • 在 cookie 中存储服务器/管理员角色密钥是一种非常糟糕的做法,即使它使用 httpOnly cookie,如果您将其发送到浏览器,那么此密钥可用于处理动物数据库中的任何事情,它授予的权限太多。

    虽然在浏览器中发送 Fauna 令牌(存储在 httpOnly cookie 中)不一定不安全,但主要取决于令牌授予的角色(以及附带的权限它)。

    大多数在线示例未能彻底解释的是,如果这些令牌具有有限的权限集,您应该只向浏览器提供秘密令牌。而这通常需要创建自定义角色,就像上面截图中提到的Public 角色。

    https://github.com/Vadorequest/rwa-faunadb-reaflow-nextjs-magic 为基础的真实示例(我是作者),您可以在https://rwa-faunadb-reaflow-nextjs-magic.vercel.app/ 看到该应用的演示。

    在此应用程序上,有一个与Public 角色相关联的 Fauna 密钥,可在浏览器中访问该应用程序的每个人使用。这并不是不安全的,因为与该角色关联的权限非常有限。 You can see them here。 (它们基本上允许读/写id=1 的一个文档,仅此而已)

    这是安全但共享令牌的一个示例。

    另一个示例(来自同一个应用程序)是当用户进行身份验证时,他会获得一个新令牌,然后将其存储在 httpOnly cookie 中(与您的示例相同)。 此标记与角色无关,而是与文档相关。

    文档是经过身份验证的“用户”,并通过另一个自定义角色“编辑器”进行处理。该角色配置了一组限制性权限,基本上允许令牌仅读取用户本身,以及将 ownerId 设置为用户 ID 的文档。

    总结一下:

    • 如果有人要“窃取”Public 令牌(它在浏览器中硬编码并且很容易检索),他们只能执行非常有限的一组操作,这是安全的。
    • 如果有人要窃取用户的令牌(这并不简单,因为它没有存储在浏览器上,尽管可能因为它被发送到浏览器),他们只能冒充该特定用户。另外,token 是 7h 的 TTL,所以生成后 7h 会自动失效。

    【讨论】:

    • 明白!非常感谢!我现在在想,我宁愿使用 ABAC 方法,而不是使用 FaunaDB 描述的标准身份验证流程。因此,为文档定义权限,分配给用户的角色是要走的路。而且,在这种情况下,如果一个人登录并收到一个对他自己的文档有效的令牌,那么我的登录 api 应该如何更改?如果应该的话。
    • 但是,如果我需要一个能够管理整个数据库的超级管理员用户角色怎么办?这不再违背目的。
    • 两者都需要,这就是我在 POC 中所做的。我有一个通过.env 管理的server 令牌,并且我在登录期间生成了一个与用户相关的令牌。服务器密钥用于管理用户范围之外的事物,而用户相关密钥用于管理与用户相关的事物。与用户相关的密钥被发送到浏览器,因为我使用了实时功能并且这是必需的,还因为我直接从浏览器运行我的 GraphQL 查询,而不是通过 API 代理端点。服务器密钥永远不会与浏览器共享。
    【解决方案2】:

    如果它是服务器密钥或管理员密钥,则永远不要将其提供给前端,它应该是后端独有的,因为:

    你提供给前端的任何东西都会公开,也就是说,任何人都可以访问它,不管它是存储在 cookie 中、本地存储中还是对 xhr 的响应中,恶意用户都会检查其中的所有内容搜索您碰巧泄露到前端的密钥。

    但是,就像@Vadorequest 解释的那样,如果它是用户用来对自己的数据进行操作的密钥(并且不能用于其他任何事情),那么我认为它完全没问题。

    【讨论】:

    • 感谢您的意见!是的,动物群服务器密钥不会暴露给前端,它将被存储在一个未被 git 跟踪的 .env 文件中,或者 - 当使用 vercel - 时,它可以存储为一个 vercel 环境变量。跨度>
    猜你喜欢
    • 2011-01-07
    • 2011-07-11
    • 2010-12-06
    • 1970-01-01
    • 2011-09-22
    • 2021-05-18
    • 2016-05-07
    • 2012-07-20
    • 1970-01-01
    相关资源
    最近更新 更多