一、JWT介绍
JWT全称为Json Web Token,简单理解为用于在客户端和服务端通过Json格式传递鉴权信息,其与Session所不同的是,JWT不需要存储在服务端,而是每次请求时客户端都会携带JWT到服务端,服务端经过计算验证,确定该JWT信息是否是合法的,从而进行鉴权。
JWT是一串BASE64编码,通过点号“.”分割成三部分,分别是Header,Claims,Signature,在https://jwt.io取一个例子,如下:
Header:header是一个JSON对象,主要描述了类型及HASH算法,类型通常为固定的JWT,而HASH算法可选,经过BASE64编码后得到,因此也可以通过BASE64解码得出具体的值;
如:{"alg":"HS256","typ":"JWT"}编码后得到:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9。
Claims:Claims是一个JSON对象,有的地方也称为Payload,主要描述了JWT Token所传输的元素,默认包括:
iss(issuer):签发人/发行人
sub(subject):主题
aud(audience):用户
exp(expiration time):过期时间
nbf(Not Before):生效时间,在此之前是无效的
iat(Issued At):签发时间
jti(JWT ID):用于标识该JWT
另外,还可以再根据自身的需求,再定义其他的原因。
Claims是一个JSON对象,通过BASE64进行编码,因此该部分也可以通过BASE64进行解码。如:{"sub":"1234567890","name":"John Doe","iat":1516239022},编码后得到eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ。
Signature:这是一个签名的部分,其计算方法为:HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret) ,即header的BASE64编码、点号、Clamis的BASE64编码以及将secret作为盐值,以前面申明的HASH算法进行计算,得到的一个值,该值具有不可逆性。
上述为JWT的简要介绍,JWT的设计是安全的,但是JWT使用不当,仍可能产生安全问题:
1、 header、claims仅进行了BASE64编码,是不能在里面存储敏感信息,否则会造成敏感信息泄露;
2、 signature部分本身是不可逆的,这是JWT安全性的保证的根本,但是若secret泄露,或者在代码中进行硬编码泄露、设置为了空密钥等,那么JWT也将不再安全,可以进行伪造;
3、 在header部分指定了signature的HASH算法,若后端程序代码在进行计算验证时不严谨,比如计算时,未包含secret,仍然会导致JWT失效;
4、 最后,signature是一个HASH值,通过加盐加强其安全性,但是若盐值不够强壮,那么使用爆破仍然会导致JWT失效。
下面通过OWASP 的WEBGOAT项目进行练习。
二、WebGoat reset votes 练习
使用普通用户tom进行Reset Votes操作,返回Only an admin user can reset the votes
获取access_token:
access_token=eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE2NTcxNDAyODIsImFkbWluIjoiZmFsc2UiLCJ1c2VyIjoiVG9tIn0.ahvoqLbmADZGJc6Xp4OW3BIA8n6BhPUEoF6fYkjnihZS_xoQoj7wh3dQQ134NBlqv2tporwaYh07Vznfv6HxhA;
在https://jwt.io/ 进行BASE64解码,如下:
HEADER:
{
"alg": "HS512"
}
PAYLOAD:
{
"iat": 1657140282,
"admin": "false",
"user": "Tom"
}
VERIFY SIGNATURE:
HMACSHA512(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
)
根据前面的报错信息,需要admin用户才可以进行重置操作,这里有两种方式可以尝试,一是找到签名的密钥,然后将PAYLOAD的admin的值修改为true,然后重新生成BASE64的JWT,并且使用密钥进行签名;第二种方式是直接去掉签名。
第一种方式:
1、 通过白盒查看签名的密钥。在前面抓包可以看到请求的URL为/WebGoat/JWT/votings,方法为POST,在IDEA中去查看源码,全局搜索jwt/votings,找到如下:
可以看到密钥为victory。
2、现在回到http://jwt.io,重新生成JWT,把admin的值修改为true,在密钥处填写victory,如下:
3、将左右生成的JWT复制后放到BURP替换原来的值,然后发送:
此时返回的信息可以看到已经重置成功。
如果我们没有通过白盒代码审计看到签名密钥呢,尝试一下不进行签名。
第二种方式:
1、 将通过BURP获取到的包中的access_token获取下来,解码:
2、 修改签名算法,如下:
{
"alg": "HS512"
}
修改为:
{
"alg": "none"
}
然后再进行BASE64编码得到ewogICJhbGciOiAibm9uZSIKfQo=,去掉后面的等号:
3、 修改JWT中PAYLOAD的admin的值为true,获取编码:
eyJpYXQiOjE2NTcxNDAyODIsImFkbWluIjoidHJ1ZSIsInVzZXIiOiJUb20ifQ
4、 整合BASE64编码,由于我们没有进行签名,因此不需要JWT的最后一部分,但是注意,要保留最后一部分前面的“.”,如下:
ewogICJhbGciOiAibm9uZSIKfQo.eyJpYXQiOjE2NTcxNDAyODIsImFkbWluIjoidHJ1ZSIsInVzZXIiOiJUb20ifQ.
5、 把新获得的JWT放到BURP中进行重放,可以看到重置成功。
第三种方式:
该方式和第二种方式差不多,不用修改算法,把PAYLOAD中的admin改为True,user改为admin,然后将签名部分删掉:
三、WebGoat JWT Cracking 练习
这个练习是根据要求对已知的JWT Token进行爆解,然后将其中的username字段的值修改为“WebGoat”,然后提交新的JWT Token:
将JWT Token复制出来进行解析,注意这里面是带时间戳的,token的有效期只有60秒钟,内容如下:
这一点从网页上的token也可以看出来,每一60秒刷新一次,JWT Token会变化。
根据网站上的提示,到GITHUB上下载google-10000-english.txt文件,然后将JWT Token复制出来,放到hashcat中进行爆破,如下:
hashcat -m 16500 /root/Desktop/jwt -a 3 -w 3 /root/Desktop/google-10000-english.txt
找到密钥为: washington
由于爆破已经花了一定的时间,导致token失效了,到百度找一个时间戳转换器,查看当前时间,然后修改token的时间到有效期内:
设置正确的时间戳,修改username的值为WebGoat,填上爆破出来的密钥:washington
将左边的token复制到网站,提交后显示成功:
标签:总结,编码,admin,BASE64,JWT,token,密钥,安全性 From: https://blog.51cto.com/u_9652359/6318140