当前位置: 首页 > 知识库问答 >
问题:

使用Apereo CAS发布的网芯加密JWT解码

戚飞虎
2023-03-14

Apereo CAS单一登录发布了以下JWT。

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg

我知道这是一个使用JWE标准的加密JWT。加密密钥如下所示。

9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8

签名秘密如下。

9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8

用于正确解码此JWT的java代码如下所示。

    public Assertion validate(String ticket) throws TicketValidationException {
        try {
            System.out.println("ticket="+ticket);
            
            final Key key = new AesKey(signingKey.getBytes(StandardCharsets.UTF_8));
            
            final JsonWebSignature jws = new JsonWebSignature();
            jws.setCompactSerialization(ticket);
            jws.setKey(key);
            if (!jws.verifySignature()) {
                throw new TicketValidationException("JWT verification failed");
            }
            
            final byte[] decodedBytes = Base64.decodeBase64(jws.getEncodedPayload().getBytes(StandardCharsets.UTF_8));
            final String decodedPayload = new String(decodedBytes, StandardCharsets.UTF_8);
            
            final JsonWebEncryption jwe = new JsonWebEncryption();
            final JsonWebKey jsonWebKey = JsonWebKey.Factory
                    .newJwk("\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}");
            
            jwe.setCompactSerialization(decodedPayload);
            jwe.setKey(new AesKey(jsonWebKey.getKey().getEncoded()));
            System.out.println("JWT ---> "+jwe.getPlaintextString());
            
            JSONParser parser = new JSONParser(JSONParser.DEFAULT_PERMISSIVE_MODE); 
            JSONObject json = (JSONObject) parser.parse(jwe.getPlaintextString());

            return new AssertionImpl(json.getAsString("sub"));
            
        } catch (JoseException | TicketValidationException ex) {
            logger.error(Arrays.toString(ex.getStackTrace()));
        } catch (ParseException ex) {
            java.util.logging.Logger.getLogger(CustomJWTValidator.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

我试图在NetCore2.2中解码相同的JWT。代码如下。

    var encryptionKey = "9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8";
    var jsonWebKey = "\n" + "{\"kty\":\"oct\",\n" + " \"k\":\"" + encryptionKey + "\"\n" + "}";
    var jwkc = new JsonWebKey(jsonWebKey);
    services.AddAuthentication(x =>
    {
        x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = false,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8")),
            ValidateIssuer = false,
            ValidateAudience = false,
            ValidateLifetime = false,
            TokenDecryptionKey = jwkc,
        };
    });

我故意禁用了签名验证和任何其他类型的验证。然而,在JWT验证中,我有以下错误。

System.ArgumentException: IDX12723: Unable to decode the payload 'ZXlKNmF...5azdB' as Base64Url encoded string. jwtEncodedString: ''. ---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: e. Path '', line 0, position 0.

有效载荷似乎没有正确解码。到目前为止,很多谷歌搜索都没有给我结果。

共有1个答案

顾俊楚
2023-03-14

我能够完全加载,验证签名并解密令牌。问题来自于您收到的密钥:当签名密钥不是时,加密密钥已经是bas64url安全编码。

相应的JWK分别为(签名和加密):

{“kty”:“oct”,“k”:“OU8YMLZKN1FKDTNTQK5OT3K4NDAYVVQZGLLV0FQNGY5C2KYCS1PODLPMJJWZDDRSNUZBUJOAE95OHZ3WMFTSDVUGRPZVDBAJRMOXNPMNETZG”}

{“kty”:“oct”,“k”:“9o22vd7qju3mbnhoy8vwzash1pdiewaj4f9si2q-O8”}

编辑:为了记录,我使用了web令牌/jwt框架(PHP库)和以下脚本:

<?php

use Base64Url\Base64Url;
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Encryption\Algorithm\ContentEncryption\A128CBCHS256;
use Jose\Component\Encryption\Algorithm\KeyEncryption\Dir;
use Jose\Component\Encryption\Compression\CompressionMethodManager;
use Jose\Component\Encryption\Compression\Deflate;
use Jose\Component\Encryption\JWEDecrypter;
use Jose\Component\Encryption\Serializer\CompactSerializer as JweSerializer;
use Jose\Component\Signature\Algorithm\HS512;
use Jose\Component\Signature\JWSVerifier;
use Jose\Component\Signature\Serializer\CompactSerializer as JwsSerializer;

require_once 'vendor/autoload.php';

$token = 'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.ZXlKNmFYQWlPaUpFUlVZaUxDSmhiR2NpT2lKa2FYSWlMQ0psYm1NaU9pSkJNVEk0UTBKRExVaFRNalUySWl3aWRIbHdJam9pU2xkVUluMC4uREJXMFNUa19OSUVrMmFCVElJNHVnUS5qX3l4a1BVOHNzQ2tCUkdrdjN2RGI0QjFyVDRHWEhzRUJtTlJvTVR0d0hvMjc0NF96cHIzaW1JUk15ek1nU0RIcF9xcXFIQVVnNUNvM3JuM0FTQWUzS1VaMmFsR1B1SmIzT3UxN0hGR2t6a0RDS29CamdHdU9LVHowMlpfVWpYcm1hZXg0RDVyOUt1blNZYWxTWVBDTFU3TncyZEZVWHBwWnlrb3pQdXl6RFFadjZVMDlQaXgxa1gtLW9obUpFVUZJWlN6Vi1DQUs1RTRsSmtWU3ZrZ1gxSmVBMkVjNlY4aFJUSzFIMXRmb2t6Y09nNlJXNElWN05JNVJUQW8ycmlIVlVnLV94czZIY2JFcFZxR0hlVW5QNmF0Nl9zLTFnbGMzTTFzeHBJcmxBN3FEblhPUGt1ZjFmbnpwcEpFVmZWVTV2LWpOUDZQQ0ZnMjA2S2pjeDBYYlRVX0hWN1NyUUhyWUx2Y0gwVWlWVjljZGNOWmJ0Q2hjQjkwX2M2YXVRVmZjeEJZZjE1c2V0M2g3MzA0T0w5RmM5MG5fbXNyV3RIMnVYcGxfUEEwc29IMnJMM0xVV3YyS1E0WE5lR0V5eXpqRXBZWTU3VzJMazZreWQ2UU13RV9ndy5TenQ3WGFqbTBnSy11bk05djl5azdB.V50nzzET85j2FAMRGCLqN1sLXZ8WZrfH0G5__WL6UwvrjAZbvj9tjXAnwcIoBeyFU-zvIsjom520-p2JCNoqEg';
$signatureKey = new JWK([
    'kty' => 'oct',
    'k' => Base64Url::encode('9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O89O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8'),
]);
$encryptionKey = new JWK([
    'kty' => 'oct',
    'k' => '9O22Vd7QJu3mBNhOy8vwZaSH1UPdieWAj4f9si2q-O8',
]);

$jwsSerializer = new JwsSerializer();
$jws = $jwsSerializer->unserialize($token);
dump($jws);

$jwsVerifier = new JWSVerifier(new AlgorithmManager([
        new HS512()
]));
$signatureIsVerified = $jwsVerifier->verifyWithKey($jws, $signatureKey, 0);
if (!$signatureIsVerified) {
    exit('Invalid signature');
}
dump('The signature is valid');

$nestedToken = $jws->getPayload();

$jweSerializer = new JweSerializer();
$jwe = $jweSerializer->unserialize($nestedToken);
dump($jwe);

$jweDecrypter = new JWEDecrypter(
    new AlgorithmManager([new Dir()]),
    new AlgorithmManager([new A128CBCHS256()]),
    new CompressionMethodManager([new Deflate()])
);
$decryptionSuccess = $jweDecrypter->decryptUsingKey($jwe, $encryptionKey, 0);
if (!$decryptionSuccess) {
    exit('Unable to decrypt the token');
}
dump('The token has been decrypted');
dump($jwe->getPayload());

dump(json_encode($signatureKey), json_encode($encryptionKey));
 类似资料:
  • 我想问一下,在使用非对称加密时,我们使用客户端的公钥加密数据,因此客户端可以使用他们的私钥解密数据,对吗? 我刚刚找到了使用RSA签署JWT的教程,但我发现它们使用服务器私钥而不是客户端的公钥加密数据,并且服务器的公钥在客户端之间共享。 安全吗?因为如果公钥因为可共享而落入坏人之手,每个人都可以正确解密? 那么,这样签jwt可以吗? 参考:教程1教程2

  • 我有一个由maven处理的Springboot项目,其中包含一些用Jasypt加密的秘密。当我运行时,我将传递jasypt密码为: 它能够运行测试用例,并将jar文件部署到存储库中。但是当我对mvn release做同样的操作时,jasypt密码没有正确设置。 或者 对于这两种情况,我在运行测试用例时都会遇到以下错误。 原因:java。lang.IllegalStateException:缺少必需

  • 我们正在使用JWT Nuget来创建和验证令牌。下面是我们用来创建令牌的代码 我的理解是,这不会加密令牌,因为我能够通过访问jwt.io解析令牌,并且能够读取内容。我想加密令牌,这样它就不应该被解析。我在JWT Nuget中找不到任何可以加密令牌的方法。 那么如何使用JWT nuget对令牌进行签名和加密呢? 编辑: 我知道JWT不需要任何加密,因为只有经过身份验证的用户才能读取令牌,这意味着,我

  • 我需要在iPhone或iPad上加密字符串(实际上是XML文件),然后用.NET应用程序解密。感谢David Veksler在这里提出的问题“.NET和iPhone之间的AES互操作性?”,以及在这里发表的博客文章http://automagical.rationalmind.net/2009/02/12/aes-interoperability-between-net-and-iPhone/。

  • 问题内容: 我正在使用ExtJS框架。我在 JavaScript中 有MD5函数来加密某些JSON。我的后端使用Java,所以我想知道如何使用 Java 解密MD5 Javascript加密? 这是我正在使用的MD5函数的JS等效项: 问题答案: MD5是 哈希 (即单向转换),因此您无法对其进行解密。您可以将已知哈希与从明文计算出的哈希进行比较,以验证输入的有效性。Java已经为此内置了库。我在

  • 我有这个应用程序编写的Golang作为后端和Typescript作为前端。我需要对传输的数据进行加密,所以选择RSA加密,基本步骤如下: *后端* null 如果前端从后端获取jwk 导入 然后导出 将导出的密钥发送回后端 后端将jwk转换回rsa公钥,它等于Redis中保存的公钥 后端接收int数组并将其转换为后,其长度和内容与前端的相等 代码如下: null null