前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文理解JWT鉴权登录的安全加固

一文理解JWT鉴权登录的安全加固

作者头像
全菜工程师小辉
发布2021-04-28 14:27:44
1.3K0
发布2021-04-28 14:27:44
举报

有关JWT的基础知识,可以查看之前的博客: 快速了解会话管理三剑客cookie、session和JWT

在之前的博客《一文理解JWT在鉴权登录的应用》介绍了JWT在鉴权登录中的使用。但是不恰当地使用 JWT 可能会对应用程序安全产生负面影响。

本文将针对JWT在鉴权登录业务场景下的安全进行讲解。

JWT使用时的安全建议

1. 切勿在令牌中传输用户的敏感数据

由于JWT的载荷部分是可以被明文获取的,因此,如果有效载荷中存在敏感信息的话,就会发生信息泄露。

2. 传输令牌时一定要使用安全连接

理由同上。

3. 使用“刷新令牌”机制

由于JWT是公开传输的,获取了令牌的黑客能够继续使用该JWT访问应用程序,所以使用最好双JWT机制降低安全风险。使用方法在《一文理解JWT在鉴权登录的应用》有详细讲解。

4. 增加JWT的业务参数,用于校验

可以在Payload中增加一些业务上的字段,用于校验当前JWT是否被滥用。例如增加设备号,用户uuid、权限的信息,可以与上下文的信息进行对照,提高爬虫的门槛与接口安全性。

5. 始终验证并过滤从用户接收的数据

kid是JWT header中的一个可选参数,它用于指定加密算法的密钥。因为该参数可以由用户输入,系统并不知道用户想要读取的到底是不是密钥文件。如果在没有对参数进行过滤的前提下,攻击者是可以读取到系统的任意文件的、造成SQL注入或命令注入等漏洞。

代码语言:javascript
复制
{
    "alg" : "HS256",
    "typ" : "jwt",
    "kid" : "/etc/passwd"
}
{
    "alg" : "HS256",
    "typ" : "jwt",
    "kid" : "key11111111' || union select 'secretkey' -- "
}

所以,验证并过滤从用户接收的数据是必要的。

6. 提高对称加密的秘钥强度

如果加密的密钥强度较弱的话,攻击者可以直接通过蛮力攻击方式来破解密钥,可以使用PyJWT、John Ripper或c-jwt-cracker进行破解测试。PyJWT库具体地址看参考文档4。c-jwt-cracker库集体地址看参考文档5。

秘钥不定期的变化。这对用户来说不太方便,因为他们将不得不再次通过身份验证,但这有助于避免安全问题的发生。

7. 服务端增加授权签名算法的白名单

签名算法可以确保JWT在传输过程中不会被恶意用户所篡改,但头部中的alg字段却可以改为None,即不使用签名算法。这样的话,当signature设置为空时,后端将不执行签名验证。

将alg字段改为none后,系统就会生成这样形式的JWT,然后将其提交给服务器并通过校验:

代码语言:javascript
复制
base64UrlEncode(header) + "." + base64UrlEncode(payload)

所以,有必要在服务端增加已授权算法的白名单,并删除所有与服务端上授权算法不同的签名算法的JWT。

8. 最好只使用一个签名算法

在使用非对称算法进行令牌签名的情况下,签名应使用私钥,而签名验证应使用公钥。由于使用JWT的某些库包含逻辑错误——当收到用对称算法签名的令牌时,将使用公钥作为验证签名的secret。由于公钥并不是秘密数据,因此黑客可能会获得公共服务密钥并用于签署自己的令牌。

所以,当网站采用非对称加密验证,且不对签名算法进行限制的话,存在这样的漏洞:

  1. 通过一定手段,获取到非对称加密的公钥,将alg字段改为对称加密算法。
  2. 使用公钥对JWT进行签名,发送给服务端。
  3. 服务端会将对称加密的公钥作为验证签名的秘钥,使用对称加密算法对接收的JWT进行验证。

为了说明这个问题,以下实验部分节选自参考文档7的部分内容:

使用非对称加密算法RS256,新建一个JWT如下:

代码语言:javascript
复制
header:
{
  "alg": "RS256",
  "typ": "JWT"
}
payload:
{
  "id": "1337",
  "username": "bizone",
  "iat": 1594209600,
  "role": "user"
}

转为JWT为:

代码语言:javascript
复制
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6InVzZXIifQ.YLOVSKef-paSnnM8P2JLaU2FiS8TbhYqjewLmgRJfCj1Q6rVehAHQ-lABnKoRjlEmHZX-rufHEocDxGUYiGMjMexUQ3zt-WqZITvozJ4pkvbV-mJ1nKj64NmqaR9ZkBWtmF-PHJX50eYjgo9rzLKbVOKYOUa5rDkJPHP3U0aaBXFP39zsGdOTuELv436WXypIZBeRq2yA_mDH13TvzegWCK5sjD4Gh177bCq57tBYjhGIQrDypVe4cWBPlvwFlmG8tdpWGu0uFp0GcbTAfLUlbTSuGROj88BY0XeUs0iqmGlEICES3uqNx7vEmdT5k_AmL436SLedE0VHcyxve5ypQ

在这种情况下,使用RS256算法签名,将需要公钥和私钥。

公钥:

代码语言:javascript
复制
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSv
vkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHc
aT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIy
tvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0
e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWb
V6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9
MwIDAQAB
-----END PUBLIC KEY-----

私钥:

代码语言:javascript
复制
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWw
kWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mr
m/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEi
NQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV
3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2
QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjs
kFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0go
amMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM
+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9
D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC
0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5Y
lSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+
hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNp
bU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X
+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9B
BwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC
2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjx
QYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz
5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9
Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0
NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j
8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma
3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5K
y18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrB
jg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=
-----END RSA PRIVATE KEY-----

为验证JWT有效性,使用参考文档2的网站如下图:

代码语言:javascript
复制
header:
{
 "typ": "JWT",
  "alg": "HS256"
}
payload:
{
  "id": "1337",
  "username": "bizone",
  "iat": 1594209600,
  "role": "admin"
}

转化为JWT的头部和载荷部分如下:

代码语言:javascript
复制
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6ImFkbWluIn0

现在只需要使用公钥读取签名。

首先,把密钥转移到十六进制表示法,如下图。

然后使用openssl生成一个签名,如下图。

将值e1r1nwnso-h7h5woycbnm6c1zzy-0hu2vwpwgmpk2g添加到网站上的“secret”中(记住选中“secret base64 encoded”),最终的JWT如下:

代码语言:javascript
复制
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6ImFkbWluIn0.E1R1nWNsO-H7h5WoYCBnm6c1zZy-0hu2VwpWGMVPK2g

正如网站显示的结果,JWT成功地通过了验证。

所以,最好只使用一种加密方式,防止类似的安全漏洞。

9. 选择知名且可靠的JWT库

网上有不少对JWT库的选型对比,由于这种建议具有时效性,本文不做推荐。

参考文档:

  1. https://github.com/auth0/java-jwt
  2. https://jwt.io/
  3. https://docs.aws.amazon.com/zh_cn/acm/latest/userguide/import-certificate-format.html
  4. https://github.com/jpadilla/pyjwt
  5. https://github.com/brendan-rius/c-jwt-cracker
  6. https://skysec.top/2018/05/19/2018CUMTCTF-Final-Web/#Pastebin/
  7. https://cyberpolygon.com/materials/security-of-json-web-tokens-jwt/
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 全菜工程师小辉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JWT使用时的安全建议
    • 1. 切勿在令牌中传输用户的敏感数据
      • 2. 传输令牌时一定要使用安全连接
        • 3. 使用“刷新令牌”机制
          • 4. 增加JWT的业务参数,用于校验
            • 5. 始终验证并过滤从用户接收的数据
              • 6. 提高对称加密的秘钥强度
                • 7. 服务端增加授权签名算法的白名单
                  • 8. 最好只使用一个签名算法
                    • 9. 选择知名且可靠的JWT库
                    相关产品与服务
                    多因子身份认证
                    多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档