【问题标题】:用于基于令牌的身份验证的 JWT 与 cookie
【发布时间】:2016-10-01 15:14:32
【问题描述】:

我读过一些关于“JWT vs Cookie”的帖子,但它们只会让我更加困惑......

  1. 我想澄清一下,当人们谈论“基于令牌的身份验证与 cookie”时,这里的 cookies 仅指 session饼干?我的理解是cookie就像一个媒介,它可以用来实现基于令牌的身份验证(在客户端存储可以识别登录用户的东西)或基于会话的身份验证(在客户端存储一个与服务器端上的会话信息相匹配的常量)

  2. 为什么我们需要 JSON 网络令牌?我使用标准 cookie 来实现基于令牌的身份验证(不使用会话 ID,不使用服务器内存或文件存储):Set-Cookie: user=innocent; preferred-color=azure,我观察到的唯一区别是 JWT 包含两者有效负载和签名...而您可以在 已签名或纯文本 cookie 之间选择 http 标头。在我看来,签名的 cookie (cookie:'time=s%3A1464743488946.WvSJxbCspOG3aiGi4zCMMR9yBdvS%2B6Ob2f3OG6%2FYCJM') 更节省空间,唯一的缺点是客户端无法读取令牌,只有服务器可以......但我认为这很好,因为就像 claim JWT 是可选的,token 没有必要有意义

【问题讨论】:

    标签: json authentication cookies jwt


    【解决方案1】:

    不记名令牌和 cookie 的最大区别在于浏览器会自动发送 cookie,其中不记名令牌需要显式添加到 HTTP 请求中。

    此功能使 cookie 成为保护网站的好方法,用户登录并使用链接在页面之间导航。

    浏览器自动发送cookies还有一个很大的缺点,就是CSRF攻击。在 CSRF 攻击中,恶意网站利用您的浏览器会自动将身份验证 cookie 附加到对该域的请求这一事实,并诱使您的浏览器执行请求。

    假设https://www.example.com 的网站允许经过身份验证的用户通过POST 将新密码更改为https://www.example.com/changepassword 来更改他们的密码,而无需发布用户名或旧密码。

    如果您在访问恶意网站时仍然登录到该网站,该网站会在您的浏览器中加载一个触发 POST 到该地址的页面,您的浏览器将忠实地附加身份验证 cookie,从而允许攻击者更改您的密码。

    Cookie 也可用于保护 Web 服务,但现在最常使用不记名令牌。如果您使用 cookie 来保护您的网络服务,则该服务需要存在于为其设置身份验证 cookie 的域中,因为 same-origin policy 不会将 cookie 发送到另一个域。

    此外,Cookie 使非基于浏览器的应用程序(如移动设备到平板电脑应用程序)更难以使用您的 API。

    【讨论】:

    • "如果您在访问恶意网站时仍然登录到该网站,该网站在您的浏览器中加载了一个触发 POST 到该地址的页面,您的浏览器将忠实地附加身份验证 cookie,允许攻击者更改您的密码。” CORS 不会阻止这种情况吗?
    • @kbuilds 只有恶意页面使用 AJAX 发布表单。如果攻击者让你点击常规表单上的提交按钮,CORS 就不会发挥作用。
    • 但这是否意味着该网站只有在没有使用 CSRF 令牌的情况下才会受到攻击?
    • 对,您可以使用 CSRF 令牌缓解 CSRF 攻击。但这是你必须明确做的事情。
    • 值得一提的是,Set-Cookie 的 SameSite 属性可以有效防止 CSRF 攻击。 developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/… 由于浏览器现在使用 SameSite=Lax 作为默认值,如果您不对 GET 请求进行更改,则默认情况下您会受到保护。但是,仅在现代浏览器的情况下。 SameSite=Strict 甚至是更强大的变体。一篇好文章值得阅读:netsparker.com/blog/web-security/…
    【解决方案2】:

    概述

    您要求的是 cookie 和不记名令牌之间的区别,用于将 JSON Web 令牌 (JWT) 从客户端发送到服务器。

    cookies 和不记名令牌都发送数据。

    一个区别是 cookie 用于发送和存储任意数据,而承载令牌专门用于发送授权数据。

    该数据通常被编码为 JWT。

    Cookie

    cookie 是一个名称-值对,存储在网络浏览器中,并具有到期日期和相关域。

    我们使用 JavaScript 或 HTTP 响应标头将 cookie 存储在网络浏览器中。

    document.cookie = 'my_cookie_name=my_cookie_value'   // JavaScript
    Set-Cookie: my_cookie_name=my_cookie_value           // HTTP Response Header
    

    网络浏览器会自动将 cookie 与每个请求一起发送到 cookie 的域。

    GET http://www.bigfont.ca
    Cookie: my_cookie_name=my_cookie_value               // HTTP Request Header
    

    Bearer Token

    不记名令牌是进入任何 HTTP 请求的 Authorization 标头的值。它不会自动存储在任何地方,它没有到期日期,也没有关联的域。这只是一个值。我们手动将该值存储在我们的客户端中,并手动将该值添加到 HTTP 授权标头中。

    GET http://www.bigfont.ca
    Authorization: Bearer my_bearer_token_value          // HTTP Request Header
    

    JWT 和基于令牌的身份验证

    当我们执行基于令牌的身份验证(例如 OpenID、OAuth 或 OpenID Connect)时,我们会从受信任的机构收到 access_token(有时是 id_token)。通常我们希望存储它并将其与受保护资源的 HTTP 请求一起发送。我们如何做到这一点?

    选项 1 是将令牌存储在 cookie 中。这会处理存储,并且还会在每个请求的 Cookie 标头中自动将令牌发送到服务器。然后服务器解析 cookie,检查令牌,并做出相应的响应。

    选项2是将令牌存储在本地/会话存储中,然后手动设置每个请求的Authorization标头。在这种情况下,服务器读取标头并像处理 cookie 一样继续。

    值得阅读链接的 RFC 以了解更多信息。

    【讨论】:

    • 将敏感数据存储到本地/会话存储中是否安全?或者它只是因为令牌是短暂的?
    • 一旦应用服务器收到 ID 令牌(其中包含声明),它会将该令牌发送到浏览器吗?这样后续的 api calla 可以传递该 id 令牌以允许应用服务器知道谁调用了端点。
    【解决方案3】:

    除了 MvdD 所说的关于自动发送 cookie 的内容:

    1. cookie 可以是一种媒介,但它最重要的功能是它如何与浏览器交互。 Cookie 由服务器设置并以非常特定的方式在请求中发送。另一方面,JWT 只是一种媒介,它是对特定结构中某些事实的断言。如果您愿意,可以将 JWT 作为您的身份验证 cookie。当您阅读比较它们的文章时,他们通常谈论的是使用由前端代码作为承载令牌发送的 JWT 与与后端的某些缓存会话或用户数据相对应的身份验证 cookie。
    2. JWT 提供了许多功能,并将它们置于标准中,以便各方之间使用。 JWT 可以在许多不同的地方充当某些事实的签名断言。 cookie,无论您在其中放入什么数据或是否对其进行签名,都只有在浏览器和特定后端之间使用才真正有意义。 JWT 可以用于从浏览器到后端,在不同方控制的后端之间(例如 OpenId Connect),或者在一方的后端服务中使用。关于您签名 cookie 的具体示例,您可能可以在该用例中实现与 JWT 相同的功能(“不使用会话 ID,不使用服务器内存或文件存储”),但您会失去库和同行评审该标准,除了在其他答案中谈到的 CSRF 问题。

    总而言之:您正在阅读的帖子可能是将 JWT 作为不记名令牌与身份验证 cookie 进行比较,以用于浏览器和服务器身份验证目的。但 JWT 可以做得更多,它带来了标准化和功能,可在您可能正在考虑的用例之外使用。

    【讨论】:

    • 很好地澄清了不记名令牌和cookie之间的比较。
    【解决方案4】:

    虽然 cookie 会随着请求自动发送而增加 CSRF 攻击的风险,但当设置 HttpOnly 标志时,它们可以降低 XSS 攻击的风险,因为任何脚本注入到页面中的将无法读取 cookie。

    CSRF:用户点击攻击者站点上的链接(或查看图像),导致浏览器向受害者站点发送请求。如果受害者使用 cookie,浏览器会自动在请求中包含 cookie,如果 GET 请求会导致任何非只读操作,则受害者站点很容易受到攻击。

    XSS:攻击者在受害站点中嵌入脚本(受害站点只有在输入未正确清理的情况下才容易受到攻击),并且攻击者的脚本可以执行 JavaScript 允许在页面上执行的任何操作。如果您将 JWT 令牌存储在本地存储中,攻击者的脚本可以读取这些令牌,并将这些令牌发送到他们控制的服务器。如果您使用带有HttpOnly 标志的cookie,攻击者的脚本将无法读取您的cookie。也就是说,他们成功注入的脚本仍然可以做 JavaScript 可以做的任何事情,所以你仍然会被 IMO 淹没(即,虽然他们可能无法读取 cookie 以将其发送到他们自己的服务器以供以后使用,他们可以使用 XHR 向受害网站发送请求,无论如何都会包含 cookie)。

    【讨论】:

    • 是否有任何解决方案不允许攻击者通过 localStorage 或发送带有 JWT 的 cookie 获取您的 JWT?
    • @DignityDignity 您可以将 JWT 存储在本地存储或 cookie 中(如 here 所述);我的回答只是提到 cookie 与不记名令牌是一种权衡(cookie 在某种意义上可能更安全,而在另一种意义上则更不安全)
    • CSRF 几乎是不可能的,因为 sameSite 的默认值是 lax。
    【解决方案5】:

    参考 - Need for JSON Web Token

    Cookies

    如果是 cookie,一旦用户通过身份验证,Gmail 服务器就会创建一个唯一的会话 ID。与此会话 ID 对应,它将在内存中存储 Gmail 服务器识别用户并允许其执行操作所需的所有用户信息。
    然后对于所有后续请求和响应,此会话 ID 也将被传递。所以现在当服务器收到请求时,它会检查会话 ID。使用此会话 id 将检查是否有任何相应的信息。然后它将允许用户访问资源并返回响应以及会话 ID。

    Cookie 的缺点

    • Cookie/会话 ID 不是自包含的。它是一个参考令牌。在每次验证期间,Gmail 服务器都需要获取与其对应的信息。
    • 不适用于涉及多个 API 和服务器的微服务架构

    智威汤逊

    • JWT 是自包含的。它是一种价值代币。因此,在每次验证期间,Gmail 服务器不需要获取与其对应的信息。
    • 它经过数字签名,因此如果有人修改它,服务器就会知道它
    • 最适合微服务架构
    • 它还有其他优点,例如指定过期时间。

    【讨论】:

    • 如果用户点击“让我退出所有会话”,那么对于每个请求,令牌都必须通过数据库调用进行验证——因此它是独立的想法不成立。短期到期可能会有所帮助,但并不完美。
    猜你喜欢
    • 2016-09-21
    • 2015-10-29
    • 1970-01-01
    • 2016-06-01
    • 2018-05-10
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 2021-02-08
    相关资源
    最近更新 更多