• JWT安全及案例实战



    越权与逻辑漏洞

    Web漏洞点只有一个入口:HTTP

    JWT 安全

    1. Cookie

    Cookie存放在浏览器中。

    cookie是一个非常具体的东西,指的就是浏览器里面能永久存储的一种数据,仅仅是浏览器实现的一种数据存储功能。

    cookie由服务器生成,发送给浏览器,浏览器把cookie以k,v形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

    2. Session

    Session存放在服务器中。

    session从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

    session也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用cookie的方式。

    服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

    3. Token

    在Web领域基于Token的身份验证随处可见。在大多数使用Veb API的互联网公司中,tokens是多用户下处理认证的最佳方式。

    以下几点特性会让你在程序中使用基于Token的身份验证

    1. 无状态、可扩展
    2. 支持移动设备
    3. 跨程序调用
    4. 安全

    4. JWT

    JWT(JSON Web Token)是一种用于在网络环境中进行身份验证和授权的开放标准。它使用 JSON 格式定义了一种安全的令牌传输格式。

    4.1 JWT概述

    image-20230913123939413

    该对象为一个很长的字符串,字符之间通过 “.” 分隔符分为三个子串。每一个子串表示了一个功能块,总共有以下三个部分:JWT头、有效载荷、签名。

    4.1.1 JWT头

    JWT头部分是一个描述JWT元数据的JSON对象(固定写法),通常如下所示:

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
    • 1
    • 2
    • 3
    • 4

    在上面的代码中,alg属性表示签名使用的算法,常见值用 HS256(默认),HS512 等。默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存。

    4.1.2 有效载荷

    载荷(Payload):载荷存储了有关用户或实体的声明和其他有关信息。

    • 声明:如用户ID、角色、权限等信息。
    • 注册声明:包含一些标准的声明(比如发行人、过期时间等)和一些自定义的声明。

    JWT指定七个默认字段供选择。

    iss:发行人
    exp:到期时间
    sub:主题
    aud:用户
    nbf:在此之前不可用
    iat:发布时间
    jti:JWT ID用于标识该JWT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20230913124904805

    载荷也使用 Base64Url 编码表示,并作为整个 JWT 的第二部分。载荷的一个示例:

    {
         "sub": "1234567890",
         "name": "John Doe",
         "iat": 1516239022
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:默认情况下JWT是未加密的(alg:none),任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。

    4.1.3 签名哈希

    签名(Signature):签名是对头部和载荷进行签名的结果,用于验证 JWT 的完整性和真实性。

    签名生成方式:将头部和载荷进行 Base64Url 编码后拼接在一起,然后使用指定的加密算法(如 HMAC、RSA)进行签名,将生成的签名添加到 JWT 中。

    4.1.4 通信流程

    image-20230913191519509

    JWT工作流:

    • 首先客户端需要向服务端申请JWT令牌,这个过程通常是登录功能。即:由用户名和密码换取JWT令牌。

    • 当你访问系统其他的接口时,在HTTP的header中携带JWT令牌。header的名称可以自定义,前后端对应上即可。

    • 服务端解签验证JWT中的用户标识,根据用户标识从数据库中加载访问权限、用户信息等状态信息。

    4.2 JWT 漏洞描述

    JWT在使用过程中可能存在以下几个主要漏洞:

    1. 令牌窃取:如果攻击者能够获取到有效的JWT,就可以使用该令牌冒充用户身份。
    2. 令牌篡改:由于JWT的内容不加密,攻击者可以篡改令牌的内容,例如修改有效载荷中的声明。
    3. 令牌伪造:攻击者可以通过构造自己的JWT来进行身份伪装,尤其是在使用对称算法进行签名时。
    4. 令牌过期失效问题:如果应用程序未正确处理JWT的过期问题,可能导致过期的JWT仍然可用。

    4.3 JWT 漏洞原理

    JWT漏洞的原理主要包括以下几个方面:

    • 窃取和篡改令牌:攻击者可以通过窃取用户的JWT或篡改有效载荷中的声明来冒充用户身份。

    • 伪造令牌:攻击者可以通过了解签名算法、密钥或公钥,构造自己的伪造JWT来进行身份伪装。

    • 无效的过期处理:应用程序在验证JWT时可能没有正确处理过期的令牌,导致过期的令牌仍然有效。

    4.4 JWT 安全防御

    1. 使用强大的密钥和算法:选择足够强大的加密算法和密钥长度,如HMAC-SHA256或RSA-2048等。使用长而随机的密钥可以增加JWT的安全性,并提高防止暴力破解和字典攻击的能力。
    2. 令牌有效期限制:设置合理的令牌过期时间。较短的过期时间可以减少令牌被滥用的风险。定期刷新和更新过期的令牌可以确保令牌的时效性和安全性。
    3. 验证令牌签名和完整性:在接收到JWT后,验证令牌的签名和完整性以确保其真实性。检查签名时使用的密钥和算法必须与发放JWT的一方保持一致。
    4. 避免在JWT中存储敏感信息:尽量避免在JWT的载荷中存储敏感信息,如密码、社会安全号码等。如果必须存储敏感信息,应使用加密技术对其进行加密。
    5. 加密敏感信息:如果需要在JWT中传输敏感信息,应使用加密算法对其进行加密。在加密前,确保选择合适的加密算法,并采取适当的密钥管理措施,确保加密信息的安全性。
    6. HTTPS传输:始终使用HTTPS来传输JWT,以保护令牌在传输过程中的安全性。HTTPS提供了端到端的加密传输,防止令牌被窃听或篡改。
    7. 令牌刷新和撤销机制:实施令牌刷新和撤销机制,以应对丢失、泄露或被盗用的令牌。可以使用黑名单、短有效期令牌或存储令牌的数据库来实现这些机制。
    8. 令牌审计和监控:建立令牌审计和监控系统,对令牌的使用进行监测和追踪。这有助于及时发现任何异常活动或未经授权的令牌使用。
    9. 密钥安全管理:安全地管理和存储用于签名和验证JWT的密钥。密钥应该存放在受保护的环境中,访问权限应限制在必要的人员范围内。

    5. WebGoat 靶场实验

    启动方式:

    java -jar webgoat-server-8.0.0.M17.jar --server.port=8888 --
    server.address=192.168.131.143
    
    • 1
    • 2

    image-20230913202102744

    浏览器访问路径如下

    127.0.0.1:8888/WebGoat
    
    • 1

    访问页面

    image-20230913154340377

    用户名:wuhu111

    密码:123456

    5.1 第四关

    本关是让我们使用管理员,然后重置所有的投票。

    image-20230913211938068

    点击删除然后使用bp抓取数据包

    image-20230913154641387

    发现的 JWT 值在Cookie字段中

    image-20230913155759362

    将 JWT字符串复制到 JWT 网址中进行解码,JSON Web Tokens - jwt.io

    image-20230913155700565

    使用网站工具将加密方式修改为none,这样他的加密方式就失效了。

    Base64加密、解密-BeJSON.com

    image-20230913160050808

    ewogICJpYXQiOiAxNjk1NDU1MTgwLAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0
    
    • 1

    修改payload数值将admin的值修改为true。

    image-20230913160007037

    ewogICJpYXQiOiAxNjk1NDU1MTgwLAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0
    
    • 1

    将这个两个base64加密后的字符串拼接在一起。

    注意:末尾的点,并且这里不需要签名。

    ewogICJhbGciOiAibm9uZSIKfQ.ewogICJpYXQiOiAxNjk1NDU1MTgwLAogICJhZG1pbiI6ICJ0cnVlIiwKICAidXNlciI6ICJUb20iCn0.
    
    • 1

    放包查看结果

    image-20230913155557280

    返回页面查看结果,重置成功。

    image-20230913160337446

    5.2 第五关

    本关先提供了一个 JWT,需要尝试找出密钥并提交。也就是需要我们爆破密钥。

    image-20230913203733043

    创建一个jwt.txt文件,然后将页面提供的JWT拷贝到里面

    image-20230913204017556

    然后输入如下命令来爆破密钥

    hashcat -m 16500 jwt.txt -a 3 -w 3 pass.txt
    
    • 1

    说明

    • -m 16500:这里的16500对应的是jwt的token爆破。
    • -a 3:代表蛮力爆破。
    • -w 3:可以理解为高数爆破,就是会让桌面进程无响应的那种高速。
    • jwt.txt :是把题目要求破解的token保存到的文件。
    • pass.txt :密码字典。

    image-20230913212717340

    提交密钥的时候还要将username修改为WebGoat,还要将时间戳修改为未过期。

    image-20230913205913796

    image-20230913205857342

    ewogICJpc3MiOiAiV2ViR29hdCBUb2tlbiBCdWlsZGVyIiwKICAiYXVkIjogIndlYmdvYXQub3JnIiwKICAiaWF0IjogMTY5NDYwODQ2NiwKICAiZXhwIjogMTY5NDY5MDc4MCwKICAic3ViIjogInRvbUB3ZWJnb2F0Lm9yZyIsCiAgInVzZXJuYW1lIjogIldlYkdvYXQiLAogICJFbWFpbCI6ICJ0b21Ad2ViZ29hdC5vcmciLAogICJSb2xlIjogWwogICAgIk1hbmFnZXIiLAogICAgIlByb2plY3QgQWRtaW5pc3RyYXRvciIKICBdCn0
    
    • 1

    然后将生成的这个payload复制到指定位置,并且添加验证签名,就是我们爆破出来的密钥victory。

    image-20230913213604564

    eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJhdWQiOiJ3ZWJnb2F0Lm9yZyIsImlhdCI6MTY5NDYwODQ2NiwiZXhwIjoxNjk0NjkwNzgwLCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJ1c2VybmFtZSI6IldlYkdvYXQiLCJFbWFpbCI6InRvbUB3ZWJnb2F0Lm9yZyIsIlJvbGUiOlsiTWFuYWdlciIsIlByb2plY3QgQWRtaW5pc3RyYXRvciJdfQ.5kvHTE2112tml-JaFMq4KDjaATs48cOAXPuD5dI9GyU
    
    • 1

    然后输入我们构造的JWT,通过成功

    image-20230913163327339

    5.3 第七关

    页面提示内容告诉我们要使用Tom用户付钱

    image-20230913193711653

    点击Checkout使用bp抓取数据包

    image-20230913193938529

    这关的JWT需要放在Authorization中,但是观察数据包,发现数据包中所有的字段都没有给我们提供JWT。

    那么我们点击页面中的here

    image-20230913194131618

    跳转到了一个页面,在页面中看到了JWT。这个页面是日志信息,这个靶场模拟的环境是想让tom用户付钱,但是没有有效的JWT,但是有一个日志泄露的点,从而找到JWT。

    image-20230913194151329

    eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q
    
    • 1

    然后将找到的 JWT 复制到刚刚抓取数据包中的Authorization字段中。

    image-20230913194913754

    发包后发现有报错信息,提示说我们的 JWT 过期了。

    image-20230913215233845

    将JWT复制到JWT网站中进行修改。

    image-20230913195204254

    生成一个没有过期的时间戳。

    image-20230913195524544

    将生成的时间戳对原先的exp中的内容进行替换。

    image-20230913195617268

    ewogICJpYXQiOiAxNTI2MTMxNDExLAogICJleHAiOiAxNjk0NjkwNzgwLAogICJhZG1pbiI6ICJmYWxzZSIsCiAgInVzZXIiOiAiVG9tIgp9
    
    • 1

    将加密方式修改为none

    image-20230913201320020

    ewogICJhbGciOiAibm9uZSIKfQ
    
    • 1

    最后将修改后JWT重新粘贴到Authorization字段中即可。

    ewogICJhbGciOiAibm9uZSIKfQ.ewogICJpYXQiOiAxNTI2MTMxNDExLAogICJleHAiOiAxNjk0NjkwNzgwLAogICJhZG1pbiI6ICJmYWxzZSIsCiAgInVzZXIiOiAiVG9tIgp9.
    
    • 1

    image-20230913201607828

    放包查看结果如下:

    image-20230913201647794

    6. CTFHub 真题

    链接地址:CTFHub.

    在历年真题页面搜索easy_login。

    image-20230924163005574

    环境启动,访问页面,这里我们注册一个账号

    image-20230924163151368

    image-20230924163208964

    然后点击GET FLAG,随后弹框说我们没有权限。

    image-20230924163256010

    返回登录界面,在登录的时候使用bp抓取数据包,发现数据包中请求体中有JWT字符串

    image-20230924163424543

    将JWT字符串复制到 JWT 网址中进行解码

    image-20230924163450281

    随后将JWT头部信息进行修改,将加密方式修改为none

    image-20230924163543572

    ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0
    
    • 1

    修改secretid和username字段。

    image-20230924163731648

    ewogICJzZWNyZXRpZCI6IFtdLAogICJ1c2VybmFtZSI6ICJhZG1pbiIsCiAgInBhc3N3b3JkIjogInd1aHUiLAogICJpYXQiOiAxNjk1NTQ0MzMxCn0
    
    • 1

    说明

    • secretid:密钥ID值为0,后面的签名会引用密钥的ID值来执行加密,修改为空[]。

    • username:用户名修改为admin。

    随后将修改后并加密了的字符串进行拼接。

    ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0.ewogICJzZWNyZXRpZCI6IFtdLAogICJ1c2VybmFtZSI6ICJhZG1pbiIsCiAgInBhc3N3b3JkIjogInd1aHUiLAogICJpYXQiOiAxNjk1NTQ0MzMxCn0.
    
    • 1

    在登录的时候进行抓包,修改数据包内容,将username修改为admin,密码不用修改,然后将构造的JWT字符串赋复制到authorization后面,发包即可。

    image-20230924164028473

    然后点击GET FLAG,继续使用bp抓取数据包

    image-20230924164410203

    这个时候直接点击放包,就可以发现flag。

    image-20230924164239920

    ctfhub{7f6ada4e7122ab061b722afa}
    
    • 1
  • 相关阅读:
    Teams Tab App 的 manifest 分析
    【MySQL | 运维篇】04、MySQL 分库分表之 MyCat 入门与配置
    Docker容器故障排查与解决方案
    基于springboot+vue专业手语翻译预约系统
    深入理解 Spring MVC 的工作原理
    1480. 一维数组的动态和
    【LeetCode】接雨水 II [H](堆)
    部署项目半途而废后续
    list的介绍及使用
    clion 中的undefined reference to 问题解决
  • 原文地址:https://blog.csdn.net/weixin_58783105/article/details/132868814