【问题标题】:PHP CSRF Token Script blocking Submit button on my formPHP CSRF 令牌脚本阻止我表单上的提交按钮
【发布时间】:2020-10-15 09:07:24
【问题描述】:

我有一些我正在使用 cookie、会话和 csrf 令牌创建登录页面的 php 脚本。这些脚本是面向对象的并使用类,但是 CSRF 令牌是我表单中的隐藏输入,它阻止了提交按钮的呈现。几个月来我一直在盯着它摆弄它,但我无法弄清楚错误在哪里或为什么它阻止了按钮的呈现,我有错误报告但没有显示任何错误。我也在使用 spl_autoload_register() 函数来加载我的类,但我不认为这是问题所在。任何帮助将不胜感激

注册.php

<?php require_once 'Core/init.php';   
      include 'Core/head.php';

      if(!Usr){                                       // Not doing anything.....
          echo '<span style="color:white;">You must be logged in to view properties</span>';
      }
?>
<h1 style="color:white;">Let Living Be Life</h1>
<h2 style="color:white;">Property Rentals</h2>

<a href="index.php">Home</a><br>
<a href="profile.php">Profile</a><br>
<a href="register.php">Register</a><br>
<a href="login.php">Login</a><br>
<a href="logout.php">Logout</a><br>
<a href="changepassword.php">Change Password</a><br>
<a href="info.php">Info</a><br>

<input type="radio" name="theme-switch"><span style="color:white;">Theme</span>

<form action="" method="post">
    <input id="usrname" type="text" name="usrname"
           placeholder="Username" autocomplete="off" required="true">
    <input id="psw" type="password" name="psw"
           placeholder="password" autocomplete="off" required="true">
    <input type="checkbox" name="remember" id="remember"> <span style="color:white;">Remember me.</span>
    <!-- This is not being rendered either !!!!!!!!!!!!!!!! -->
    <input type="hidden" name="csrf_tokenz" value="<?php echo Token::gen_csrf_token(); ?>"><br>   <!-- Added '' around the echo, but it is not generating a valid token, button is back though...-->
<!-- Note, Something is blocking the button from rendering              ???????????????????? -->
    <button id="Submit_btn" type="submit">Submit</button>
</form>


<a href="index.php">Home</a>
<a href="profile.php">Profile</a>
<a href="register.php">Register</a>
<a href="login.php">Login</a>
<a href="logout.php">Logout</a>
<a href="changepassword.php">Change Password</a>
<a href="info.php">Info</a>

<?php
  // $_SESSION['user-type'] = guest; << need to set this at top of loggin page. aswell as other checks.

    if(Input::inp_exists()){
        if(Token::check_token(Input::post_or_get_inp('csrf_tokenz'))){
            $validate = new Validate();
            $validation = $validate->check_val($_POST, array(
                             'usrname' => array('required' => true),
                             'psw'     => array('required' => true)
            ));
            if($validation->vali_passed()){
              // Log Usr in..
                $usr = new Usr();

                $remember = (Input::post_or_get_inp('remember') === 'on') ? true : false;
                $login = $usr->login_usr(Input::post_or_get_inp('usrname'), Input::post_or_get_inp('psw'), $remember);

                if($login){
                    Redirect::r_to('index.php');
                    echo 'Success';
                }else{
                    echo '<p>Sorry Login Failed</p>';
                }
            }else{
                foreach($validation->vali_errors() as $error){
                   echo $error, '<br>';
                }
            }
        }
    }
?>

Token.class.php

<?php                                                           // Check all Syntax::>> 

  class Token{
    public static function gen_csrf_token(){                                  // Csrf Token 1.
        return Session::sesh_put(Config::get_conf('session/token_name'), bin2hex(random_bytes(28)).openssl_random_pseudo_bytes(7));   // md5(uniqid()) md5(random_bytes(164))<< this is the old version which is deprecated...
        }
    public static function gen_csrf_token2(){                                 // Csrf Token 2.
        return Session::sesh_put(Config::get_conf('session/token2_name'), bin2hex(random_bytes(28)).openssl_random_pseudo_bytes(7));  // ::>> Brackets maybe wrong way round in here.            
        }
    public static function genchilli_token(){                                 // Use this to Build a Pepper, Salt is in the Hash Class. Abstract Away.. 
          $Chilli = bin2hex(128).=openssl_random_psuedo_bytes(48).=md5('x12ii21ii12x');
          return $Chilli;           // <<:: Test me?
          }
    public static function check_token($token){
                                                                                // echo 'I have been run line 15 Token Class';
        $token_name = Config::get_conf('session/token_name');         // ::>> index=12
                                                                                // echo 'I have been run line 16 Token Class';
        if(Session::sesh_exists($token_name)&& $token === Session::get_sesh($token_name)){
            Session::del_sesh($token_name);
            return true;
        }
        return false;
    }
  }

Token 类依赖于 Session 和 Conig 类来工作。 即功能: Session::sesh_put() & Config::conf_get() 但我在这里找不到任何错误 或者,并且没有显示任何错误。

Session.class.php

<?php
  class Session{
        public static function get_sesh($name){
            // echo 'Debug Only >> Session::Get Ran';
            return $_SESSION[$name];                                            // ::<< these relate to Token Name in Token.class.php

        }
        public static function sesh_put($name, $value){
            // echo 'Debug Only >> Session::put Ran';
            return $_SESSION[$name] = $value;

        }
        public static function sesh_exists($name){
            // echo 'Debug Only >> Session::exists Ran';
            return (isset($_SESSION[$name])) ? true : false;
        }
        public static function del_sesh($name){
            if(self::sesh_exists($name)){
                unset($_SESSION[$name]);
            }
        }
        public static function sesh_flash($name, $string = ''){                      // Used for flashing a msg to user.
            if(self::sesh_exists($name)){                                            // Flash eps 13            // Not returning any messages for some reason..
                $session = self::get_sesh($name);
                self::del_sesh($name);                                            // This deletes the session
                return $session;
            } else {
                self::sesh_put($name, $string);
              }
        }
  }
  
  // After done upload to code review
?>

配置.php

<?php                      // ::>> This File Has no Errors.        Upto eps 8 No errors spotted so far..

  class Config{                                     // ::>> Need to build in here a check for Faulty Paths then Exit script. destroy session, log user out. 
      public static function get_conf($path = null){
          if($path){
              $config = $GLOBALS['config'];
              $path = explode('/', $path);
              
              foreach($path as $bit){
                  if(isset($config[$bit])){
                      $config = $config[$bit];
                  }
              }return $config;
          }return false;
      }
  }

init.php

<?php
    session_start();
    error_reporting(E_ALL & E_NOTICE); 
       ini_set('display_errors', 1);
       ini_set('display_startup_errors', 1);

    $GLOBALS['config'] = array(
        'mysql' => array(
            'host'    => 'localhost', // ::> 127.0.0.1 
            'charset' => 'redacted',
            'db-usr'  => 'redacted',
            'db-psw'  => 'redacted',
            'db'      => 'redacted',
            'ssh'     => 'false',                   // ::<< I added these last three for later Updates to Determine access via these three methods.
            'cli'     => 'false',                   // <<::   Need very strong Authentication If I every choose to use these.
            'cgi'     => 'false'                    // ::>>        Set-up two factor Authentication at some point.
             ),
        'remember' => array(
            'cookie_name'   => 'hashish_cookie',
            'cookie_expiry' => '784828'
            // 'preferences'   => array(            // <<:: I added this for later functionality.
            //           'usr_pref' => 'has_cat',
            //           'needs'    => 'null'
            //            ),
             ),
        'session' => array(                        // Add different Session types in here ie. Guest, Admin, Mod, ExtMod, RootAd, HasCat.
            'session_name' => 'usr_session',
            'token_name'   => 'csrf_tokenz',
            'token2_name'  => 'csrf_tokenz2',
            'hacker_bait'  => 'redacted',
            'has_cat'      => '0'
             )
    );                                          // Closing Tag for Globals Array
    spl_autoload_register(function($class) {
        require_once 'Classes/' . $class . '.class.php';
    });
    require_once 'Functions/sanitize.php';
    
    if(Cookie::cookie_exists(Config::get_conf('remember/cookie_name')) && !Session::sesh_exists(Config::get_conf('session/session_name'))){
        echo 'User Asked to Be remembered!';
        $hash = Cookie::get_cookie(Config::get_conf('remember/cookie_name'));
        $hashCheck = DB::getInstance()->get_dbr('usr_session', array('hash', '=', $hash));   // <<:: Check if this is xx >> usr_session << Correct one < or usrs_session..
        
        if($hashCheck->count_dbr()){
            echo 'Hash matches, log usr in';
        } // Unsure if this is dbr_count or count_dbr or a built in pdo version of count?

    }
?>

任何帮助或指示将不胜感激,因为我找不到错误及其困扰我。当我重新登录到我的托管站点后,将在一分钟内更新问题并包含 config.php。我已经尝试使用 md5、uniqid、random_bytes、ssl_random_pseudo_bytes 和多种不同的组合,但无法使其正常工作。我知道关于如何安全地生成 CSRF 令牌还有许多其他问题,但我发现没有一个问题是使用类或面向对象的程序,它们也没有解决我的具体问题。我已经阅读了多个不同的,其中一些有助于我理解但没有解决这个问题。

图像显示正在渲染的内容以及停止或中断的位置。 正如 Mike 在 cmets 中建议的那样使用 Ctrl + U。

更新,在阅读 Mike 分享的帖子后,刚刚在 E_NOTICE 错误报告中添加了一个 ~:Error Reporting,它生成了一个以前没有显示的新通知,因此这可能有助于解决这些问题。图片如下:

修正:注释掉辣椒函数的内部......

【问题讨论】:

  • 当你说当你输出 CSRF 令牌时它会阻止提交按钮呈现,这向我表明正在回显一条错误消息并使你的页面具有无效的 HTML,这就是为什么它不是被渲染到屏幕上。除非您在生成页面后使用某种输出缓冲和操作页面,否则没有理由不存在提交按钮。您需要查看实际的输出页面源,而不是浏览器如何决定将其呈现到屏幕上。
  • 另外,根据this answerbin2hex(random_bytes(32)) 应该足以生成 CSRF 令牌。我建议坚持使用它,而不是使用不同的随机数生成器来复杂化。
  • @Mike 感谢您的回复我已经在 Firefox 开发者版的 devtools 中检查了源代码,但未包含隐藏输入字段,它应该显示生成的令牌灰色且非可编辑,但它甚至没有显示,所以在 php 的某个地方有一个错误,ps 我没有使用任何缓冲区..
  • 你还是找错地方了。开发工具不会向您显示您想要什么,因为这是浏览器解析 HTML 的方式。您需要查看页面的实际源代码。按 Ctrl-U。
  • 在评论中的代码之后输出是否突然结束?如果没有,请将其发布在您的问题中。如果确实这样结束,请检查您的日志文件。它很可能会产生某种错误或异常,从而在那时杀死脚本。

标签: php html csrf


【解决方案1】:

您收到的错误消息让我陷入了一个循环,因为错误中的行号不是与产生错误的代码中的同一行,这意味着您必须在您发布问题和发布错误消息之间更新了您的代码。请务必确保您发布的错误消息是通过执行您拥有的代码实际产生的错误消息,否则任何人都无法重现您的错误。

你的问题是这一行:

$Chilli = bin2hex(128).=openssl_random_psuedo_bytes(48).=md5('x12ii21ii12x');

这是一个语法错误,应该是这样的:

$Chilli = bin2hex(128) . openssl_random_psuedo_bytes(48). md5('x12ii21ii12x');

或者这个:

$Chilli = bin2hex(128);
$Chilli .= openssl_random_psuedo_bytes(48);
$Chilli .= md5('x12ii21ii12x');

【讨论】:

  • 问题最底部显示的错误代码是在我将 tilda ~ 添加到错误报告的 E_NOTICE 部分后出现的代码,我只截取了以下代码按照您的建议按 Ctrl + U 显示。
  • @RyanStone 请参阅meta.stackoverflow.com/questions/285551/…,了解您不应发布代码截图的原因。
  • 我只是发布了那个屏幕截图来回应你说按下 Ctrl+U 以便人们可以看到结果是什么..
  • @RyanStone 该文本也可以复制和粘贴。
【解决方案2】:

您是否尝试过使用&lt;?php echo Token::gen_csrf_token(); ?&gt; 以纯文本形式显示生成的令牌?

如果您尝试过,它是您所追求的并且可用于“隐藏”标签的令牌字符串吗?

【讨论】:

  • 刚试过这个,但是在我的 Token 类、Session 类或我的配置文件中的某个地方有一个错误,但它无法在我的生活中找到它在哪里,希望 php 错误报告是更健壮或更深入。屏幕上绝对没有错误,在我的日志文件或错误文件中......只是要继续路由直到我找到它......这个回显不输出任何东西,只是空白
猜你喜欢
  • 2017-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 2011-10-15
  • 2014-11-16
相关资源
最近更新 更多