【问题标题】:Storing PHP token in session but it keep changing automatically在会话中存储 PHP 令牌,但它会自动更改
【发布时间】:2015-05-22 17:45:26
【问题描述】:

我有一个表格,我希望它尽可能安全。所以我有这个生成表单令牌的函数。

     function generateFormToken($form) {

       // generate a token from an unique value
        $token = hash('sha256', uniqid(microtime()));  
        // Write the generated token to the session variable to check it against the hidden field when the form is sent
        $_SESSION[$form.'_token'] = (string)$token; 

        return $token;
     }

以下是它的激活方式:

       if (empty($_POST)){
           $newToken = generateFormToken('form1');
       }

这是我用来检查的函数:

 function verifyFormToken($form) {

    // check if a session is started and a token is transmitted, if not return an error
    if(!isset($_SESSION[$form.'_token'])) { 
        return false;
    }

    // check if the form is sent with token in it
    if(!isset($_POST['token'])) {
        return false;
    }

    // compare the tokens against each other if they are still the same
    if ($_SESSION[$form.'_token'] !== $_POST['token']) {
        return false;
    }

    return true;
   }

我的 HTML 表单有一个隐藏的输入,我在其中放置了新的令牌变量。该表格正在通过form action="#" 发送到同一页面。

我遇到的问题是,由于某种原因,当页面刷新时,即使函数没有再次调用,令牌在会话中也会发生变化,但在表单中保持不变。

我真的很迷茫,因为我认为要求 PHP 在会话中存储一个字符串在这些条件下刷新页面时它不会改变,但它总是给我不同的响应。我试图在它进入函数之前调用die(),以确保该函数没有以某种方式再次加载到脚本中的更远位置,但没有任何反应。理论上应该不会刷新。

请帮帮我。

这是 HTML 表单:

    <form action="#" method="POST" id="form1">
        <label for="firstname">Firstname</label>
        <input type="text" name="firstname">
        <input type="hidden"name="token" value="<?= $newToken; ?>">
    </form>

这是我在页面顶部使用的验证逻辑:

    $msg = "";
    //If the form has been filled
    if (!empty($_POST)){
       //If the form has been sent from our website
       if (verifyFormToken('form1') == true){
           //TODO CAPTCHA
           if (1 == 1){
              //Everything's fine
           }
           else{
             $msg = 'Veuillez cocher la case «Je ne suis pas un robot».';
           }
        }
    //Else, user tried to send data with his own script (Possible XSS attack)
    else{
        $msg = 'Veuillez utiliser le formulaire directement sur notre site Web afin d\'appliquer sur l\'offre d\'emploi';
    }
}
else{
    //If form is not sent, we generate a new token and store it in the user's session
    $newToken = generateFormToken('form1');
}
if (!empty($msg)){
    echo $msg;
}

【问题讨论】:

  • 您确定该函数没有再次运行?您是否尝试过print_r($_POST) 以确保它是空的。尝试在函数内添加echo 语句,看看它是否在每次刷新时都被命中。
  • 100% 确定...,我试过了,但没有任何回应
  • 您的隐藏属性不包含名称属性,并确保在您的服务器上启用短标签
  • 如果您发布的不是您的“实际”代码,那么我不喜欢猜测。如前所述,请确保您开始了会话。太多未知数。
  • 您说您的“真实”和“实际”代码包含它的名称属性。好吧,这告诉我,你的代码的其他部分可能不是它们应该是的,这是有风险的,我无法测试这个;不是不知道我真正在处理什么。您需要调试您的代码,因为我已经在一开始就已经给了您一些相关的内容。祝你好运。

标签: php forms session


【解决方案1】:

通常,当$_SESSION 令牌发生变化时,即使您正确设置了它,那是因为您没有正确设置session_start()

尝试查看文件的开头并在此处添加session_start()(如果您还没有的话)

【讨论】:

  • 10 次中有 9.9 次,OP 回来并说它已启动。但是……你可能是对的,你可能是对的。
  • 看到我告诉你的了吗? ^
  • 但它是否也设置了 cookie?否则可能会丢失
  • @Fred-ii- ...我认为这个 OP 会是 .1
  • @Crackertastic 是的,统计数据不像以前那样有效。总是有那个 "je ne sais quoi" ;-)
【解决方案2】:

您的代码中缺少一个结束分号:&lt;input type="hidden" value="&lt;?= $newToken ?&gt;"&gt;。这 -> $newToken;

【讨论】:

  • 遗憾的是,正如我所说,输入中的令牌正在通过 POST 标头完美发送,即使没有调用该函数,会话变量也会不断变化
【解决方案3】:

以下内容已经过测试。

Apache版本:2.2.29,PHP版本:5.4.24,MySQL版本:5.5.42-37.1,架构:x86_64,操作系统:linux

form.php

<?php
include('so-sessions.php');

$form = "form1"; // set form id

// check if form has been submitted
IF (isset($_POST['token'])) {

    $msg = ""; // default response

    // Validate Token
    IF (VerifyFormToken($form)) {

        $msg = "Token is valid";

    }ELSE{

        $msg = "Token is invalid";

    }

    echo("<p>".$msg."</p>");

}ELSE{
    // form not submitted

    $token = Set_TokenSession($form); // Set token

    // debugging
    echo("<p>Token: ".$token."</p>");

    // form
    echo('
    <form action="#" method="post" id="'.$form.'">
        <input type="hidden" name="token" value="'.$token.'">
        <label for="firstname">First Name: </label><input type="text" name="firstname" />
        <input type="submit" name="submit" value="submit" />
    </form>');

}
?>

so-sessions.php

<?php
Function HasSessionStarted() {

    $result = false; // default to false

    // Check if session has started
    IF ((session_status() == PHP_SESSION_NONE) || (session_id() == '')) { 
        $result = true; 
    }

    return $result;

}

Function GenerateFormToken() {

    // Create token
    $result = hash('sha256', uniqid(microtime())); 

    return $result;

}

Function Set_TokenSession($form) {

    $new_session = HasSessionStarted(); // Check Session Status
    $token = GenerateFormToken(); // Create token

    // If the session hasn't started do so
    IF ($new_session) { session_start(); }

    // Unset any pre-set token
    Unset_TokenSession($form);

    // Set new session token
    $_SESSION[$form.'_token'] = $token;

    // End the current session and store session data
    IF ($new_session) { session_write_close(); }

    return $token;

}

Function Unset_TokenSession($form) {

    $new_session = HasSessionStarted(); // Check Session Status
    IF ($new_session) { session_start(); }

    // Unset session token
    IF (isset($_SESSION[$form.'_token'])) { unset($_SESSION[$form.'_token']); }

    // End the current session and store session data
    IF ($new_session) { session_write_close(); }

}

Function VerifyFormToken($form) {

    $result = false; // default result to fail

    $new_session = HasSessionStarted(); // Check Session Status
    IF ($new_session) { session_start(); }
    $sesstoken = $_SESSION[$form.'_token']; 
    Unset_TokenSession($form); // Unset the used token 
    IF ($new_session) { session_write_close(); }

    // debugging
    #echo("<!-- Tokens (Form/Session) : ".$_POST['token']." / ".$sesstoken." -->");

    // check if session and post token are not empty
    IF ((!empty($sesstoken)) && (!empty($_POST['token']))) { 

        // compare the tokens against each other 
        IF ($sesstoken == $_POST['token']) {
            $result = true;
        }

    }

    return $result;

}
?>

【讨论】:

  • 您能否解释一下,以便访问该问题的人知道发生了什么?
  • 由于我已经在文档开头开始了会话,因此它无法正常工作,同样的错误
  • @Fred -ii- .. 更好? @Yann Chabot ...您是刷新页面还是提交表单?
  • 您复制并粘贴了完整的代码(两个文件)并运行它?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
  • 2018-05-06
  • 1970-01-01
  • 2021-01-07
  • 2018-02-05
  • 2011-06-14
  • 2018-08-02
相关资源
最近更新 更多