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

在PHP中,如何在没有密钥的情况下检查JWT的完整性?

陆俊智
2023-03-14

我研发的App使用了一些JWT令牌,而不是它生成的。到目前为止,我存储令牌,并严格比较头中给出的令牌和我在数据库中得到的令牌。

我找到的所有JWT PHP库都按以下顺序显示示例:

  1. 使用密钥ky生成令牌

我需要检查JWT是否有效(关于标头、有效负载和给定的签名),这将增加一个安全层。

在没有密钥的情况下,我如何“简单”地检查令牌完整性?

共有3个答案

井逸明
2023-03-14

在没有密钥的情况下,我如何“简单”地检查令牌完整性?

假设这个问题意味着您根本无法访问任何类型的公钥(如果使用非对称签名算法)或机密(如果使用对称算法),那么答案是:

你不能!

签名是一个散列,根据头有效负载secret/key的值计算得出。验证基本上意味着重新计算该哈希并与令牌的签名进行比较。如果没有密钥或机密,则无法计算哈希,因此无法证明签名是否与内容匹配。

您没有详细介绍用例、令牌颁发者的角色和您的应用程序。但是,如果要验证由第三方身份验证系统颁发的令牌,它使用非对称算法,您可能会在令牌中找到密钥id(kid)和JWK(JSON Web key)endpoint的url,您可以从中以JWK的形式获取公钥。

而且,如果您只想读取令牌的内容,假设您谈论的是已签名(未加密)的令牌,那么您可以通过简单的解码来访问内容。标头和负载只是Base64url编码的。你不需要钥匙来解码它们。

徐嘉谊
2023-03-14

请找到我的代码片段来解码没有键和任何库的有效负载,简单的php代码。

function decodeJWTPayloadOnly($token){
        $tks = explode('.', $token);
        if (count($tks) != 3) {
            return null;
        }
        list($headb64, $bodyb64, $cryptob64) = $tks;
        $input=$bodyb64;
        $remainder = strlen($input) % 4;
        if ($remainder) {
            $padlen = 4 - $remainder;
            $input .= str_repeat('=', $padlen);
        }
        $input = (base64_decode(strtr($input, '-_', '+/')));

        if (version_compare(PHP_VERSION, '5.4.0', '>=') && !(defined('JSON_C_VERSION') && PHP_INT_SIZE > 4)) {
            $obj = json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
        } else {
            $max_int_length = strlen((string) PHP_INT_MAX) - 1;
            $json_without_bigints = preg_replace('/:\s*(-?\d{'.$max_int_length.',})/', ': "$1"', $input);
            $obj = json_decode($json_without_bigints);
        }
        return $obj;
}
徐奇逸
2023-03-14

JWT可以使用对称或非对称算法进行加密或签名(或两者依次进行)。

您描述的过程使用对称算法,其中使用相同的密钥对令牌进行签名或加密,然后对其进行验证或解密。这适用于同一应用程序正在创建和使用的令牌——例如,Web应用程序将令牌发送到浏览器,并从请求中读取它。

如果一个应用程序正在创建供不同应用程序使用的令牌,它应该使用非对称算法:

  • 要加密某些内容,您需要使用公钥,应用加密算法,最后得到一个只能用私钥解密的字符串。一个常见的类比是,公钥就像挂锁:任何人都可以将其扣上,但只有私钥的持有者才能在之后打开它
  • 要对某个内容进行签名,需要使用私钥,应用签名算法,最终得到一条任何人都可以读取的消息,并且任何人都可以使用公钥验证该消息。类似的情况是,公钥就像某人签名的一个样本:伪造他们的签名是不够的,但足以判断签名是否真实

在您的情况下,您需要生成令牌的应用程序使用只有该应用程序知道的私钥对其进行签名。然后,可以将相应的公钥共享给服务的每个用户,并存储在需要验证令牌的应用程序的配置中。

您没有指定正在使用的库,因此很难具体说明,但您需要寻找的是对令牌进行签名而不是加密的选项。然后,您(或控制其他应用程序的人)将公钥分发给需要验证它的每个endpoint,并验证它是否包含具有预期算法和密钥的签名。

例如,使用lcobucci/jwt库,创建令牌的应用程序如下所示:

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Rsa\Sha256;

$signer = new Sha256();
$privateKey = new Key('file://{path to your private key}');

$token = (new Builder())->withClaim('some', 'claim')
                        ->getToken($signer,  $privateKey);

接收到它的应用程序将按如下方式进行验证:

use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Signer\Key;

$publicKey = new Key('file://{path to your public key}');

$token = (new Parser())->parse('{token taken from request}');
if ( $token->verify($signer, $publicKey) ) {
    var_dump($token->getClaims());
}
else {
    echo 'Token does not have valid signature!';
}

另一方面,如果要根据数据库中的已知列表检查令牌,则实际上不需要JWT,只需使用GUID之类的东西,并将额外数据存储在数据库中。JWT的思想是,您不需要任何先验知识,只需检查令牌内的签名和声明(例如,使用“expires at”声明,以避免攻击者重用在日志中找到的旧令牌)。这就平衡了令牌的长度和复杂性,允许分散的无状态应用程序读取令牌。

 类似资料:
  • 如何在Azure密钥库中设置秘密,而不使用PowerShell。我们正在使用Azure Key Vault来安全地存储连接字符串和一些其他应用程序秘密。我们可以使用PowerShell脚本添加秘密,但我想知道是否有其他方法可以在Azure KeyVault中添加密钥,最好是使用API。我们实际上需要提供一个管理工具,应用程序管理员可以使用该工具在密钥库中添加/修改机密。

  • 我需要一个apache/php来识别ffmpeg命令,而不需要指定/usr/local/bin/ffmpeg的完整格式 从命令行调用ffmpeg执行程序通过web从php调用ffmpeg不执行程序通过web从php调用 /usr/local/bin/ffmpeg执行程序 原因:php脚本调用youtube dl(编译程序)并在内部执行ffmpeg 提前感谢-尝试了ffmpeg路径:哪个ffmpeg

  • 在我的响应中,有一个,没有任何。那么,我如何获取该响应呢? 这是我的JSON代码-

  • 我正在创建一个Android应用程序,使用一个普通的谷歌驱动器帐户作为一个应用程序-养号,如上所述,以令人难以置信的简洁,这里: 使用常规Google帐户作为应用程序拥有的帐户 不幸的是,有关如何在云端硬盘上执行任何操作的所有说明都指向客户端密钥,如下所述: Google API控制台-缺少客户端机密 对于已安装的应用程序,这实际上不再存在。我设法通过构建一个实际的网页,在难以置信的痛苦中获得了O

  • 我有一个JWT安全令牌,需要通过jwksendpoint进行验证。jwks中的数据如下所示: 我尝试了一个第三方api,但它看起来依赖于x5c密钥,这在我的案例中不存在。 我的代码是: 如何在没有x5c的情况下通过jwks验证JWT?

  • 我有一个rest api,它是一个Spring Boot和spring mvc项目。 还有另一个web项目,它是一个普通的spring项目。它的前端如和后端如需要调用。用户需要登录才能使用它。 我不需要对做权限控制,只有登录的用户才能通过的前端和后端访问 有一些解决方案,如、、。 我想尝试这三种方法,然后选择一种。