freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

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

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

FreeBuf+小程序

FreeBuf+小程序

web安全战技101之JWT
2021-08-05 22:16:29

原理

从源头思考测试方法是如何来的。 ------ sec875

JWT只是为了授权而不是身份验证

身份验证后用户访问特权资源通常是session ID机制,具体实施是使用会话cookie来授权

但JWT实际上没有使用cookie,而是使用json web token授权

传统的session ID授权机制如图所示

image

以前是别人告诉你cookie可能永不过期等测试方法。而现在可以基于原理图的观察与质疑来增加测试方法。

基于第一步:我可以高并发注册一个账户吗?它会生成多少session ID?有效期?是否都一致,都有效?

基于第二步:我注销后再登录,它下发一样的session ID吗?以前下发的session ID是否弃用了?

基于第三步:发送假session ID?空?多个session ID?

基于第四步:bypass 验证?弱比较验证?

基于第五步:响应包中有没有客户端hook重定向?OAUTH 2.0?

现今JWT授权机制如图所示

image

可以发现与session ID非常类似。但不是将信息存储在服务器的会话内存中。

服务器创建了一个json web token,它进行了编码,使用自己的key对其签名。如果您进行篡改,则它知道已无效。服务器上没有任何JWT的信息,而是将它发送给了浏览器。但是key本身保存于服务器中,确保密钥安全性。

浏览器可以选择存储它,比如使用cookie来存储。不管已什么方式,最终浏览器会发送含有jwt内容的请求给服务器,确保服务器知道用户正在使用什么进行授权。

服务器验证jwt的签名。要注意key在json web token中还是在服务器上面?记住哦,原则上是保存于服务器上确保安全性。至于具体实施就不清楚了哦 :)

举一反三,大家可以自己观察与质疑并测试。

为什么要如此?

session ID存储在服务器上,服务器必须根据ID来找到用户信息。

而json web token将用户信息存储在token中,这意味着它存储在客户端上,服务器不需要存储。去掉了服务器的依赖,就能引入多台服务器共用JWT。

JWT的签名以及它如何存储用户信息

https://jwt.io/ debug

红色部分的头部是base64编码,用于确定算法和JWT令牌类型,对最后蓝色的验证部分有用

image

紫色部分的数据payload一看就是用户信息

sub字段类似于session ID,只不过是存进了JWT中发送给客户端,而没有存储它。

iat字段是发布时间。name就不用讲了吧。有的会出现eat字段,是过期时间。

鼠标放上去可以看见时间。您看,您可能又有新的测试手法了。比如过期时间?你把着JWT拿走一直用?image

蓝色部分是最重要的验证签名

签名验证用户是否篡改了它。

用户验证就靠这里的东西。如果这里出现问题,将你验证成管理员,那你就真的变成管理员了。

注意观察签名内部使用的函数。JWT为什么是base64编码?因为签名中使用的是这个函数。为什么JWT有点号?看看签名中用了什么符号进行了拼接。注意HMACSHA256函数是两个参数,因此参数1的头部与payload是定义用户的,而参数2 secret密钥,用于签名验证。image

如果您篡改了header与payload部分。马上就签名报错。

因为参数1的值与参数2 secret的值不匹配了。无法通过签名验证。

验证函数大致类似如下所示,您修改了数据部分,但是密钥部分没变。这肯定无法通过验证函数

VerifyFile(secretkey, signedFile);

image

同理,如果您篡改secret的签名部分,那么header、payload和签名又不匹配了。

参数1的header与payload部分,和参数2的secret部分是同时生成的匹配值。它们相互验证彼此。secret本身的密钥key又保存于服务器中。

参数1与参数2的数据一旦变化,马上就能发现,无法通过验证。

总之一句话:参数1与参数2要互为匹配,整个JWT才会验证通过。如果您想篡改并通过验证,则需要secret密钥key。

签名函数大致如下所示,您会发现,要签名一个东西需要key,数据,和需要签名的东西(您不会只签名红色部分和紫色部分吧。。那谁来保证蓝色部分是否被篡改)。

SignFile(secretkey, dataFile, signedFile);

image

签名处的secret值保存于服务器中,确保了密钥本身的安全性。

为什么要用JWT?

同一个组织的,两个服务器:银行与社保服务器

用户希望登录银行账户的同时也能自动登录到社保账户,或者该银行的任何其他服务器

当用户的登录信息仅保存在银行服务器时,登录到社保服务器自然需要重新登录

出于体验,用户不希望登录银行服务器的用户切换到社保服务器时又重新登录

需要一个无缝衔接,让用户感觉就在用一个程序一样

如果两个服务器共享了key,那么JWT刚好满足这种需求。两个服务器需要做的就是给客户端发送一样的JWT

诸如负载均衡,微服务的API也可以使用JWT进行授权管理,只要它们共享了key

image

node.js与JWT

【以下代码仅用于这里的示例,不能直接用于实际开发】

在node.js服务器上有一个自动刷新key的机制来刷新JWT,大致情况如下:

image

node.js服务器上JWT的机制大致情况如下:

接收请求的账户身份验证,如果验证通过将创建一个JWT访问令牌,将用户信息保存在其中,下发给浏览器

image

image

node.js服务器上会存在一些逻辑来验证一下JWT,判断一下头部分,判断一下是否为空?来验证一下浏览器发送的JWT是否有效。大致情况如下:

image

服务器共享同一个key,这里是调用同一个变量来指定同一个地方的key,大致代码如下:

image

在服务器处通过验证(1),服务器下发JWT(3),复制JWT访问另一个服务器(3),一样可以授权与识别JWT(2)

image

一个服务器处理所有的令牌创建、刷新、删除与身份认证,其他服务器做别的事情。为啥需要刷新令牌就不需要再提了。会话永不过期在cookie时代老生常谈了。。

node.js服务器上会存在一些逻辑来验证一下JWT的令牌刷新,刷新令牌是否为空,是否有效等。大致代码如下:

image

服务器会下发两个token值,一个是前面的,一个是刷新的。如果前面的过期了,服务器将返回拒绝。您可以增加逻辑机制,比如快过期了再下发刷新值等等。大致代码如下:

image

如何让这些刷新与生成的令牌失效呢,同理,代码层引入删除令牌的机制。代码体现都差不多的,这里也不需要再放出来看。不同的函数命名,delete之类的东东。

JWT漏洞场景练习

漏洞场景环境部署

万事俱备,练练手?切记,万事都逃不掉大局观。全局观的原理很重要,能学到就先学了再回过头来看安全。攻击向量会变多,测试手法与思维也会变多。

有轮子的话尽量借鉴

//www.calder-systems.com/vuls/219056.html

请合法练习遵守法律与规则

https://www.onelogin.com/ 是在线已授权的JWT测试网站,有时候速度很慢。。

点击DevelopersGET A DEVELOPER ACCOUNT获取一个账户,身份认证通过后,下发JWT

https://www.onelogin.com/developer-signup

burpsuite扩展应用 JSON Web Tokens,可以debug JWT。 JSON Web Tokens Attacker扩展也可以试试

JWT漏洞:算法None 和 CVE-2018-0114

参考资料:https://portswigger.net/bappstore/f923cbf91698420890354c1d8958fee6

参考资料:https://portswigger.net/bappstore/82d6c60490b540369d6d5d01822bdf61

JWT扩展使用

https://www.油兔比.com/watch?v=SuDN35-aefY

webgoat靶机也有JWT tokens 练习场景

https://github.com/WebGoat/WebGoat/releases 部署与安装

https://www.油兔比.com/watch?v=k94sct9FKw4 windows 10部署视频

https://www.oracle.com/java/technologies/javase-jdk16-downloads.html java 16版本下载

java -jar webgoat-server-8.2.1.jar [--server.port=8080] [--server.address=localhost] [--hsqldb.port=9001]
java -jar webwolf-8.2.1.jar [--server.port=9090] [--server.address=localhost] [--hsqldb.port=9001]

可以发现靶机对java版本的差异性还是依赖很强烈的,我这里是11 TLS版本,部署失败。你们可以自行安装16版本,我这里就不换版本了。

image

安装一下扩展

image

docker实例

ubuntu 20.04TLS部署webgoat

https://www.油兔比.com/watch?v=aMKUuaga85A 部署docker

sudo apt install docker.io   # 对了,仓库中的docker版本够用了,无需去官网部署最新docker版本。
docker --version
sudo systemctl status docker

https://hub.docker.com/r/webgoat/goatandwolf
https://www.油兔比.com/watch?v=qSqXhBABxhU 靶机部署视频

docker语法这里就不讲了 --help对照看看

docker --help
sudo docker ps -a   #列举实例
sudo docker pull webgoat/goatandwolf    # 拉取镜像

注意是不是拉取成功了。

image

运行docker靶机

sudo docker run -p 127.0.0.1:8080:8080 -p 127.0.0.1:9090:9090 -e TZ=Europe/Amsterdam webgoat/goatandwolf
sudo docker run --help

image

访问靶机并注册一个账户

http://127.0.0.1:8080/WebGoat/

image

停止docker运行实例

image

停止后再起实例,将docker运行实例的端口转发到虚拟机IP上面,方便windows上的bp访问与测试

sudo docker run -p 192.168.236.130:8080:8080 -p 192.168.236.130:9090:9090 -e TZ=Europe/Amsterdam webgoat/goatandwolf

访问,注册并登录JWT场景

image

第一页是教学

image

解码JWT

这里是让我们用jwt调试一下,找username

image

image

这里的任务是让我们改jwt成管理员权限,然后重置投票

image

它说guest不能投票,叫我们登录

image

切换一下用户看看数据包

image

image

用插件解码一下。看见字典admin为false值

image

修改false值为true的话,签名验证就没法通过。这里验证一下后端是否存在签名验证机制。

复制header部分到编解码器,base64解码,篡改为none,再编码回去。none表示不进行签名验证。

image

将数据包发到重放器中,将篡改后的header部分替换好,再复制出数据payload部分进行字段admin的值篡改,再替换。

image

注意观察解码后的base64是不是解码正确了。如果缺少闭合,请手动修改

image

以上属于乱改的,是为了和有意识的测试形成鲜明的对比。

因为,不基于功能点的观察,您就算篡改了jwt,那它这个数据包发送后去做什么事情?

我这里是已投票这个功能点为例子,您可以找一找重置的功能点在哪里?

找到投票功能点,然后抓取数据包

这个包才是基于功能点触发的投票包

image

发送到重放器中

image

header部分篡改为none,不进行签名验证。重放器中记得替换header。

image

数据payload部分篡改admin字段为true

image

篡改,替换完了之后重放数据包发现 401 权限拒绝

思考:算法改成了none,数据payload也改了admin,不进行签名。那再改改签名部分?删除它看看?

image

base64编码的header头部分中,存在特殊字符 = ,值中含有特殊字符肯定是需要百分号编码,为%3d。将签名部分的值删除掉,发现请求成功。

image

多发几次,投票数字一直在涨,疯狂刷票

image

注意算法none的其他变体都试试:none,None,nOnE,NONE。

JWT还有一个算法替换攻击 CVE-2015-9235

阅读理解部分:https://www.chosenplaintext.ca/2015/03/31/jwt-algorithm-confusion.html

简而言之:服务器本来部署了RSA验证,但是攻击者篡改算法为HS256,导致RAS的公钥变成了HS256验证签名的私钥了。拿着这个公钥就能给JWT签名。

image

走到第六页,发现这后面就有教学。大家可以对照一下自己的测试姿势已用于工作中SDL的web渗透阶段。

image

结尾

到此为止,有原理有练习场景还有例子,已经可以运用到工作的实施阶段了。

我鼓励您将这个靶机的其他内容都看一看,将这些验证方法运用到SDL中来。这个靶场也比较新,在不停的维护中。

助力各位师傅们在SDL建设中快速的成长。

感谢师傅们很有耐心的阅读到这里。

我们还会再见面的。

共勉。

本文作者:, 属于FreeBuf原创奖励计划,未经许可禁止转载

# Web安全漏洞
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
评论 按热度排序

登录/注册后在FreeBuf发布内容哦

相关推荐
\
  • 0 文章数
  • 0 评论数
  • 0 关注者
文章目录
登录 / 注册后在FreeBuf发布内容哦
收入专辑