PHP的JSON Web Token实现。从https://github.com/nowakowskir/php-jwt分支而来

2.0.2 2021-06-17 17:07 UTC

This package is not auto-updated.

Last update: 2024-09-21 06:28:41 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

您可以向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()方法仅解码令牌。它允许您访问其负载,而不进行任何验证!

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

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

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

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

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

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

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

// 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中传递令牌

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

使用令牌的过期日期

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

检查更新

定期检查此包的更新。