JSON Web Token(JWT) 简称JWT
1、头部
2、payload 数据
3、验证签名
{
"alg": "None",
"typ": "jwt"
}
#alg
#是说明这个JWT的签名使用的算法的参数,常见值用HS256(默认),HS512等,也可以为None。HS256表示HMAC SHA256。
#typ
#说明这个token的类型为JWT
[
{
"iss": "admin",
"iat": 1649316004,
"exp": 1649323204,
"nbf": 1649316004,
"sub": "user",
"jti": "2df98b5b4695c8a6a555a74ab1566e3f"
}
]
#下方是声明部分一些常见的键,其中一些键不是必须的
#iss:发行人
#exp:到期时间
#sub:主题
#aud:用户
#nbf:在此之前不可用
#iat:发布时间
#jti:JWT ID用于标识该JWT
下面是一个用HS256生成JWT的代码例子的结构 HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret)
#头部base64.数据段base64 然后加上自己的一个密钥 构成了一个jwt认证
1、用户端登录,用户名和密码在请求中被发往服务器 2、(确认登录信息正确后)服务器生成JSON头部和声明,将登录信息写入JSON的声明中(通常不应写入密码,因为JWT的声明是不加密的),并用secret用指定算法进行加密,生成该用户的JWT。此时,服务器并没有保存登录状态信息。 3、服务器将JWT返回给客户端 4、用户下次会话时,客户端会自动将JWT写在HTTP请求头部的Authorization字段中 5、服务器对JWT进行验证,若验证成功,则确认此用户的登录状态
稍稍解释下,就是客户端登录,带着一些账号密码等信息,服务器接收并判断登录成功后,通过秘钥生成jwt返回给浏览器,在之后每次客户端发请求都会带上jwt表示身份,然后服务器验证令牌并根据身份匹配权限,对行为进行相应。
JWT最常用的两种算法是HMAC和RSA。
HMAC(对称加密算法)用同一个密钥对token进行签名和认证。
RSA(非对称加密算法)需要两个密钥,先用私钥加密生成JWT,然后使用其对应的公钥来解密验证。
解密: https://jwt.io/
通常用该网站进行解密
科普完了,正好在刷ctfshow(再次安利一波)
这类题目我本身做的也不多,实战的话,实习时候在公司遇到过,不过不好拿出来放到博客。
就先演示ctfshow吧,会一直更新
查看源码发现有admin 我直接访问是会跳转到首页的。
auth参数貌似就是jwt,这里我直接base64解密看看
jwt头部的加密方式是None。所以这是一个jwt不加密验证漏洞。 JWT支持将算法设定为“None”。如果“alg”字段设为“ None”,那么签名会被置空,这样任何token都是有效的。
alg字段设置为“None”就可以伪造我们想要的任何token,接着便可以使用伪造的token冒充任意用户登陆网站。
直接把user改为admin 在进行base64编码后提交给cookie 访问admin 直接提交发现get flag。
跟上题类似,我这边直接url访问admin发现还是会跳转到首页,看下cookie 把auth参数拿去官网解密一下看看
第一反应应该是一个弱密钥,爆破一下试试看
这个脚本可以进行解密,和伪造jwt https://github.com/ticarpi/jwt_tool
python3 jwt_tool.py <jwt值> -C -d <字典>
填上密钥并修改 sub的值为admin重新生成了jwt 替换掉
此题目给了源码
发现公私钥都放在了public文件夹下面,nodejs中可以直接访问此文件。直接访问私钥
这回看一下jwt解码的结果。
加密为RS256 非对称加密 利用私钥生成 jwt ,利用公钥解密 jwt。
而 HS256这种对称加密,双方之间仅共享一个密钥,要千万注意密钥不要被泄露。
既然我们已经拿到了私钥,我就用Python生成jwt
import jwt
#payload
token_dict = {
"user":"admin"
}
#headers
headers = {
'alg':"RS256",
}
#私钥
key = open('private.key','r').read()
jwt_token = jwt.encode(payload=token_dict,key=key,algorithm='RS256',headers=headers)
print(jwt_token)
这里补充下 我用Python最开始无法生成加密后的jwt后来发现是 加密版本很低
pyjwt 2 需要 加密包版本稍高
python3 -m pip install --upgrade cryptography
拿来解密发现没任何问题
直接替换 并用post请求
这题直接给了源码。
源码里面呢也附带了 公钥
这题属于是密钥混淆攻击 。
如果将算法RS256修改为HS256(非对称密码算法=>对称密码算法)?
那么,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。
直接用上面的Python脚本去改,也会生成响应的jwt但是,提交到题目却拿不到flag,猜测难道是
jwt在python和nodejs的库不同。
直接用node
const 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)
npm install jsonwebtoken 安装模块 node jwt.js 运行
其实直接使用jwt.io也是可以的,但是经过测试如果密钥较复杂,例如有换行,粘贴到jwt.io以后会被替换为空格,最后导致结果不正确,所以直接采用了node,方便快捷。