php - 唯一的表单 token 禁用用户的多任务处理

标签 php forms token csrf csrf-protection

如果我想保护我的站点和用户免受跨站点伪造 (CSRF) 攻击,我可以生成一个唯一 token $token = md5( time() * rand );在具有表单的每个页面 上。 token 是在隐藏的输入字段中提交的 echo '<input type="hidden" name="token" value="'.$token.'">';同时存储在 session 变量中 $_SESSION['token'] = $token; .

我会检查是否在任何提交的表格上 if($_POST['token'] == $_SESSION['token'])并相应地进行。

但是有些用户可能会同时处理多项任务。这是我在发布此内容时实际上正在做的事情。

在撰写我的帖子时,我会打开不同的窗口/选项卡来研究信息或查看有关堆栈溢出的其他一些问题。堆栈溢出让我可以毫无问题地提交表单。

但如果我要在我的网站上这样做 - 意味着浏览其他页面,同时仍在撰写帖子/表格 - 我的 $token每次我从我的网站上拉出不同的页面时都会重新生成。制作隐藏的input我正在处理的表单上的标记,最终想提交不正确,因为它不匹配 $_SESSION['token']变量不再存在,当我访问不同的页面时它已经重新生成......

有什么好的想法可以防止这个问题,或者有什么更好的解决方案来首先阻止 CSRF 吗?

我想允许我的用户执行多项任务并希望免受 CSRF...

最佳答案

由于单个 CSRF,我遇到了与您陈述的内容相同的问题,除非他们提交最新页面,否则它会被替换,但是如果您使用带 session 的数组,它应该可以解决您的问题。此外,您可能还想添加一个验证码,我推荐使用 Google 的 Recaptcha。

session_start();
function createToken(){
    $token = sha1(uniqid(mt_rand(), true));
    $_SESSION['Tokens']['Token'][] = $token;
    $_SESSION['Tokens']['Time'][] = time() + (10 * 60); #10 min limit
    #you can omit/change this if you want to not limit or extend time limit
    return $token;
}

function checkToken($token){
    clearTokens();
    foreach($_SESSION['Tokens']['Token'] as $key => $value){
        if($value === $token){
            return true;
        }
    }
    return false;
}

function clearTokens(){
    foreach($_SESSION['Tokens']['Time'] as $key => $value){
        if($value <= time()){
            unset($_SESSION['Tokens']['Token'][$key], $_SESSION['Tokens']['Time'][$key]);
            #remove last parameter if you aren't using token time limit
        }
    }
}

您的 HTML:

<input type="hidden" name="token" value="<?php createToken(); ?>">

PHP token 检查器

if(isset($_POST['token']) && checkToken($_POST['token'])){
    #valid token
}else{
    #create error message saying that they tried to repost data or session token expired
}

关于php - 唯一的表单 token 禁用用户的多任务处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18238614/

相关文章:

html - 带有信息的 Django HTML POST 删除按钮

ajax - 为什么 $form_state 中的 'triggering element' 是表单上的最后一个按钮?

c# - If 语句跳过 for 循环中除第一个元素之外的元素。我怎样才能为其他元素找到正确的解决方案?

mysql - 使用bindParam的pdo更新显示绑定(bind)变量数量与 token 数量不匹配的错误

c - 关于 LINUX 中的段错误

php - foreach 和 simplexml

php - 循环遍历动态 mysql 数据数组时遇到问题

php - 在 html 标签中的鼠标悬停中的 setTimeOut 函数中使用 php 变量

php 页面给出 500 错误,但通过 ssh 执行有效

string - 在for循环中获取 token 的子字符串?