Php 唯一表单令牌禁用用户的多任务处理

Php 唯一表单令牌禁用用户的多任务处理,php,forms,token,csrf,csrf-protection,Php,Forms,Token,Csrf,Csrf Protection,如果我想保护我的站点和用户免受跨站点伪造(CSRF)攻击,我可以生成一个唯一的令牌$token=md5(time()*rand)。令牌在隐藏的输入字段echo''中提交并同时存储在会话变量$\u session['token']=$token中 我将检查任何提交的表单上是否存在($\u POST['token']==$\u SESSION['token']),并相应地继续 然而,有些用户可能会同时处理多个任务。这是我在发布本文时正在做的事情 在撰写我的文章时,我打开不同的窗口/选项卡,可能会研究

如果我想保护我的站点和用户免受跨站点伪造(CSRF)攻击,我可以生成一个唯一的令牌
$token=md5(time()*rand)有表单的每页上编码>。令牌在隐藏的输入字段
echo''中提交
并同时存储在会话变量
$\u session['token']=$token中

我将检查任何提交的表单上是否存在($\u POST['token']==$\u SESSION['token'])
,并相应地继续

然而,有些用户可能会同时处理多个任务。这是我在发布本文时正在做的事情

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

但如果我在我的网站上这样做——也就是说,在撰写帖子/表单的同时浏览其他页面——每次我从我的网站上调出不同的页面时,我的
$token
都会重新生成。使我正在处理并最终要提交的表单上的隐藏
输入
标记不正确,因为它不再匹配
$\u会话['token']
变量,该变量在我访问其他页面时重新生成

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


我希望允许我的用户执行多任务,并希望受到CSRF的保护…

即使在选项卡和窗口之间,浏览器也应保持正确的会话id。会话id应相同。(应跨浏览器测试危险假设以确保)

根据会话id生成更多应有效的令牌

所以你可以检查一下这样的东西

$tokenCorrect = false;

foreach($_SESSION['tokens'] as $token) {
  if ($token !== $_POST['token'])
     continue;
  $tokenCorrect = true;
}

if ($tokenCorrect == false) {
   die(); // 
   // Maybe log to database ?? but watch if possible Denial of Service because somebody can write your disk/ shared diskspace full with only making fast requests with a invalid CSRF token
}

我也有同样的问题,你说,因为单一的CSRF,它会被替换,除非他们提交最新的页面,但如果你使用阵列w/会话,它应该解决你的问题。另外,你可能想包括一个验证码,我推荐谷歌的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
        }
    }
}

我不知道一个令牌是如何阻止这一切的。一个唯一的令牌应该用来阻止CSRF,可以在GET或POST中使用requests@RaymondN:是的,这正是我正在做的,对吗?在我看来,您在$\u会话中存储了1个令牌['token']?@olli令牌如何阻止攻击者将请求嵌入到您的“带令牌的页面”,并获取令牌并发出请求?很好,这是一个好主意!正在生成多个令牌,这些令牌将在一段时间后过期。。。谢谢你给我的小费@奥利:下一步,你可能需要添加类似于recaptcha的内容。我确实在我的网站的某些地方使用recaptcha,通常只在我希望防止暴力攻击的地方使用。。。我想不出一个场景,在这个场景中,暴力使用令牌进行CSRF是现实可行的…?好主意,谢谢!类的实现更高级,所以我选择它作为最佳答案。。。据我所知,会话ID在浏览器选项卡之间保持不变,因为它是在服务器上生成的(在开始编程之前,我做了一系列测试,以了解一些基本知识)和将用于标识一个用户。关于将在服务器上生成会话,为true,但如果客户端再次请求而没有该会话id,则将在服务器上生成新会话。当新窗口打开时,浏览器可能会拒绝所需的会话id,因此需要对其进行测试,但我知道firefox和IE不会在这里造成问题
<input type="hidden" name="token" value="<?php createToken(); ?>">
if(isset($_POST['token']) && checkToken($_POST['token'])){
    #valid token
}else{
    #create error message saying that they tried to repost data or session token expired
}