前言
依旧是Java安全的内容,今天主要是讲JWT这个东西,JWT之前讲过了,是Java中特有的身份校验机制,原理我就不再多说了,主要是看看它的安全问题,至于Swagger和Druid顺便讲一下。
Druid泄露
Druid是阿里巴巴数据库事业部出品,为监控而生的数据库连接池。Druid提供的监控功能,监控SQL的执行时间、监控Web URI的请求、Session监控。当开发者配置不当时就可能造成未授权访问漏洞。

可以看到里面有sql监控,就是执行了哪些sql语句。

还有session监控,就是会显示已经登录的用户的session,因为我这里只是简单演示一下,就啥也没有。

那么它主要的危害就是信息泄露,直接拼接URL路径,尝试能否直接未授权访问系统功能点。

结合泄露URL路径和Session信息,利用BurpSuite进行尝试登录。也就是说有了登录地址,也有用户的session,那么我就可以以这个用户的身份去登录。

Swagger自动化
这个之前也是讲过的,就是Swagger给开发者提供了一个接口测试的页面,将项目中所有(想要暴露的)接口展现在WEB页面上,并可以进行接口调用和调式的服务(一般都是用SpringBoot框架搭建该服务)

我们来批量的去测试一下,因为太多的话手动测不过来,postman导入Swagger地址。

成功导入,然后批量去测试即可。

接着讲一下postman和BP的联动,其实就是设置一个代理就行,postman代理设置和BP一样即可。

再次运行可以看到BP这边有大量的数据包,这时就可以利用BP上的插件去进行漏洞探测,还可以联动一些漏扫,如Xray,这个后续再说了。

JWT攻防
首先来了解一下JWT的组成。
1、标头(Header)
Header是JWT的第一个部分,是一个JSON对象,主要声明了JWT的签名算法,如"HS256"、"RS256"等,以及其他可选参数,如"kid"、"jku"、"x5u"等
alg字段通常用于表示加密采用的算法。如"HS256"、"RS256"等(HS对称加密、RS非对称加密)
typ字段通常用于表示类型
还有一些其他可选参数,如"kid"、"jku"、"x5u"等
2、有效载荷(Payload)
Payload是JWT的第二个部分,这是一个JSON对象,主要承载了各种声明并传递明文数据,用于存储用户的信息,如id、用户名、角色、令牌生成时间和其他自定义声明。
iss:该字段表示jwt的签发者。
sub:该jwt面向的用户。
aud:jwt的接收方。
exp:jwt的过期时间,通常来说是一个时间戳。
iat:jwt的签发时间,常来说是一个时间戳。
jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问
3、签名(Signature)
Signature是对Header和Payload进行签名,具体是用什么加密方式写在Header的alg 中。同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
第一部分:对 JSON 的头部做 base64 编码处理得到
第二部分:对 JSON 类型的 payload 做 base64 编码处理得到
第三部分:分别对头部和载荷做base64编码,并使用.拼接起来
使用头部声明的加密方式,对base64编码前两部分合并的结果加盐加密处理,作为JWT
JWT识别
识别我们可以人工识别,就是直接看cookie的格式就行,也不算难,就是要一个一个数据包来看有点麻烦罢了。

还可以用BP中的插件来自动化识别,这个比较简单快速,自带的插件有JSON Web Tokens,就在
BP商店里面。但是我这里下载不了,说我BP版本不够高,好吧,那就不演示这个插件了。

还有一个插件就是Hae,但是需要自己去下载导入BP,BP商店没有自带。但是我这里啥也没识别出来,不知道为啥,访问的网站明明是有JWT,妈的。

接着来讲一下JWT常见的安全问题,分别是空加密算法、未校验签名、暴力破解密钥、源码泄漏密匙。
空加密算法
签名算法可被修改为none,JWT支持将算法设定为"None"。如果"alg"字段设为"None",那么签名会被置空,这样任何token都是有效的,这里直接用CTFshow里面的题目来讲解,先来看web345。

查看源码得知叫我们访问admin。

抓包发现有JWT。

拿去解密一下,发现我们sub的值是user,sub上面我们说过是该JWT面向的用户,那么这题估计是要admin身份才能拿到flag。

注意到这里的alg为None,也就是说没用到加密算法,我们可以直接修改。这里有个坑,直接在这个网站修改的话是空白的,并不会给你生成修改后的JWT。

我们可以直接在BP上面进行base64解码,可以看到是能解出来数据的,因为第一和第二部分是用base64进行加密的。

我们修改user为admin之后再进行base64加密,就得到新的JWT了,然后替换掉原来的JWT即可得到flag。

未校验签名
某些服务端并未校验JWT签名,可以尝试修改payload后然后直接请求token或者直接删除signature再次请求查看其是否还有效。
来看CTFshow的Web346。

抓包解密JWT,我们发现这里的alg设置为HS256了,不再是空加密。那么此时我们直接把user改为admin肯定是不行的,因为你没有秘钥是无法解密的。

这时候就有两个思路,要么就爆破HS256的秘钥,要么就把alg改为空再去除签名,因为它如果不去校验第三部分的签名的话,那么有没有这一部分其实没影响的,这里我们要用到一个工具去修改。
https://github.com/ticarpi/jwt_tool
先输入命令让它先去解析你的JWT,我这里有点小乱码,但是问题不大,可以看到能成功解析出数据。
项目命令帮助
#解析JWT
python3 jwt_tool.py your_JWT
# 使用None算法
python3 jwt_tool.py your_JWT -X a
# 自定义修改生成
python3 jwt_tool.py your_JWT -T
# 使用字典破解
python3 jwt_tool.py your_JWT -C -d dictionary.txt
# 指定密码测试
python3 jwt_tool.py your_JWT -C -p password_here

接着自定义修改,我们选择1,对alg进行修改。

提示叫我们输入新的值,输入None,把alg算法修改为空。

改完之后输入0,结束对头部的修改,进入下一步去修改payload。

我们选择5,修改user为admin,修改完之后输入0结束修改,就会生成一个新的JWT。

然后我们用新生成的JWT去替换原来的JWT去发包,结果还是不行。

这是为啥呢,上面说过如果"alg"字段设为"None",那么签名会被置空,这样任何token都是有效的,也就是说不会校验你的签名,所以直接把签名删除再发包即可。

秘钥爆破
这种情况就是虽然它用了加密,但是秘钥过于简单,爆破一下就出来,这里用Web347进行演示。

解密JWT可以看到用了HS256进行加密。

我们利用工具进行秘钥的爆破,爆破出秘钥为123456。

剩下的直接来到网站改就行,秘钥天123456,user改为admin即可。

信息泄露
有时候秘钥的泄露或者加密源码的泄露,也会造成安全问题,利用web349进行演示。

扫下目录发现有个私钥泄露。

直接下载来看一下。

然后又从题目中下载了源码,通过分析源码我们可以知道是通过私钥加密,公钥解密。

现在我们已经知道私钥了,那么我们直接进行修改加密即可,记得安装PyJWT库才行。
import jwt
public = open('private.key', 'r').read() //读取当前目录下的私钥
payload={"user":"admin"} //user的值设置为admin
print(jwt.encode(payload, key=public, algorithm='RS256'))

用生成的JWT替换掉原本的JWT即可,记得改为POST提交方式,因为源码中的解密是要POST去提交。

web350也是信息泄露,不过这题有点意思。

直接把源码包下载下来看看,可以看到也是私钥加密,公钥解密的。

但是问题是它源码中只给出了公钥,没有给出私钥啊,如果我们用公钥加密的肯定是解密不出来的。怎么办呢,我们都知道RSA是两个密钥一个加密一个解密,而上面说到的HS256加解密都是同一个密钥,现在我们只知道一个密钥,那我们是不是可以修改alg的值为HS250,那么这时我们公钥加密再公钥解密完全是没问题的。
var jwt = require('jsonwebtoken');
var fs = require('fs');
var privateKey = fs.readFileSync('./public.key');
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
利用JS代码生成新的JWT。

利用新生成的JWT替换掉原本的即可,记得改为POST请求。

总结
主要讲了JWT的安全问题,总的来说就那么几种方式利用,空算法、密钥爆破、签名未校验。关于Druid和Swagger以后讲到接口安全再细讲了。
最后,以上仅为个人的拙见,如何有不对的地方,欢迎各位师傅指正与补充,有兴趣的师傅可以一起交流学习。