JSON Web Token
文章目录
- JSON Web Token
- 知识点
- JWT攻击
- JWT攻击的影响
- JWT漏洞的产生
- JWT Lab
- Lab I: JWT authentication bypass via unverified signature(通过未验证签名绕过JWT身份验证)
- Lab II: JWT authentication bypass via flawed signature verification(通过有缺陷的签名验证绕过 JWT 身份验证)
- Lab III: JWT authentication bypass via weak signing key(通过弱签名密钥绕过 JWT 身份验证)
- Lab IV: JWT authentication bypass via jwk header injection(通过 jwk 标头注入绕过 JWT 身份验证)
- 预防JWT攻击
知识点
概念
JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种独立的方式,作为JSON对象在各方之间安全地传输信息。此信息可以被验证,因为它是经过数字签名的。JWT可以使用HMAC算法或使用RSA的公钥/私钥对进行签名。
JWT的作用场景
身份验证
这是使用JWT的典型场景,一旦用户登录,每个后续请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用JWT的一个特性,因为它的开销很小,并且能够在不同域的系统之间轻松使用。
信息交换
JWT是在各方之间安全传输信息的好方法,因为它们可以签名,例如使用公钥/私钥对,可以确定发送者是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此还可以验证内容是否被更改。
JWT的结构
JWT以点 . 分割三部分,它们分别是:
- 标头
- 有效载荷
- 签名
因此,JWT通常表示为:xxxxx.yyyyy.zzzzz,接下来分别看一下每一部分
标头
标头通常由两部分组成:typ令牌的类型,即JWT,以及alg消息验证算法,这里使用的典型加密算法是采用HS256(HMAC+SHA-256)和采用RS256 (RSA + SHA-256)。这个JSON被Base64Url编码以形成JST的第一部分
{
'typ': 'JWT',
'alg': 'HS256'
}
这里解释一下alg参数里的两种算法:首先是第一种HS256(HMAC+SHA-256),它使用的是"对称"密钥,这意味着服务器使用单个密钥来签署和验证令牌。显然,这个密钥对于整体的安全性非常重要。
第二种RS256 (RSA + SHA-256),它使用的是"非对称"密钥对。这包括服务器用来签署令牌的私钥和可用于验证签名的公钥。顾名思义,这里的私钥必须保密,但公钥通常是共享的,这样任何人都可以验证服务器发布的令牌的签名。
有效载荷
令牌的第二部分是有效载荷,其中包含声明。声明是关于实体(通常是用户)和附加元数据的陈述。JWT规范定义了七个注册声明名称,它们是令牌中通常包含的标准声明。通常还包含自定义声明,具体取决于令牌的用途。
标准声明包括
代码 | 名称 | 描述 |
---|---|---|
iss | 发行人 | JWT的发布者 |
exp | 有效时间 | JWT的有效时间 |
sub | 主语 | JWT 的主语 |
aud | 用户 | JWT发给哪个终端,可以是终端类型或用户名称 |
nbf | 在此之前不可用 | JWT开始被接受处理的时间 |
iat | 发布时间 | JWT的发布时间 |
jti | JWT ID用于标识该JWT | 区分Token大小写的唯一标识符 |
下边的示例包含标准声明Issue At Time(iat)和自定义声明(loggedInAs)
{
"iss": "portswigger",
"exp": 1648037164,
"name": "Carlos Montoya",
"sub": "carlos",
"role": "blog_author",
"email": "carlos@carlos-montoya.net",
"iat": 1516239022
}
签名
签名用于验证JWT令牌的安全性,并确保消息不会被更改。签名的生成过程使用标头中指定的算法对Base64Url编码后的标头、有效负载、密钥(secret)按以下公式对其进行签名,这里标头中的算法默认使用HMAC SHA256。
HMACSHA256(
base64UrlEncode(header) + '.' +
base64UrlEncode(payload),
secret)
分别对这三部分进行Base64url编码,并使用**.**连接以生成JWT:
const token = base64urlEncoding (标头) + '.' + base64urlEncoding (有效载荷) + '.' + base64urlEncoding (签名)
下面显示了一个JWT,它对前面的标头和有效负载进行了编码,并使用密钥进行了签名。
这个生成的令牌可以在HTML和HTTP环境中轻松传递
JWT的工作流程
在身份验证中,当用户使用其凭据成功登陆时,将返回一个JSON Web Token。之后该令牌就成为浏览器和服务器之间传输信息的凭据,因此需要严格按照到期时间来限制令牌的保留时间。由于缺乏安全性,我们不应该将敏感信息存储在浏览器存储中。
每当浏览器想要访问受保护的路由时,它都应该发送JWT,令牌通常保存在Bearer模式中。标头的内容为Authorization: Bearer <token>
。这是一种无状态身份验证机制,因为用户状态永远不会保存在服务器内存中。服务器的路由将检查Authorization标头中是否存在有效的JWT,如果存在,则允许用户访问。由于JWT是独立的,所有必要的信息都在那里,减少了返回和转发到数据库的需要。
优势
这里对比一下JWT相较于简单网络令牌(Simple Web Tokens,SWT)和安全断言置标语言(Security Assertion Markup Language Tokens, SAML)的优势。
简洁性
由于JSON比XML更简洁,因此在编码时它的大小也更小;使 JWT 比 SAML 更紧凑。这使得JWT成为在HTML和HTTP环境中传递的不错选择。
安全性
安全方面,SWT只能通过使用HMAC算法的共享密钥进行对称签名。而JWT和SAML令牌也可以使用X.509证书形式的公钥/私钥对来签名。然而与JSON签名的简单性相比,使用XML数字签名很难不引入隐蔽的安全漏洞。
易使用性
JSON解析器在大多数编程语言中都很常见,因为他们直接映射到对象,相反,XML没有自然的文档到对象映射。这使得使用JWT比使用SAML更容易。并且JWT在Internet范围内使用,这凸显了客户端在多个平台(尤其是移动平台)上处理JWT的便利性。
JWT攻击
JWT攻击涉及用户将修改后的JWT发送到服务器以实现恶意攻击。通常,此类攻击是通过模拟另一个已经经过身份验证的用户来绕过身份验证和访问控制。
JWT攻击的影响
JWT攻击的影响通常很严重,如果攻击者能够使用任意值创建自己的有效令牌,他们可能会提升自己的权限或冒充其他用户,从而完全控制他们的帐户。
JWT漏洞的产生
JWT漏洞通常是由于应用程序本身的JWT处理有缺陷而引起的.与JWT相关的各种规范在设计上相对灵活,允许网站开发人员自行决定许多实现细节。这可能会导致他们意外地引入漏洞,即使在很常用的库中也是如此。
这些实施缺陷通常意味着JWT签名未正确验证,这使攻击者能够篡改令牌中传给应用程序的payload。即使签名得到了可靠的验证,它是否真正可信在很大程度上取决于服务器的秘密密钥是否保密。如果此密钥以某种方式泄露,或者可以被猜测或暴力破解,则攻击者可以为任意令牌生成有效签名,从而破坏整个机制。
JWT Lab
Lab I: JWT authentication bypass via unverified signature(通过未验证签名绕过JWT身份验证)
服务器通常不会存储有关他们发出的JWT的任何信息。相反,每个令牌都是一个完整独立的实体。这样做引入了一个基本问题——服务器实际上不知道令牌的原始内容,甚至不知道原始签名是什么。因此,如果服务器没有正确验证签名,就无法阻止攻击者对令牌的其余部分进行任意更改。下边这个实验就解释了这个问题:
这个实验室简单来说,就是让我们登入用户wiener,然后修改令牌值,获得管理员权限后删除用户carlos
整体流程
1.用户登录
首先以wiener用户权限登陆
这里跳转到我的账户,在跳转过程中需要用到JWT令牌
2.获取JWT令牌
使用Burpsuite截取JWT令牌
这里第一个**‘.‘到第二个’.’**之间存放的是payload也就是我们需要改动的地方,这里的iss是令牌的发行者,sub是令牌的主语,exp是令牌的有效时间,这里尝试将sub更改为admin,更改后payload为:eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluIiwiZXhwIjoxNjY5MjEwNTUzfQ%3d%3d
3.修改payload得到管理权限
这里提示我们没有登陆为administrator,我们尝试修改sub为’administrator’,更改后payload为:eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6ImFkbWluaXN0cmF0b3IiLCJleHAiOjE2NjkyMTA1NTN9
成功进入admin后台管理界面
4.删除用户
按照要求点击删除carlos用户,完成Lab,这一步仍然需要在burpsuite中完成,否则会显示没有管理员权限
顺利完成~
Lab II: JWT authentication bypass via flawed signature verification(通过有缺陷的签名验证绕过 JWT 身份验证)
JWT可以使用一系列不同的算法进行签名,但也可以不签名。在这种情况下,alg参数设置为none,表示"不安全的JWT",但服务器通常会拒绝没有签名的令牌。但是,由于这种过滤依赖于字符串解析,我们可以使用经典的混淆技术(例如混合大小写和意外编码)绕过这些过滤器。
这个实验室简单来说,就是让我们登入用户wiener,然后修改标头的值,绕过签名对payload的验证,获得管理员权限后删除用户carlos
整体流程
1.用户登录
首先以wiener用户权限登录
2.修改JWT
这一关包含了对payload的简单验证(这里猜测是用签名验证payload是否被更改),所以不能直接修改payload获取管理员权限,可以尝试先删除JWT第三部分签名,然后将第一部分标头中的alg消息验证算法改为none(注:虽然删去签名但JWT中的第二个**‘.’**不能删除,否则会报错),标头改为{"typ":"JWT","alg":"none"}
,最后记得修改payload中的sub项
3.删除用户
成功进入admin后台管理界面,剩下的和第一关基本一样(注:这里进入Burpsuite后的操作模仿上一步)
Lab III: JWT authentication bypass via weak signing key(通过弱签名密钥绕过 JWT 身份验证)
一些签名算法,例如HS256(HMAC+SHA-256),使用任意的独立字符串作为密钥,但这个密钥不能轻易被攻击者猜到或暴力破解。否则,他们可能能够使用他们喜欢的任何标头和有效负载创建JWT,然后使用密钥重新签署具有有效签名的令牌。
在实施JWT应用程序时,开发人员有时会忘记更改默认密钥。在这种情况下,攻击者很容易使用hashcat暴力破解JWT的密钥。
这个实验室简单来说,就是让我们登入用户wiener,然后破解得到签名中的密钥值,之后可以随意修改payload的值,获得管理员权限后删除用户carlos
整体流程
1.用户登录
首先以wiener用户身份登录
点击My account获取JWT令牌
2.破解哈希值得到密钥
成功使用Burpsuite截取到JWT令牌
这一关我们先尝试用hashcat来破解令牌的第三部分签名,这里-a 0指破解模式为按字典破解,-m 16500指需要破解的哈希值为JWT格式,最后破解得出签名用到的密钥值为secret1
接下来使用破解得到的密钥值更改payload中的sub值为administrator,得到新的JWT令牌值
在Burpsuite中更新JWT令牌,并更改id和ur值(注:其实我们也可以在浏览器F12中更新JWT令牌,也可以起到提权效果)
3.提权并删除用户
成功以admin权限进入
进入Burpsuite,更改JWT令牌,删除用户carlos,完成Lab
Lab IV: JWT authentication bypass via jwk header injection(通过 jwk 标头注入绕过 JWT 身份验证)
整体流程
1.用户登录
首先以wiener用户身份登录
2.获取JWT令牌
进入后台页面点击my-account,并进入Burpsuite的JSON Web Token中操作JWT令牌
这里给出的JWS是JWT的一种实现方式,也就是说JWS和JWT的结构是一致的
3.修改JWS标头
这里准备修改JWS的标头信息,这里首先生成RSA私钥,然后将公钥保存在JWT的标头中,每次只需用验证公钥的安全性即可,这里利用自己构造的公钥可以直接修改payload
生成完成后选择RSA密钥,重新构造JWS标头
构造完成得到新的JWS标头
{
"kid": "c164cfd3-49c9-417f-8054-234ca76b2d76",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "c164cfd3-49c9-417f-8054-234ca76b2d76",
"n": "nb32Jfze-FcP5jcuOwibZat41PuqC2BYGwTQmfQJlXcwweYZjsQuOMYu1a5aOJpC-mCd-VmcxXerMx-JFpy4rDz8FePjdoKIlCLvTudgU2UxBObSHqHiyJcqKASr3dP5uGYGD_yCj1ZvH7HU0vQgytV9M9nmiNvwEFaG0BhGYluAViiAtp5DZhkDx22Xpppt-JCiO6iZ60ac0ZFBvmVR1EjED7mnGN8t3SSsuEiXQ1GyJ4wv2C1GwLTK8NYccP5CPdJbrB2aUioWrrWnGwcvy2-HgzTMoU-zBOv53iYOaKrzLNnVidPTJGOdkl2ynB10opZhCn6hCXq9YEoHkN9cMw"
}
}
接下来可以修改payload中的sub为administrator,即可成功到admin权限
4.提权并删除用户
记得修改/admin和id值
进入Burpsuite,更改JWT令牌,删除用户carlos,完成Lab
预防JWT攻击
采用以下措施,可以避免网站免受以上的很多攻击:
- 尽可能避免在URL参数中发送令牌
- 确保对收到的任何JWT执行可靠的签名验证,并考虑到使用不常用算法签名的JWT
- 始终为所有发行的令牌设置到期时间
这里给出的几个几个攻击例子比较片面,之后碰到合适的还会继续更新