您的位置 首页 php

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

有关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注入或命令注入等漏洞。

 {    "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,然后将其提交给服务器并通过校验:

 base64UrlEncode(header) + "." + base64UrlEncode(payload)  

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

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

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

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

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

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

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

 header:{  "alg": "RS256",  "typ": "JWT"}payload:{  "id": "1337",  "username": "bizone",  "iat": 1594209600,  "role": "user"}  

转为JWT为:

 eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6InVzZXIifQ.YLOVSKef-paSnnM8P2JLaU2FiS8TbhYqjewLmgRJfCj1Q6rVehAHQ-lABnKoRjlEmHZX-rufHEocDxGUYiGMjMexUQ3zt-WqZITvozJ4pkvbV-mJ1nKj64NmqaR9ZkBWtmF-PHJX50eYjgo9rzLKbVOKYOUa5rDkJPHP3U0aaBXFP39zsGdOTuELv436WXypIZBeRq2yA_mDH13TvzegWCK5sjD4Gh177bCq57tBYjhGIQrDypVe4cWBPlvwFlmG8tdpWGu0uFp0GcbTAfLUlbTSuGROj88BY0XeUs0iqmGlEICES3uqNx7vEmdT5k_AmL436SLedE0VHcyxve5ypQ  

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

公钥:

 -----BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQAB-----END PUBLIC KEY-----  

私钥:

 -----BEGIN RSA PRIVATE KEY-----MIIEogIBAAKCAQEAnzyis1ZjfNB0bBgKFMSvvkTtwlvBsaJq7S5wA+kzeVOVpVWwkWdVha4s38XM/pa/yr47av7+z3VTmvDRyAHcaT92whREFpLv9cj5lTeJSibyr/Mrm/YtjCZVWgaOYIhwrXwKLqPr/11inWsAkfIytvHWTxZYEcXLgAXFuUuaS3uF9gEiNQwzGTU1v0FqkqTBr4B8nW3HCN47XUu0t8Y0e+lf4s4OxQawWD79J9/5d3Ry0vbV3Am1FtGJiJvOwRsIfVChDpYStTcHTCMqtvWbV6L11BWkpzGXSW4Hv43qa+GSYOD2QU68Mb59oSk2OB+BtOLpJofmbGEGgvmwyCI9MwIDAQABAoIBACiARq2wkltjtcjskFvZ7w1JAORHbEufEO1Eu27zOIlqbgyAcAl7q+/1bip4Z/x1IVES84/yTaM8p0goamMhvgry/mS8vNi1BN2SAZEnb/7xSxbflb70bX9RHLJqKnp5GZe2jexw+wyXlwaM+bclUCrh9e1ltH7IvUrRrQnFJfh+is1fRon9Co9Li0GwoN0x0byrrngU8Ak3Y6D9D8GjQA4Elm94ST3izJv8iCOLSDBmzsPsXfcCUZfmTfZ5DbUDMbMxRnSo3nQeoKGC0Lj9FkWcfmLcpGlSXTO+Ww1L7EGq+PT3NtRae1FZPwjddQ1/4V905kyQFLamAA5YlSpE2wkCgYEAy1OPLQcZt4NQnQzPz2SBJqQN2P5u3vXl+zNVKP8w4eBv0vWuJJF+hkGNnSxXQrTkvDOIUddSKOzHHgSg4nY6K02ecyT0PPm/UZvtRpWrnBjcEVtHEJNpbU9pLD5iZ0J9sbzPU/LxPmuAP2Bs8JmTn6aFRspFrP7W0s1Nmk2jsm0CgYEAyH0X+jpoqxj4efZfkUrg5GbSEhf+dZglf0tTOA5bVg8IYwtmNk/pniLG/zI7c+GlTc9BBwfMr59EzBq/eFMI7+LgXaVUsM/sS4Ry+yeK6SJx/otIMWtDfqxsLD8CPMCRvecC2Pip4uSgrl0MOebl9XKp57GoaUWRWRHqwV4Y6h8CgYAZhI4mh4qZtnhKjY4TKDjxQYufXSdLAi9v3FxmvchDwOgn4L+PRVdMwDNms2bsL0m5uPn104EzM6w1vzz1zwKz5pTpPI0OjgWN13Tq8+PKvm/4Ga2MjgOgPWQkslulO/oMcXbPwWC3hcRdr9tcQtn9Imf9n2spL/6EDFId+Hp/7QKBgAqlWdiXsWckdE1Fn91/NGHsc8syKvjjk1onDcw0NvVi5vcba9oGdElJX3e9mxqUKMrw7msJJv1MX8LWyMQC5L6YNYHDfbPF1q5L4i8j8mRex97UVokJQRRA452V2vCO6S5ETgpnad36de3MUxHgCOX3qL382Qx9/THVmbma3YfRAoGAUxL/Eu5yvMK8SAt/dJK6FedngcM3JEFNplmtLYVLWhkIlNRGDwkg3I5Ky18Ae9n7dHVueyslrb6weq7dTkYDi3iOYRW8HRkIQh06wEdbxt0shTzAJvvCQfrBjg/3747WSsf/zBTcHihTRBdAv6OmdhV4/dD5YBfLAkLrd+mX7iE=-----END  RSA  PRIVATE KEY-----  

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

8885031e149d46bead3db4ee49df1719

 header:{ "typ": "JWT",  "alg": "HS256"}payload:{  "id": "1337",  "username": "bizone",  "iat": 1594209600,  "role": "admin"}  

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

 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6ImFkbWluIn0  

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

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

2a30974d493c43a9add1b7ac62e4fd1f

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

f7706a2623e1483a918ad6f3c72fbde2

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

 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjEzMzciLCJ1c2VybmFtZSI6ImJpem9uZSIsImlhdCI6MTU5NDIwOTYwMCwicm9sZSI6ImFkbWluIn0.E1R1nWNsO-H7h5WoYCBnm6c1zZy-0hu2VwpWGMVPK2g  

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

52c0006f080e4ccfa21ed36e74a0ced5

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

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

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

参考文档:

  1. #Pastebin/

文章来源:智云一二三科技

文章标题:一文理解JWT鉴权登录的安全加固

文章地址:https://www.zhihuclub.com/46724.shtml

关于作者: 智云科技

热门文章

网站地图