算法混淆攻击
翻译
原文:https://portswigger.net/web-security/jwt/algorithm-confusion
- name: 翻译
desc: 原文:https://portswigger.net/web-security/jwt/algorithm-confusion
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 1算法混淆攻击
算法混淆攻击(也称为密钥混淆攻击)发生时,攻击者可以强制服务器使用不符合预期的算法来验证 JSON Web Token(JWT (opens new window))签名。如果处理不当,攻击者就可以伪造包含任意值的有效 JWT,而无需知道服务器的私有签名密钥。
# 2对称与非对称算法
对 JWTs 进行签名时,可以使用一系列不同的算法。其中某些算法使用 “对称” 密钥,例如 HS256(HMAC + SHA-256),这意味着服务器将会使用 单个密钥 来对令牌进行签名和验证。显然,这个密钥的机密性需要得到保证,就像密码一样。
另一些算法使用 “非对称” 的密钥对,例如 RS256(RSA + SHA-256)。这对密钥是由一个私钥 和 一个与数学相关的公钥组成的,服务器使用私钥对令牌进行签名,而公钥可用于验证签名。
顾名思义,私钥必须保密;公钥通常是共享的,以便任何人都可以对 服务器颁发的令牌签名 进行验证。
# 3算法混淆漏洞是如何产生的?
算法混淆漏洞通常是由于 JWT 库的实现有缺陷而产生的。尽管实际的验证过程因所使用的算法而异,但许多库都提供了一种与算法无关的单一方法来验证签名。这些方法依赖于令牌标头中的alg
参数,根据参数值来确定应执行哪种类型的验证。
下面的伪代码展示了一个简化版的示例,说明了这个通用方法verify()
在 JWT 库中的大致写法:
function verify(token, secretOrPublicKey){
algorithm = token.getAlgHeader();
if(algorithm == "RS256"){
// Use the provided key as an RSA public key
} else if (algorithm == "HS256"){
// Use the provided key as an HMAC secret key
}
}
2
3
4
5
6
7
8
随后,假设网站开发人员使用此方法,用来处理非对称算法(如 RS256)所签名的 JWTs,就会出现问题。由于使用了非对称算法,他们可能总是会将一个 固定的公钥 传递给该方法,如下所示:
publicKey = <服务器公钥>;
token = request.getCookie("session");
verify(token, publicKey);
2
3
此时,如果服务器收到另一个由对称算法(如 HS256)所签名的令牌,则库中的通用方法verify()
会将原本的公钥视为 HMAC 密钥。这意味着,攻击者可以使用 “HS256算法 + 公钥” 对令牌进行签名,而服务器将会使用相同的公钥来验证该签名。
(译者加:
- 原本是 “私钥签名 + 公钥验证”(非对称算法 两个密钥)
- 然后变成了 “(HS256公钥加密) + (HS256公钥解密)”(变成对称算法 就一个公钥) )
笔记
这个对令牌进行签名的公钥,必须与服务器上存储的公钥完全相同。需要包括相同的格式(如 X.509 PEM)并保留任何非打印字符(如换行符)。在实践中,你可能需要多次尝试不同的格式,才能使此攻击生效。
# 4实现算法混淆攻击
算法混淆攻击通常涉及以下高级步骤:
- 获取服务器的公钥
- 将公钥转换为合适的格式
- 生成一个恶意 JWT,修改其有效信息一栏,并且
alg
标头设置为HS256
。 - 使用 HS256 对令牌进行签名,将公钥作为密钥。
在本节中,我们将更详细地介绍此过程,演示如何使用 Burp Suite 执行此类攻击。
# 4.1步骤1-获取服务器的公钥
有时,服务器会映射标准端点/jwks.json
或/.well-known/jwks.json
,将公钥作为一个 JSON Web Key(JWK)对象进行公开。这些公钥存储在一个称为keys
的 JWKs 数组中,称为 JWK Set(JWK 集合)。
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
},
{
"kty": "RSA",
"e": "AQAB",
"kid": "d8fDFo-fS9-faS14a9-ASf99sa-7c1Ad5abA",
"n": "fc3f-yy1wpYmffgXBxhAUJzHql79gNNQ_cb33HocCuJolwDqmk6GPM4Y_qTVX67WhsN3JvaFYw-dfg6DH-asAScw"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
即使公钥没有被公开,你也可以从一对现有的 JWTs 中提取它 (opens new window)。
# 4.2步骤2-将公钥转换为合适的格式
虽然服务器会以 JWK 格式公开其公钥,但在验证令牌的签名时,服务器会使用本地文件系统 或 数据库中存储的密钥副本。在这些数据存储系统中,公钥可能会以不同的格式进行存储。
为了攻击顺利,用来对 JWT 进行签名的公钥 必须 与服务器的本地副本相同。除了采用相同的存储格式以外,公钥的每个字节都必须相匹配,包括任何非打印字符。
在本例中,假设我们需要 X.509 PEM 格式的公钥。你可以使用 Burp 中的 JWT Editor (opens new window) 扩展将 JWK 转换为 PEM 格式,过程如下:
- 加载扩展程序后,从 Burp 的主选项卡转到 “JWT Editor Keys” 选项卡。
- 单击 “New RSA Key”。在对话框中,粘贴你之前获得的 JWK。
- 单击 “PEM” 按钮并复制生成的 PEM 密钥。
- 转到 “Decoder” 选项卡并对 PEM 进行 Base64 编码。
- 返回到 “JWT Editor Keys” 选项卡,然后单击 “New Symmetric Key”(新建对称密钥)。
- 在对话框中,单击 “Generate” 以 JWK 格式生成新密钥。
- 复制第四步中经过 Base64 编码的 PEM 密钥,用其替换
k
参数的值。 - 保存密钥。
# 4.3步骤3-修改你的JWT
当你有了合适格式的公钥之后,只需将alg
标头设置为HS256
,你就可以随心所欲地修改 JWT (opens new window)。
# 4.4步骤4-使用公钥对JWT进行签名
使用 HS256 算法对令牌进行签名 (opens new window),并将 RSA 公钥作为本次的密钥。
- name: 实验室-专家
desc: 通过算法混淆绕过JWT身份验证 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/jwt/algorithm-confusion/lab-jwt-authentication-bypass-via-algorithm-confusion
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6
# 5从现有令牌中导出公钥
在公钥不容易获得的情况下,你也许可以从一对现有的 JWTs 中推导出公钥,然后测试算法混淆。使用jwt_forgery.py
等工具可以让此过程变得相对简单。你可以在rsa_sign2n
的 GitHub 存储库 (opens new window)中找到它,其中还包含其他一些有用的脚本。
我们还创建了此工具的简化版本,你可以将其作为单个命令来运行:
docker run --rm -it portswigger/sig2n <token1> <token2>
笔记
你需要使用 Docker CLI 来运行这个工具。首次运行此命令时,它会自动从 Docker Hub 拉取镜像,这可能需要几分钟的时间。
该工具会使用你提供的 JWTs 来计算一个或多个潜在的值n
。不要太关心 “n” 指的是什么 - 你只需要知道,其中只有一个n
值会与服务器上的公钥相匹配。对于每个潜在值,我们的脚本都会输出:
- 两个经过 Base64 编码的 PEM 公钥,分别采用 X.509 和 PKCS1 格式。
- 两个伪造的 JWT 签名,分别使用每个公钥生成。
若想要识别正确的密钥,请在请求中包含每个伪造的 JWTs,并依次使用 Burp Repeater 发送,服务器只会接受其中的某一个请求。然后,你可以使用匹配公钥来构造算法混淆攻击。
- name: 实验室-专家
desc: 通过算法混淆绕过JWT身份验证-无公开的密钥 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/jwt/algorithm-confusion/lab-jwt-authentication-bypass-via-algorithm-confusion-with-no-exposed-key
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6
有关此攻击过程、以及如何规范使用jwt_forgery.py
工具的详细信息,请参阅存储库 (opens new window)中提供的文档。