JWT 安全

cookie(放在浏览器)

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

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

session(放在服务器)

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

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

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

token

在 Web 领域基于 Token 的身份验证随处可见。在大多数使用 Web API 的互联网公司中,

tokens 是多用户下处理认证的最佳方式。

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

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

token采用加密的方式操作cookie值

jwt(json(数据格式) web token)

JWT(JSON Web Token)由三部分组成:头部(Header)、载荷(Payload)、签名(Signature)

头部(Header):头部通常由两部分组成,算法类型和令牌类型

算法类型:指定用于生成签名的算法,例如 HMAC、RSA 或者 ECDSA。

令牌类型:指定令牌的类型,常见的是 JWT。

头部使用 Base64Url 编码表示,并作为整个 JWT 的第一部分。

头部的一个示例:

{ "alg": "HS256",none #表示签名时使用的加密方式,none表示失效 "typ": "JWT"}

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

声明:如用户 ID、角色、权限等信息。

注册声明:包含一些标准的声明(比如发行人、过期时间等)和一些自定义的声明。

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

载荷的一个示例:

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

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

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

头部

alg

是说明这个 JWT 的签名使用的算法的参数,常见值用 HS256(默认),HS512 等,也可以为

None。HS256 表示 HMAC SHA256。

typ

说明这个 token 的类型为 JWT

payload

有载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明(建议但不强制使用):

  • iss: jwt签发者
  • sub:jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击

签名

服务器有一个不会发送给客户端的密码(secret),用头部中指定的算法对头部和声明的内容用

此密码进行加密,生成的字符串就是 JWT 的签名

搭建WebGoat靶场

前期准备

启动靶场

java -jar webgoat-server-8.1.0.jar --server.port=8888 --server.address=192.168.63.129(kali的IP

注意大小写

kali的IP:8888/WebGoat

访问靶场

注册用户名和密码

  • 登录成功

  • 开启JWT tokens靶场

WebGoat靶场通过

第4关

目的:伪造签名并清空

解题思路:

  • 修改 payload 数据,admin 修改为 true,将加密方式修改为 none

  • 加密,然后再解密

步骤:

首先登录Tom用户

选择一个并开始投票,发现可以一致投票

点击删除,提示只有admin用户才能清空

利用bp开始抓包

右击发送到Repeater

将cookie的值利用进行JWT解码

利用base64编码,将HS512改为nonefalse改为true

分别将修改后的base64编码放在Encoded中

将HEADER和PAYLOAD的Encoded放在bp的cookie中

提示已经成功完成任务

回到页面查看,删除成功

第5关

目的:修改 exp 有效时间

前期准备:

WebGoat的爆破密钥1.txt

步骤:

找到cookie值

用Encoded打开

将cookie值放入jwt.txt文档中

用管理员身份执行打开终端

hashcat -m 16500 jwt.txt -a 3 -w 3 1.txt --force#-m 16500 16500对应的就是 jwt 的 token 爆破;#-a 3 代表蛮力破解#-w 3可以理解为高速破解,就是会让桌面进程无响应的那种高速#jwt.txt是我把题目要求破解的 token 保存到的文件

爆破成功

将cookie值利用base64编码进行修改

  • 修改有效时间
  • 修改时间戳

  • 修改uaername为WebGoat

修改密钥为bnsiness

将base64编码好的放在encoded中

复制cookie值,并提交

任务成功完成

第7关

步骤:

将这个cookie值进行解码

利用时间戳将有效期1526217811改为2023年12月7号21点30分

利用base64编码分别改为1701955800none

分别将修改后的base64编码放在Encoded中

点击Checkout进行抓包,并提示我们不是一个JWT令牌,请重试

右击发送到Repeater

Authorization提示我们可以承载空值,然后将cookie值放入Authorization

提示我们成功的完成任务, tom 帮我们付钱成功