CSRF 保护在手机上失败

CSRF protection failing on mobiles

在 index.php 内,我已将其放在顶部

<?php
session_start();

function generate_secure_token($length = 16)
{
    return bin2hex(openssl_random_pseudo_bytes($length));
}

$_SESSION['csrf_token'] = generate_secure_token();
$token = $_SESSION['csrf_token'];

?>

然后在我的表单中有一个隐藏字段

<input type="hidden" name="csrf_token" id="csrf_token" value="<?php echo $token; ?>">

在我的 Javascript 中,我提出了一个 Ajax 请求

submitHandler: function(form) {
    $.ajax({
        type: "POST",
        url: "php/process.php",
        dataType: "json",
        data: {
            'csrf_token': $("#csrf_token").val()
        }
    }).done(function(response) {
        if (response === 'success') {
            window.location.replace("thanks.php");
        }
    }).fail(function(jqXHR, textStatus) {
        return false;
    });
}

最后在 process.php 我检查了 CSRF

<?php
session_start();

$errors = array();
$userData = array();

if (!isset($_POST['csrf_token']) ||
    empty($_POST['csrf_token']) ||
    $_POST['csrf_token'] != $_SESSION['csrf_token']) {
    $errors['csrf_token'] = 'Something went wrong';
}

if (!empty($errors)) {
    echo json_encode('failure');
    sendErrorEmail($errors, "Validation", $userData, __LINE__);
} else {
    //Do something
}

我注意到我收到了很多与未设置 CSRF 令牌相关的错误电子邮件。在 sendErrorEmail 内,我向自己发送失败的浏览器信息,我注意到其中 90% 是 IPhone 或 Android。

此代码是否有任何可能无法在智能手机中运行的特定内容?

谢谢

您在 index.php 的每个请求上重新生成 CSRF 令牌,因此如果用户在访问表单页面后在新的 window/tab 中打开某些内容,他们的令牌将不会在他们尝试提交表格,这将解释为什么您看到的结果也不一致。我建议让 CSRF 令牌在用户的整个会话中持续存在:

<?php
session_start();

function generate_secure_token($length = 16)
{
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(openssl_random_pseudo_bytes($length));
    }
}

generate_secure_token();

使用 CSRF 令牌的目的是防止远程网站导致当前登录的用户在您的网站上执行不需要的操作。为了执行该操作,需要一个令牌,并且此令牌仅由您的 Web 应用程序提供。如果令牌是伪随机生成的(如您的情况),则基本上不可能猜测它,因此在每个请求上重新生成令牌不会增加整体安全性,除非您的应用程序存在某种其他漏洞(例如 XSS ) 然后可能导致令牌被泄露回恶意网站。

另请参阅:New CSRF token per request or NOT?