【翻译】不要再比较Cookies和JWT

文章讨论了JWT、Cookies、WebStorage在身份验证中的角色和安全风险,包括XSS和CSRF攻击。它强调了JWT作为令牌的一种格式,不应用于与Cookies的直接比较,而应关注基于会话和基于令牌的身份验证的区别。同时,提出了防止CSRF攻击的策略,如使用Same-siteCookies和CSRF令牌,以及如何在JWT中集成CSRF防护机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很多人对于cookies,sessions,基于令牌的身份验证(token-based authentication)和JWT这些术语存在着一些混淆和不理解
今天,我想谈谈当人们提到“JWT vs Cookie”、“Local Storage vs Cookies”、“Session vs token-based authentication”和“Bearer token vs Cookie”时,人们究竟是想比较什么呢?

提示一下 - 我们应该停止比较JWT和Cookies!

在接下来的内容中,我将先介绍什么是XSS和CSRF攻击,以及如何使用JWT和CSRF令牌实现基于令牌的身份验证,从而防范这些攻击。

让我们开始吧!

关键术语

首先我们需要了解一些关键术语以及它们之间的差异

客户端

客户端应用程序,在本文中,我们专门讨论网络浏览器,例如Firefox,Brave,Chrome,等等

服务端

幕后默默运转的机器。。

请求/响应头(Request/Response Headers)

HTTP头信息,注意不区分大小写

Cookie

也称作HTTP cookie,web cookie,浏览器cookie,是服务器发送给客户端的一小段信息。

Cookies 存储在浏览器的 Cookies Storage中,通常用于身份验证、个性化和跟踪。

Cookie是通过 Set-Cookie 响应头,以kv对的形式设置的。浏览器接收cookie,并且将自动保存在浏览器的 Cookies Storage中(document.cookie)。
Cookie的一个例子,你自己要注意别公开你的JWT(图上的JWT已经过期了)
注意:设置了HttpOnly, Secure, 和 SameSite=Strict 属性的Cookies会更加安全

例如,设置了HttpOnly属性,Cookies就无法通过JavaScript获取,因此可以防止XSS攻击。

可以在MDN上阅读更多内容并查看其他属性的功能(它们都非常实用)

XSS攻击

XSS也就是所谓的“跨站脚本攻击“

在Web开发中,通过JavaScript可以在相同的域内访问Web Storage(例如Local Storage)。然而,这也使得Web存储容易受到XSS攻击。简单来说,XSS攻击是一种漏洞类型,攻击者通过在页面上注入恶意的JS代码,从而获取用户信息或进行其他攻击行为。

基本的XSS攻击可以通过表单注入JS代码,例如攻击者会将alert(localStorage.getItem(‘your-secret-token’))这段代码放入表单中,如果浏览器运行这段代码,攻击者就能成功获取存储在本地存储中的敏感数据。此外,如果攻击者在表单中注入的代码可以在其他用户的浏览器中运行,那么他们也可以看到这些数据,这是非常危险的。

如果想进一步了解XSS,请观看这个视频

CSRF攻击

CSRF就是“跨站请求伪造”攻击

Cookies容易受到CSRF攻击,由于浏览器会自动在所有请求中发送Cookies,攻击者可以利用此特性,来获取对受信任站点的认证访问。如果需要更多解释,请查看:“简单易懂的CSRF原理

要在使用Cookies(SameSite=None)的情况下保护您的站点免受CSRF攻击,请看这个回答

另外这里也介绍了有关预防CSRF的知识,虽然比较枯燥

如果仍然不了解CSRF,请看这个“CSRF详解”视频

Cookies Storage

Cookies Storage,是一种客户端存储方式,用于存储 HTTP Cookies
需要注意的是,浏览器会在每个请求中自动发送 Cookie,无需客户端代码,通过 cookie 请求头来实现。这也正是 Cookies 存储易受 CSRF 攻击的原因所在。
将 Cookie 设置 HttpOnly 标志时,可以有效地降低 XSS 攻击的概率
请添加图片描述

Web Storage

包括Local Storage和Session Storage,是一种客户端存储机制,通常用于以键值对的形式存储数据。
Local Storage可用于永久保存数据,即使浏览器关闭或计算机重新启动也不会丢失。而Session Storage则只在当前会话中保留数据,一旦用户关闭了浏览器选项卡或浏览器窗口,存储的数据就会被删除。

尽管 Web Storage 是一种非常方便的客户端存储机制,但它们也存在一些安全风险。与 Cookies 不同,Web Storage 的数据无法在浏览器请求中自动发送。然而,由于 Web Storage 是通过 JavaScript 在客户端中访问的,因此它们容易受到 XSS 攻击的影响。攻击者可以通过注入恶意脚本来访问和篡改存储在 Web Storage 中的敏感数据。因此,不建议将私有、敏感或身份验证相关的数据存储在 Web Storage 中。
你可以用JS获取Local Storage中的任意数据
查看LocalStorage:F12 → ‘Application’ → ‘Storage’ → ‘Local Storage’ / ’Session Storage’
有关Web Storage的更多信息请查看MDN

Cookies (Storage) vs Web Storage

LOCAL/SESSION STORAGECOOKIES (STORAGE)
JavaScript同域下可通过 JavaScript 访问当 Cookies设置了 HttpOnly 标志时,就不能通过 JavaScript 访问
XSS attacks容易受到XSS攻击设置HttpOnly标志后不易收到XSS攻击
CSRF attacks不易收到CSRF攻击容易受到CSRF攻击
缓解措施不要将私有、敏感或身份验证相关的数据存储在 Web Storage为了防止 CSRF 攻击,开发人员应该使用 CSRF token或其他预防措施

JWT

全称“JSON Web Tokens”,常用于身份验证和授权

JWT是一个开放标准(RFC 7519),意味着JWT是一个通用的token格式

通常,JWT存储在Local Storage或者Cookies (storage)中

请记住,JWT不以任何方式加密。相反,它是以Base64编码的。尝试在jwt.io上解码任何JWT

为什么使用JWT

JWT一般是配合“基于令牌的身份验证(Token-based Authentication)”使用,这时使用JWT的系统将更容易水平扩展

为什么?因为验证JWT不需要服务器和数据库之间的任何通信。换句话说,身份验证可以是无状态的

请查阅Auth0的文档以获取更多信息。

停止比较JWT和Cookies

请停止比较JWT和Cookie,因为它们本身都代表完整的身份验证机制。

JWT只是一种令牌格式,而Cookie实际上是一种HTTP状态管理机制。

正如我们所说,Web Cookie可以包含JWT,并且可以存储在浏览器的Cookies存储中。

因此,我们需要停止比较JWT和Cookie。这是因为它们具有不同的用途和功能,不能简单地进行比较。JWT用于在客户端和服务器之间传递信息,而Cookie用于管理HTTP状态并存储会话信息。在实际应用中,它们可能会被同时使用,但它们的作用是不同的。

基于会话的身份验证vs基于令牌的身份验证(Session-based vs Token-based Authentication)

我们实际上应该问的问题是:基于令牌(token)身份验证和基于会话(session)身份验证之间的区别是什么?

TOKEN-BASEDSESSION-BASED
无状态有状态
服务端不存储身份验证状态服务端存储身份验证状态
易于水平扩展不易于水平扩展
一般通过JWT做认证一般通过Session ID做认证
通常通过HTTP请求头(例如Bearer)发送到服务器,也可以使用Cookies传递令牌将Session ID作为Cookies请求头发送到服务器
相对于基于会话的身份验证,撤销用户令牌身份验证更加困难相对于基于令牌的身份验证,撤销用户会话更加容易

Cookie vs Bearer Tokens

现在我们知道了Cookie的工作原理,接下来让我们了解一下“Bearer tokens”这个术语。让我们假设我们将使用JWT作为我们的身份验证令牌。

所谓的“Bearer token”是一个字符串(例如JWT),它放置在HTTP请求的Authorization头中。与浏览器Cookie不同,它不会自动存储在任何地方,从而使跨站请求伪造攻击(CSRF)成为不可能。

GET http://www.example.com
Authorization: Bearer my_bearer_token_value // HTTP Request Header

要使用“Bearer token”,我们需要明确地将JWT存储在客户端的某个位置(Cookies Storage或Local Storage),并在请求时将该JWT添加到HTTP Authorization头中。

如果你的Cookies(例如带有JWT的Cookies)设置了HttpOnly标志,那么将无法使用JavaScript获取令牌。

等等,我们可以使用本地存储(Local Storage)来存储JWT吗?

请记住,使用本地存储(Local Storage)会使我们的JWT容易受到跨站脚本攻击(XSS)的攻击。因此,你会经常听到人们强烈建议不要将JWT存储在本地存储中。

此时,Cookie似乎是我们唯一的选择。但是请记住,这使我们的网站容易受到跨站请求伪造攻击(CSRF)的攻击。

CSRF防范

Same-site Cookies

Same-site Cookies可以有效地防止CSRF攻击,但这也带来了其他问题

假设不使用Same-site Cookies,还有以下的办法

常见的CSRF防范方法

不考虑JWT,以下是两种最常见的CSRF防范方法:

  • 同步令牌模式(Synchronizer token pattern)
  • Cookie-to-header-token模式
    请查看这个StackOverflow答案,以获得上述两种方法的快速摘要。

很好。但现在出现了一个问题 - 我们如何使用JWT实现这一点呢?

修改后的“Cookie-to-header token”方法

老实说,我不太确定这种方法是否有一个合适的名称。我从Hubert Sablonnière的这个关于100%无状态JWT(JSON Web Token)的精彩演讲中发现了这种方法。我强烈、强烈地建议你去看一看。它值得你花一个小时去了解。

简而言之,修改后的方法(在我看来)与原始的Cookie-to-header token方法相似,但有一些调整:

  • anti-CSRF令牌在单独的响应头(例如X-CSRF-Token)中返回,而不是在Set-Cookie响应头中返回
  • 在Set-Cookie响应头上设置JWT
    上述实现可以在Cloudflare Worker demo和GitHub上找到(就是原作者的demo)
    (附:Cloudflare Worker demoGitHub的地址)

解释:

  1. 用户登录后,服务器将使用csrfToken作为JWT声明的一部分签署JWT(用于在步骤6中进行验证)。

    {
    "email": "your@email.com",
    "exp": 1666798498,
    "csrfToken": "1449bd3e-41c2-45cb-a538-73c7ad80ca2c",
    "iat": 1666794898
    }
    

    生成的csrfToken应该是不可预测的,并且对于每个用户会话应该是唯一的。

  2. JWT将以字符串形式存入Cookie,设置在Set-Cookie响应头中。另一方面,随机生成的csrfToken将设置在X-CSRF-Token响应头中。

  3. 随着Set-Cookie头被设置,浏览器将自动将JWT存储在Cookies(存储)中。X-CSRF-Token头中的csrfToken将被提取并设置在浏览器的Local Storage中。

  4. 当触发请求(例如GET /hello)时,浏览器将从Local Storage中获取csrfToken。

  5. 从Cookies(存储)中获取的JWT和从Local Storage中获取的csrfToken将放入请求头,并发送到服务器。

  6. 服务器将验证JWT,并检查请求头中的csrfToken是否与JWT中的csrfToken声明相匹配,以验证CSRF令牌是否有效。

原作者的Demo

上一节中的时序图其实就来自原作者的demo,图后给出了github的地址

另外为了测试CSRF攻击,可以利用这个小工具
并且原作者也创建了一个名为csrf-attack-demo的分支,可以在本地运行它,以模拟对网站的CSRF攻击。

总结

实际上,只要身份验证不是自动进行的(例如使用浏览器中的Cookies),就不必担心CSRF攻击。

例如,如果应用程序通过Authorization头附加身份验证凭据,则CSRF就是不可能的,因为浏览器无法自动验证请求。

最后要注意,我们不能简单地说某种解决方案一定比另一个更好,而应该考虑每种身份验证方式的优缺点,并根据我们的需求和情况选择合适的方式。

原文链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值