惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cisco Talos Blog
Cisco Talos Blog
K
Kaspersky official blog
T
The Exploit Database - CXSecurity.com
NISL@THU
NISL@THU
AWS News Blog
AWS News Blog
V2EX - 技术
V2EX - 技术
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Security @ Cisco Blogs
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Recent Commits to openclaw:main
Recent Commits to openclaw:main
J
Java Code Geeks
Microsoft Azure Blog
Microsoft Azure Blog
Attack and Defense Labs
Attack and Defense Labs
Jina AI
Jina AI
The Last Watchdog
The Last Watchdog
W
WeLiveSecurity
H
Help Net Security
V
Visual Studio Blog
宝玉的分享
宝玉的分享
C
Cybersecurity and Infrastructure Security Agency CISA
T
Threat Research - Cisco Blogs
IT之家
IT之家
Hugging Face - Blog
Hugging Face - Blog
Latest news
Latest news
T
Tor Project blog
I
Intezer
美团技术团队
GbyAI
GbyAI
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
博客园 - 三生石上(FineUI控件)
Google DeepMind News
Google DeepMind News
Scott Helme
Scott Helme
Y
Y Combinator Blog
博客园 - 司徒正美
T
Tenable Blog
O
OpenAI News
N
News and Events Feed by Topic
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V
Vulnerabilities – Threatpost
P
Palo Alto Networks Blog
博客园 - 聂微东
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Threatpost
Google Online Security Blog
Google Online Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
云风的 BLOG
云风的 BLOG
Help Net Security
Help Net Security

Ray's Blog

Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog Ray's Blog
Ray's Blog
i@mk1.io (Ra · 2022-11-15 · via Ray's Blog

详解 JWT

这可能是旧博客的最后一篇文章了,之后会使用新博客系统。

创客七户社 征文。

阅读这篇文章前,我们假定你对 HTTP 稍有一些了解。

JWT,即 JSON Web Tokens。顾名思义,其为用于 Web 授权认证的一种令牌。它最为显著的特征为安全和“无状态”。

我们先来看看过去的几种认证方式。

在 Web 授权认证这一方面,我们最先使用的是 HTTP Basic Auth。这种方式优缺点都很明显,优点是简单易用,基本上所有流行的网页浏览器都支持,开发者只需要在服务器的响应中加上一行形如 WWW-Authenticate: Basic realm="Secure Area" 的响应头即可。但这种认证方式只对用户密码进行了近乎裸奔的 Base64 编码,且易被获取造成信息泄露,甚至可以发起中间人攻击,因此极少在生产环境中使用。

Cookie/Session 认证机制是一种较为安全的 Web 授权认证机制,其分为两大组成部分,即存储在客户端的 Cookie 和服务端的 Session。它的运行方式也十分简单,客户端发出一个登录请求,服务端记录下用户信息 (即 Session),并在响应中要求客户端记录下 Cookie。在用户发起请求时,Cookie 会一同发出,服务端便可基于此进行用户认证。

这种方式看似是一种完美的解决方式,但其实仍有不足之处。

首先,Session 存储于服务端,这就必然导致服务器资源的占用。倘若有大量用户或攻击者同一时间大量发起登录请求,服务器便要大量存储 Session,容易导致内存不足,甚至崩溃。同时,如果在 Session 中置入了较大的对象,也会产生较大的性能负担。Session 的服务端开发对于程序员来说也不是一件美事,过度使用 Session 会导致代码不可读而且不好维护。

既然 Basic 不安全,Session 又会给服务器造成大量负担,那该怎么办呢?

首先我们需要一个安全的认证方式,这个好办。我们只需要一个只存在于服务器的密钥对敏感信息进行加密就可以了。

其次是不能给服务器造成性能负担,那我们势必将登录信息存储于客户端。

由此,JWT 就诞生了。

部分内容来自 https://javaguide.cn/system-design/security/jwt-intro.html

我们可以在 jwt.io 上直观感受 JWT。JWT 是一种形如 xxxxx.yyyyy.zzzzz 的由服务器返回的字符串,其中 xxxxx 为 Header (描述 JWT 的元数据,定义了生成签名的算法以及 Token 的类型)、yyyyy 为 Payload (用来存放实际需要传递的数据),zzzzz 为 Signature (签名)(服务器通过 Payload、Header 和一个密钥 (Secret) 使用 Header 里面指定的签名算法 (默认是 HMAC SHA256) 生成)。

可以看出,JWT 本质上就是一组字符串,通过 . 切分成三个经过 Base64 编码的部分。

例如:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoic28xdmUiLCJwYXNzd29yZCI6bnVsbH0.zPEzTi2VzXpMTndG0k04QVddxaQ2Ermgw21skfyl1XWqdF5mdPoT6goQsk8XsAh40Twux-IHFl1RSYUeLuyCGQ

你可以在 这里 对它进行解码,可以得出其中包含的 Header、Payload 和 Signature。

Header 通常由两部分组成:

  • typ (type): 令牌类型,也就是 JWT。
  • alg (algorithm): 签名算法,比如 HS512。

示例:

{
  "alg": "HS256",
  "typ": "JWT"
}

JSON 形式的 Header 被转换成 Base64 编码,成为 JWT 的第一部分。

随后是 Payload。Payload 也是 JSON 格式数据,包含了 Claims(声明,包含 JWT 的相关信息)。在这里可以包含一些用户相关的信息,但请注意,默认情况下该部分并未进行加密,请不要存储隐私信息。

例如:

{
  "name": "so1ve",
  "password": null
}

这是一个很简单的例子,除了这些自定义的内容,我们还可以放置如下数据:

  • iss (issuer):JWT 签发方。
  • iat (issued at time):JWT 签发时间。
  • sub (subject):JWT 主题。
  • aud (audience):JWT 接收方。
  • exp (expiration time):JWT 的过期时间。
  • nbf (not before time):JWT 生效时间,早于该定义的时间的 JWT 不能被接受处理。
  • jti (JWT ID):JWT 唯一标识。

JSON 形式的 Payload 被转换成 Base64 编码,成为 JWT 的第二部分。

Signature 部分是对前两部分的签名,作用是防止 JWT(主要是 payload)被篡改。

这个签名的生成需要用到:

  • Header + Payload。
  • 存放在服务端的密钥(一定不要泄露出去)。
  • 签名算法。

签名的计算公式如下:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用.分隔,这个字符串就是JWT

使用 JWT 进行认证,大致可以简化为如下步骤:

  1. 客户端向服务器发起登录请求(用户名、密码,或许还有验证码?),服务器后返回一个包含用户信息(Payload 中)的 JWT 令牌。
  2. 客户端将这个 JWT 存放在自己的 localStorage(本地存储)中,并且在每次需要用户信息的请求中在请求头中携带上该令牌。Authorization: Bearer <JWT>
  3. 服务器接收到 JWT,并进行解密,利用自己的密钥检验 Signature,对用户权限进行判断。如果用户拥有访问该页面的权限,则返回相应内容。
  4. 客户端接收到响应内容。

可以看出,全程服务器乐的清闲,不需要本地存储用户信息,而是将工作交给浏览器。

前面我们提到,JWT 的弊病之一是 Payload 只经过 Base64 加密 (≈裸奔了),因此不能存储隐私信息。在一般情况下,客户端无需用户的隐私信息,如果必要,我们可以采用对 JWT 进行对称加密,用时再解密的方式来增加安全性。

另外,由于 JWT 被 JavaScript 存储在 localStorage 中,由于 JavaScript 的同源策略,网站下所有的 JavaScript 代码都可以访问同一个 localStorage,从而获取到 JWT,这就会带来注入的风险。

最后,网站一定要使用 HTTPS。如果只使用 HTTP,Token 在网络中明文传输还是存在泄露的风险。

此外,Web 授权认证还有 OAuth 等方式,在此不再多说。总而言之,JWT 是目前最流行也最优秀的 Web 授权认证方案。

开学就上高中了,之后更新的频率可能会降低不少,请见谅。