如何在使用php的登录系统中使用nonce来避免重播攻击?

如何在使用php的登录系统中使用nonce来避免重播攻击?,php,security,login,nonce,Php,Security,Login,Nonce,我用php创建了一个登录和注册系统。我打算使用nonce来防止重播攻击。到目前为止,我得到的是,使用(uniqid(mt_rand(),true))生成一个随机数然后将其存储在数据库中,并将相同的数据以隐藏字段的形式传递给客户端,然后在单击登录按钮时将其发送回服务器端。如果它与数据库中的on匹配,则会将用户重定向到专用页,然后在数据库中生成并更新新的nonce 这就是我打算实施它的方式。但是我有点不太确定这个实现。您可以使用php会话来实现这个目的。 会话是一种更为传统和有用的登录方法。 接收表

我用php创建了一个登录和注册系统。我打算使用nonce来防止重播攻击。到目前为止,我得到的是,使用
(uniqid(mt_rand(),true))生成一个随机数
然后将其存储在数据库中,并将相同的数据以隐藏字段的形式传递给客户端,然后在单击登录按钮时将其发送回服务器端。如果它与数据库中的on匹配,则会将用户重定向到专用页,然后在数据库中生成并更新新的nonce


这就是我打算实施它的方式。但是我有点不太确定这个实现。

您可以使用php会话来实现这个目的。 会话是一种更为传统和有用的登录方法。 接收表单数据后,验证该数据,然后将该数据存储在会话中是否有效。


<?php
session_start();
//Check nonce against session
if(isset($_POST) && $_POST["nonce"] === $_SESSION["csrf"]){
    //save data
    //redirect
}
//generate new nonce for form
$_SESSION["csrf"] = uniqid(mt_rand(),true);
?>
<form method="post" action="<?php echo $_SERVER['REQUEST_URI'] ?>">
    <input type="hidden" name="nonce" value="<?php echo $_SESSION['csrf']; ?>"/>
    <!-- other form fields -->
    <!-- submit button -->
</form>
uniqid(mt_rand(),true)
不适用于当前值:

它使用具有已知特征的随机数生成器,使用 »Mersenne Twister,可产生四次随机数 比libc rand()提供的平均速度更快

他的函数不会生成加密安全值,并且 不应用于加密目的。如果你需要 密码安全值,考虑使用RealthIn In() 或者改为openssl\u random\u pseudo\u bytes()

random_bytes
openssl_random_pseudo_bytes
返回不可打印的字符,但可以将其转换为十六进制表示形式:

bin2hex(random_bytes($length))
确保nonces缓存存储对其他用户不可用。例如,PHP会话通常保存为/tmp文件夹中的文件。如果正在使用会话,请覆盖其默认行为:

无论如何,我开发并发布了一个nonces库:

以下是使用库创建具有nonce的表单的方法:

<?php
require __DIR__ . '/../vendor/autoload.php';

$form = new \pedroac\nonce\Form\NonceForm(
    'token',
    new \pedroac\nonce\NoncesManager(
      new \Symfony\Component\Cache\Simple\PdoAdapter($pdo)
    )
);
if ($form->isSubmittedInvalid()) {
  /**
   * handle failure
   */
}
if ($form->isSubmittedValid()) {
  /**
   * handle the success
   */
}
?>
<form method="POST">
    <?= new HtmlNonceField($form) ?>
    <input type="submit" name="myform" value="Submit" />
</form>

您也可以这样做:

<?php
require __DIR__ . '/../vendor/autoload.php';

$manager = new \pedroac\nonce\NoncesManager(
    new \Symfony\Component\Cache\Simple\PdoAdapter($pdo)
);
$lastNonceName = $_SESSION['nonce_name'];
if(isset($_POST[$lastNonceName]) && $manager->verifyAndExpire($lastNonceName, $_POST[$lastNonceName])) {
    // handle success
}

$nonce = $manager->create();
session_start();
$_SESSION['nonce_name'] = $nonce->getName();
?>
<form method="post">
    <input type="hidden"
           name="<?= htmlspecialchars($nonce->getName()) ?>"
           value="<?= htmlspecialchars($nonce->getValue()) ?>" />
    <input type="submit" name="myform" value="Submit" />
</form>


不要使用
mt\u rand()
,因为“随机”数是可以预测的-使用
openssl\u random\u pseudo\u bytes()
来阻止任何攻击者成功预测您在其重放攻击中使用的值。但是,这仍然存在一个问题。只要会话处于启动和运行状态,它就容易受到攻击。但是如果会话结束,那么它工作正常。在某种程度上,您是对的,但即使会话已启动并正在运行,它们也需要为每个提交请求提供一个新的nonce。因此,如果他们想重播,他们将需要新的nonce。这称为CSRF保护。但是,如果您想防止用户在登录时强行输入密码,请跟踪错误的密码尝试,并在错误密码数超过三个时显示验证码。从同一ip成功登录后,将错误密码计数器重置为零。