问题描述
我有一个 Server A
,它有一个包含有效下载令牌的数据库。
如果用户提供有效的令牌(存在于数据库中),他们将可以下载一个大文件(> 2 GB)。目前,我这样做(详见 Fastest Way to Serve a File Using PHP 和 Downloading files with download.php):
<?PHP
$ok = check_token_in_database($_GET['token']); // internally uses a sqlite DB
$file = "bigfile.zip";
if ($ok) {
header("X-Sendfile: /path/to/" . $file);
header("Content-type: application/octet-stream");
header('Content-disposition: attachment; filename="' . $file . '"');
}
它有效,但现在我需要减轻 Server A
的负载,如果令牌有效,我希望从另一个 Server B
提供文件.我在想:
<?PHP
$ok = check_token_in_database($_GET['token']);
if ($ok) {
header("Location: https://server_b.example.com/obfuscated_url_ff87a45d76apZ/bigfile.zip");
但是,任何人都可能能够找到目标链接 https://server_b.example.com/obfuscated_url_ff87a45d76apZ/bigfile.zip
他们可以与其他人分享,我不想要。
如何处理这种情况,而不必将令牌数据库和令牌检查移动到Server B
?
解决方法
您可以使用 JWT 来生成令牌。在有效载荷中,您可以存储用户的 IP 地址以防止链接共享。
我不确定要为 PHP 使用哪个库,但让我们以这个库为例: https://github.com/miladrahimi/php-jwt
在服务器 A 上生成令牌:
// Use HS256 to generate and parse tokens
$signer = new HS256(JWT_SECRET_KEY);
// Generate a token
$generator = new Generator($signer);
$jwt = $generator->generate(['file' => 'bigfile.zip','ip' => $_SERVER['REMOTE_ADDR']);
在服务器 B 中,您验证并解析令牌:
$jwt = &$_GET['token'];
$signer = new HS256(JWT_SECRET_KEY);
// Add Validation (Extend the DefaultValidator)
$validator = new DefaultValidator();
$validator->addRule('ip',new EqualsTo($_SERVER['REMOTE_ADDR']));
// Parse the token
$parser = new Parser($signer);
try {
$claims = $parser->parse($jwt);
// Serve $claims['file'] here.
} catch (ValidationException $e) {
// Validation failed.
}
在两台服务器中你都应该定义密钥:
define('JWT_SECRET_KEY','your-long-secret-key-here');
当然,您可以添加更多验证、令牌过期等。
如果您只想将私钥保留在服务器 A 上,则应使用 RSA 算法,然后使用服务器 A 上的私钥生成令牌,并使用公钥解析服务器 B 上的令牌。 (图书馆的 README 中有一个例子)