nowakowskir/php-jwt

PHP 的 JSON Web Token 实现。

2.1.1 2022-11-14 18:21 UTC

This package is auto-updated.

Last update: 2024-09-10 14:21:02 UTC


README

JWT

在此了解更多关于 JWT 的信息

许可

请在使用前检查 BSD-3 Clause 许可条款。

支持算法

  • HS256
  • HS384
  • HS512
  • RS256
  • RS384
  • RS512

安装

您可以通过运行 composer 命令将此包添加到您的项目中

composer require nowakowskir/php-jwt

确保您的 vendor 自动加载文件已正确加载,并且以下类被使用。

use Nowakowskir\JWT\JWT;
use Nowakowskir\JWT\TokenDecoded;
use Nowakowskir\JWT\TokenEncoded;

元素

当使用此包时,您将主要使用两个类: TokenEncodedTokenDecoded

您可以将这些类的对象转换为以下形式

TokenEncoded => TokenDecoded
TokenDecoded => TokenEncoded

TokenDecoded

此类表示一个解码后的令牌。它由一个头和一个有效载荷组成。这两个元素都是数组。

TokenDecoded 类的对象表示的令牌允许您访问和修改其任何部分。

TokenEncoded

此类表示一个编码后的令牌。

用法

构建新的 JWT

您可以将 payload 和 header 作为可选参数传递给 TokenDecode 构造函数。

$tokenDecoded = new TokenDecoded(['payload_key' => 'value'], ['header_key' => 'value']);
$tokenEncoded = $tokenDecoded->encode($privateKey, JWT::ALGORITHM_RS256);

echo 'Your token is: ' . $tokenEncoded->toString();

请参阅 安全最佳实践 部分,了解为什么在编码令牌时提供算法是强制性的!

实例化现有令牌

$tokenEncoded = new TokenEncoded('Existing JSON Web Token');

获取令牌的头

$tokenEncoded = new TokenEncoded('Existing JSON Web Token');
$header = $tokenEncoded->decode()->getHeader();

获取令牌的有效载荷

$tokenEncoded = new TokenEncoded('Existing JSON Web Token');
$payload = $tokenEncoded->decode()->getPayload();

请注意,提供密钥不是解码令牌所必需的,因为其头和有效载荷是公开的。您应特别注意不要在令牌的头和有效载荷中传递任何机密信息。JWT 只允许您验证包含给定有效载荷的令牌是否由受信任方签发。它不会保护您在有效载荷中传递的数据!请注意,任何人都可以访问您的令牌有效载荷!

验证令牌

为了使用解码后的有效载荷,请确保您的令牌首先通过了验证过程。否则,无法假设有效载荷是可信的!

try {
    $tokenEncoded->validate($publicKey, JWT::ALGORITHM_RS256);
} catch(Exception $e) {
    // Token validation failed.
}

请参阅 安全最佳实践 部分,了解为什么在验证令牌时提供算法是强制性的!

如果您需要更多关于为什么您的验证过程失败的信息,您可以捕获几个异常类

带有过期日期(exp)的新 JWT 构建

如果您希望令牌在某日期过期,您可以使用 exp 标志。

$tokenDecoded = new TokenDecoded(['exp' => time() + 1000]);
$tokenEncoded = $tokenDecoded->encode($key, JWT::ALGORITHM_RS256);

带有不早于日期(nbf)的新 JWT 构建

如果您希望令牌在达到某个日期之前不活跃,您可以使用 nbf 标志。

$tokenDecoded = new TokenDecoded(['nbf' => time() + 1000]);
$tokenEncoded = $tokenDecoded->encode($key, JWT::ALGORITHM_RS256);

解决服务器之间的时钟差异问题(exp、nbf)

由于服务器之间的时钟可能不同,您可以使用所谓的 leeway 来解决这个问题。这是一种时间范围,在验证令牌(exp、nbf)时将考虑它。

$leeway = 500;
$tokenEncoded = new TokenEncoded('Existing JSON Web Token');
$tokenEncoded->validate($key, JWT::ALGORITHM_RS256, $leeway);

安全最佳实践

不要在令牌的有效载荷中传递机密数据

请注意,提供密钥不是解码令牌所必需的,因为其头和有效载荷是公开的。您应特别注意不要在令牌的头和有效载荷中传递任何机密信息。JWT 只允许您验证包含给定有效载荷的令牌是否由受信任方签发。它不会保护您在有效载荷中传递的数据!请注意,任何人都可以访问您的令牌有效载荷!

在验证令牌之前不要信任您的有效载荷

确保令牌有效的唯一方法是使用 TokenEncoded::validate() 方法。请记住,TokenDecoded::decode() 方法只解码令牌。它允许您访问其有效载荷,而无需任何验证!

它允许您在不进行任何验证的情况下获取令牌的payload的原因是

  • JWT 的本质是令牌的payload未加密,并且未受密钥保护,因此您甚至不应有它受到保护的幻想,
  • 您可能需要在验证令牌之前使用令牌有效负载的一些部分。

在编码和验证令牌时强制使用算法

因为在某些情况下,令牌头部中定义的算法可能会被攻击者修改,因此强烈建议不要依赖于令牌头部中包含的算法。

出于安全原因,您应该尽可能选择一种算法,并在发行者和验证者应用程序中坚持使用该算法。

为了提高令牌的安全性,此包要求在编码和验证令牌时提供一个算法。

以下您可以看到正确编码和解码令牌的方法

// Issuer
$tokenDecoded = new TokenDecoded();
$tokenEncoded = $tokenDecoded->encode($privateKey, JWT::ALGORITHM_RS256);
// Consumer
$tokenEncoded->validate($publicKey, JWT::ALGORITHM_RS256);

如您所见,两者使用相同的算法。

如果您选择的用于验证令牌的算法与令牌头部中指定的算法不同,此包将抛出Nowakowskir\JWT\Exceptions\AlgorithmMismatchException

这可以保护您的令牌免受篡改后被成功验证的风险。

您可能会想尝试一些变通方法,并使用令牌头部中包含的算法进行验证,尽管这强烈不推荐!

// Don't use algorithm defined in token's header like here!
$header = $tokenEncoded->decode()->getHeader();
$tokenEncoded->validate($publicKey, $header['alg']);

使用不安全的令牌

由于安全原因,创建不安全的令牌是不可能的。

此包不允许您创建使用none算法或空签名的令牌。

尝试这样做将导致抛出Nowakowskir\JWT\Exceptions\InsecureTokenException异常。

try {
    $tokenEncoded = new TokenEncoded('Existing JSON Web Token with none algorithm or missing signature');
} catch (InsecureTokenException $e) {
    // Insecure token
}
try {
    $tokenDecoded = new TokenDecoded();

    $tokenDeoded->encode($privateKey, 'none');
} catch (InsecureTokenException $e) {
    // Insecure token
}

如果不定义算法,也无法解析令牌。

try {
    $tokenEncoded = new TokenEncoded('Existing JSON Web Token without an algorithm');
} catch (UndefinedAlgorithmException $e) {
    // Algorithm not provided
}

生成强大的私钥

首先,您需要生成一个私钥。

ssh-keygen -t rsa -b 4096 -m PEM -f private.key
chmod 600 private.key

然后,您需要根据私钥生成一个公钥。

openssl rsa -in private.key -pubout -outform PEM -out public.pub

定期轮换您的公钥/私钥对

为了最大限度地降低未经授权实体获取您的公钥/私钥的风险,请定期轮换。

保护您的私钥

确保您的私钥受到保护,并且不被任何未经授权的实体访问。特别要注意文件权限。在大多数情况下,您应该将私钥文件的权限设置为600,这意味着只有文件的所有者才能访问。

保护您的公钥

即使它被称为公钥,也只有在真正需要的时候才分享这个密钥。此外,文件权限应尽可能严格。不要在请求之间传递公钥或将它们暴露给公众。

不要在URL中传递令牌

它们将被存储在服务器日志、浏览器历史记录等中。

使用令牌的过期日期

尽可能使用令牌的过期日期,这样令牌的有效期就越短。

检查更新

定期检查此包的更新。