令牌不匹配(CSRF)

tokens do not match (CSRF)

我已经输入了以下代码来防止 CSRF 但发布和检查令牌。 顶部位于 login.php,第二部分位于着陆页。令牌的发行有效,当我在登录页面上打印 $_SESSION['token'] 时,它们匹配。但是,当我替换其他代码时,它说它们不匹配并显示 'expired'。

<?php
session_start();
$_SESSION['token'] = $token;
$_SESSION['token'] = uniqid(md5(microtime()), true); 
print $_SESSION['token'];
?>

<html>
<head>
    <title>My first PHP website</title>
</head>
<body>
    <h2>Please login here to see your tour</h2>
    <form action= "checklogin.php" method="post">
        Enter Username: <input type="text" name="username" required="required"/> <br/>
        Enter Password: <input type="password" name="password" required="required" /> <br/>
        <input type="hidden" name="token" value="<?php echo $_SESSION['token'] ?>" />
    <input type="submit" value= "login" />

    </form>
</body>

<?php
session_start();

print $_SESSION['token'];
session_start(); 
if ($_POST['token'] !== $_SESSION['token']) { 
die('expired'); 
} 
?>

表单操作是 login.php,因此当用户登录 POST 时,数据会提交到 login.php 页面。您的问题没有解释用户随后如何被定向到他们的目标网页。

一种选择是尝试以下方法。

替换:

<form action="login.php" method="post">

与:

<form action="landingpage.php" method="post">

这样在您的着陆页上您将能够获得

的价值
$_POST['token']

在我们对您的问题的评论中进行讨论之后,我发布了这个答案,以便对信息进行总结。

您的代码基本上是正确的,但您遇到的问题是因为在重定向到用户的唯一登录页面后,您无法再访问 $_POST 中的数据,您最初在 checklogin.php,即提交登录表单后。

所以在您的 checklogin.php 脚本中,您有以下选项:

  1. 将令牌包含在您要重定向到的 URL 中,然后检查 $_SESSION['token']$_GET['token']

  2. $_SESSION中设置一个标志,表明该用户已被允许访问系统。像 $_SESSION['loggedIn'] = true;(这是我推荐的)

注意: 这里您面临另一个问题:您必须考虑限制每个用户只能访问他们自己的页面。想象一下,如果一个用户以某种方式知道另一个用户主页的 URL,他们可以轻松地编辑 URL 并访问它。我的建议是将用户的id保存在$_SESSION中,然后在每个用户主页的顶部检查是否允许当前登录的用户打开所述页面。

我希望这样更清楚!