CSRF保护在手机上失败

时间:2018-11-06 22:20:40

标签: php jquery csrf csrf-protection

在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。

此代码是否有某些特定内容可能无法在智能手机中使用?

谢谢

1 个答案:

答案 0 :(得分:4)

您在每次向index.php发送请求时都重新生成CSRF令牌,因此,如果用户在访问表单页面后在新窗口/标签页中打开了某些内容,则当他们尝试提交表单时,其令牌将不会生效表格,这将解释为什么您看到的结果也不一致。我建议改为使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?