0%

jwt伪造

前言:

之前有碰到过好几次,没想着整理,最近在重新补基础就一起写了。

一、JWT

简介

JSON Web Token(JSON Web令牌):通过JSON形式作为Web应用中的令牌,用于在各方之间安全地将信息作为JSON对象传输。并且在传输过程中可以对数据进行加密、签名等处理。

结构

这里推荐一个平台https://jwt.io/。利用这个平台可以快速查看jwt的头部和payload

jwt的结构分为三个部分

1
2
3
头部(Header): eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
有效载荷(payload): eyJ1c2VybmFtZSI6IlRHMXUifQ
签名(Signature):E6_aosK_r4woX4_yxoxoSjA7L-vvwjqPSmRxAaNnjEo

三个部分利用.拼接在一起类似于xxxx.xxxx.xxxx格式,上面三个部分拼接在一起:

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRHMXUifQ.E6_aosK_r4woX4_yxoxoSjA7L-vvwjqPSmRxAaNnjEo

头部(Header)

头部包含两部分信息:

  • 声明token类型typ。

  • 声明加密的算法alg,通常直接使用HMAC、SHA256、RSA。(如果“alg”字段设为“ None”,那么JWT的第三部分会被置空,这样任何token都是有效的。这样就可以无需secret伪造token进行随意访问)

将头部进行base64加密就构成了第一部分

有效载荷(payload)

payload有三部分组成

1、注册声明(一般实战中才会有)

1
2
3
4
5
6
7
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

2、公共声明

可以添加任何信息,一般会添加用户的一些信息,但是不建议添加敏感信息。(这部分无需secret就可以解密出来了)

3、私有声明

由发行者和消费者之间私有使用的声明,不会被共享给其他发行者或消费者。这些声明主要用于在特定应用场景下传递一些特定的信息,仅限于发行者和消费者之间使用‌.

1
2
3
4
{
“username”: "TG1u", //公共声明
"admin": true //私有声明
}

签证(Signature)

需要知道header、payload、secret、alg才能得到签证

以HMAC SHA256算法为例

1
2
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret');

通过HMAC SHA256算法结合secret进行加盐签名(私钥加密),其中header和payload将通过base64UrlEncode()方法进行base64加密,然后通过字符串拼接"."生成新字符串,最终生成JWT的第三部分。

二、JWT伪造

一般secret都不会给到客户端,所以如果需要伪造jwt的话,就需要利用一个工具jwt-cracker来获取secret。

jwt-cracker下载后进行配置npm install --global jwt-cracker

下面随便给出一个JWT令牌

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRHMXUifQ.E6_aosK_r4woX4_yxoxoSjA7L-vvwjqPSmRxAaNnjEo

首先就是放入到jwt.io平台查看头部和payload

可以看到是存在secret的,所以无法直接伪造。

jwt-cracker

利用jwt-cracker进行爆破

1
2
3
4
5
6
7
jwt-cracker -t <token> [-a <alphabet>] [--max <maxLength>] [-d <dictionaryFilePath>] [-f]

//token:需要破解的完整HS256-512JWT令牌字符串
//alphabet:用于暴力破解的字母表(默认值://“abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”)
//maxLength:暴力破解过程中生成的字符串的最大长度(默认值:12)
//dictionaryFilePath:密码列表的路径(每行一个),用于代替暴力破解
//force:当令牌无效时强制执行脚本

具体使用

1
jwt-cracker -t eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlRHMXUifQ.E6_aosK_r4woX4_yxoxoSjA7L-vvwjqPSmRxAaNnjEo

可以看到爆破出的secret为SYSA

jwt.io

由于我的jwt.io在浏览器中有点问题,所以自己在本地部署了一个

1
2
3
4
5
6
7
8
9
10
11
// 下载
git clone [email protected]:jsonwebtoken/jsonwebtoken.github.io.git

// 安装所需的依赖项
npm install

// 构建项目
npm run build

// 运行开发服务器
npm run start

伪造jwt

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.9avq5ApZ-XZul2kbon8z2cB6Y4bNru_0nnIZfJ1mO50