如何在没有数据库的情况下验证令牌?

6 php cookies setcookie

我在同一台服务器上托管了两个域,域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>
Run Code Online (Sandbox Code Playgroud)

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

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

可以在不使用数据库的情况下使用cookie完成此过程吗?

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

$APP_SECRET_KEY = "key code secret";
Run Code Online (Sandbox Code Playgroud)

Tob*_* K. 6

在这里使用共享密钥是一个好方法。

当我需要生成和验证令牌(例如,电子邮件验证)并且不想将其存储在数据库中时,我倾向于使用HMAC。另外,HMAC内置在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);
}
Run Code Online (Sandbox Code Playgroud)

在域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>
Run Code Online (Sandbox Code Playgroud)

在域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
Run Code Online (Sandbox Code Playgroud)