【问题标题】:How to validate a token without a database?如何在没有数据库的情况下验证令牌?
【发布时间】:2019-01-18 02:20:57
【问题描述】:

我在同一台服务器上托管了两个域,域 A 和域 B。

域 A 将生成对域 B 内容的唯一访问令牌。

域 A

<?php
  //http://php.net/manual/en/function.phpversion.php
  //echo 'Version of PHP: ' . phpversion();

  session_start();
  //$expiry_timestamp = time() + $expiry;
  //https://davidwalsh.name/random_bytes //https://secure.php.net/random_bytes
  //$token = bin2hex(random_bytes(64)); 
  $token = bin2hex(openssl_random_pseudo_bytes(64));
  //$time_token = 12000;
  //$time_token = srand(floor(time() / $time_token));
  //echo $token;
  $_SESSION['token']=$token;
?>

<html>
    <head>
    </head>

    <body>  
        <a href= "domainB.com/content1.php?token=<?php echo $_SESSION['token']; ?>">Content 1</a>
    </body>
</html>

生成令牌的过程似乎是正确的,它很容易生成。

现在我的问题来了,如何验证从域 A 到域 B 生成的令牌?生成的令牌必须仅对生成令牌的内容有效,令牌不得对其他内容有效,令牌必须是唯一的,这样如果不是来自他或她的计算机,用户就不能与其他用户共享访问权限,令牌必须仅在访问 4 小时内有效 4 小时后令牌将不再有效以显示内容必须生成新令牌才能再次访问。

这个过程可以使用cookie而不使用数据库来完成吗?

也许使用密钥来识别域 A 和域 B,类似的东西

$APP_SECRET_KEY = "key code secret";

【问题讨论】:

  • 您不想使用数据库,但您可以创建一个文件来检查数据吗?您从域 A 生成令牌 -> 使用用户 + 令牌数据创建文件 -> 域 B 检查此文件 -> 4 小时后删除文件
  • 将令牌从一个域传递到另一个域很容易,但是您将需要两个域都可以访问的某种共享服务器端资源(因此无法修改) - 如果您不使用数据库,它可能是共享文件服务器。
  • @CD001你能解释一下我应该在我的服务器上修改什么吗?
  • @MickaelLeger 看起来像你说的那么简单,但是这个过程应该如何实现:(
  • 在我工作的地方,我们使用 AWS s3 (aws.amazon.com/fr/s3),创建文件、上传文件、读取文件或删除文件真的很容易。我确定还有其他过程可以做到,但不知道他们很抱歉:s

标签: php cookies setcookie


【解决方案1】:

Json Web Token (JWT) 似乎符合您的要求。两个应用程序都使用一个密钥来相互交换令牌和加密数据。

示例用例:

  • 让秘钥$secret="secret"
  • 原始数据告诉我们生成令牌时的 Unix 时间戳(iat 字段)、用户 ID(sub 字段)和内容 ID(content 字段)
$data = [
  "sub" => "1234567890",
  "iat" => 1516239022,
  "content" => 1
];

应用程序 A 使用 HS256 算法 ($token = jwt_encode($raw, 'HS256', $secret)) 使用密钥对原始数据进行编码。输出$token 将是:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNTE2MjM5MDIyLCJjb250ZW50IjoxfQ.idM7d2fgmJVk3WjANwG-Gt6sY0lyE3eTvpKRpwITHRs

您可以解析令牌以在JWT home page 中查看其内容。

令牌被发送到应用程序 B。此应用程序使用相同的算法和共享密钥 ($raw = jwt_decode($token, 'HS256', $secret)) 对令牌进行解码。原始数据将在应用程序 B 中可用。这些数据可用于验证令牌:

  • sub字段读取用户ID,检查是否正确
  • content字段读取内容id并检查是否正确
  • iat字段中读取生成令牌时的时间戳,检查是否在最近4小时内。

severalPHP librariesimplementJWT给你。

【讨论】:

  • 不使用第三方库是不行的:(
  • 您可以加密您的数据以自己创建令牌。基本思想是两个应用程序共享一个密钥,该密钥用于加密数据。
  • 您可以给我一个示例,说明如何使用您评论中所写的两个键来验证数据。
【解决方案2】:

在这里使用共享密钥是一个不错的方法。

当我需要生成和验证令牌(例如:电子邮件验证)并且不想将其存储在数据库中时,我倾向于使用 HMAC。另外,HMAC is built in to PHP,所以这里不需要库。

这个想法是,在您的数据之上,您添加一个签名以验证此令牌是由您的应用程序在域 A 上创建的。您在域 B 上再次以相同的方式生成令牌以验证它。

例子:

生成令牌的共享函数:

function buildVerificationToken($expires, $content)
{
    // Same function on both domains
    $APP_SECRET_KEY = 'key code secret';  // Maybe move that out of source code

    $tokenData = [
        'expires' => $expires, // Include it in signatur generation to prevent user from changing it in URL
        'content' => $content, // Create different token for different content
        'ip' => $_SERVER['REMOTE_ADDR'], // Identify the browser to make it not shareable. Best approach I could think of for this part.
    ];

    $serialized = json_encode($tokenData);

    return hash_hmac('sha256', $serialized, $APP_SECRET_KEY);
}

在域 A 上生成令牌:

<?php
$expires = time() + (4 * 3600); // +4h
?>
<a href= "domainB.com/content1.php?expires=<?php echo $expires; ?>&token=<?php echo buildVerificationToken($expires, 'content1'); ?>">Content 1</a>

在域 B 上验证它:

$providedExpires = (int) $_GET['expires'];
$providedToken = $_GET['token'];

$verificationToken = buildVerificationToken($providedExpires, 'content1'); // Build token the same way

if (!hash_equals($verificationToken, $providedToken)) { // hash_equals instead of string comparison to prevent timing attacks
    // User provided forged token, token for another content, or another IP
    die('Bad token'); // However you want to handle this
}

if (time() > $providedExpires) { // Check expiry time. We can trust the user did not modify it as we checked the HMAC hash
    die('Token expired'); // However you want to handle this
}

// User is allowed to see content1

【讨论】:

    猜你喜欢
    • 2019-05-22
    • 2019-05-10
    • 2016-09-15
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    • 2021-01-18
    • 2020-05-05
    • 2019-09-23
    相关资源
    最近更新 更多