【问题标题】:Protect form with session token使用会话令牌保护表单
【发布时间】:2016-09-07 18:24:39
【问题描述】:

我编写了一个脚本来使用会话令牌保护我的表单;但是,如果我在检查令牌之前尝试验证表单字段,我的脚本将不起作用。有人能帮我弄清楚我的脚本有什么问题吗?

<?php
          session_start();
          class TOKEN {
            public static function generate() {
              return $_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(15));
            }
            public static function check($token) {
              if (isset($_SESSION['token']) && $token === $_SESSION['token']) {
                unset($_SESSION['token']);
                return true;
              }
              return false;
            }
          }
        ?>
        <?php
          $display_form = FALSE;
          if (isset($_POST['submit'])) {
            $username = $_POST['username'];
            $userpass = $_POST['userpass'];

            if (strlen($username) < 4) {
              $error_name = 'required';
              $display_form = true;
              $validation_error = true;
            }
            if (strlen($userpass) < 8) {
              $error_pass = 'required';
              $display_form = true;
              $validation_error = true;
            }
            if (!$validation_error) {
              if (TOKEN::check($_POST['token'])) {
                echo 'process form';
              } else {
                echo 'invalid security token';
              }
            }
          } else {
            $display_form = TRUE;
          }
        ?>
        <!DOCTYPE html>
        <html lang="en">
        <head>
          <meta charset="UTF-8">
          <title>Title</title>
        </head>
        <body>
        <?php
          if ($display_form == true) {
        ?>
        <form method="post" action="<?php echo htmlspecialchars($_SERVER['REQUEST_URI']); ?>">
          <input type="hidden" name="token" value="<?php echo TOKEN::generate(); ?>">
          <input type="text" name="username" id="" placeholder="username">
          <?php echo $error_name; ?>
          <br>
          <input type="password" name="userpass" id="" placeholder="Password">
          <?php echo $error_pass; ?>
          <br>
          <input type="submit" name="submit" value="Sign in">
        </form>
        </body>
        </html>
        <?php
         }
        ?>

【问题讨论】:

  • 你检查过生成的html吗?你检查过$_POST吗?
  • 是的,我做到了,令牌是在 html 中生成的。如果我提交的表格没有任何错误,它就可以工作。但是,如果需要一个或两个字段并且我修复了字段验证然后提交表单,它会显示无效的安全令牌。

标签: php forms token


【解决方案1】:

我想这里的问题出在下面。

  1. 您在 form 中有令牌,在 session 中有令牌。他们是平等的。
  2. 当您填写错误的表单时 - 您的表单会再次加载。但!在 session 中,您有前一个令牌,从第 1 点开始,在 form 中您有新令牌。
  3. 您再次提交并检查不同的令牌。

所以,解决方案是unset 令牌总是,无论您在表单中的值是错误的还是正确的。

更新:

我想应该是这样的:

if (!$validation_error) {
  // here token will be removed in `TOKEN::check`
  if (TOKEN::check($_POST['token'])) {
    echo 'process form';
  } else {
    echo 'invalid security token';
  }
} else {
  // remove token implicitly
  TOKEN::remove();
}

TOKEN:

public static function check($token) {
  $result = false;

  if (isset($_SESSION['token'])) {
    if ($token === $_SESSION['token']) {
      $result = true;
    }
    // if token set - remove it
    self::remove();
  }

  return $result;
}

public static function remove() {
  unset($_SESSION['token']);
}

【讨论】:

  • u_mulder,你是绝对正确的,这就是正在发生的事情,你能告诉我我需要在哪里包含未设置的令牌吗?那是我应该做的吗: unset($)SESSION['token']);
  • 在应用上述解决方案后仍然获得无效的安全令牌
【解决方案2】:

这段代码很难阅读。我不知道 if 语句何时开始和结束。也停止使用类的一切。像个大男孩一样使用过程式编程。

您的问题很简单。 $validation_error 未在外部范围内初始化。这意味着它没有在 if 语句之间保存。

要解决此问题,只需在外部范围添加 $validation_error = false

...
$display_form = FALSE;
$validation_error = false; // right here
          if (isset($_POST['submit'])) {
            $username = $_POST['username'];
            $userpass = $_POST['userpass'];
            ...

【讨论】:

    猜你喜欢
    • 2014-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-05
    • 2010-09-13
    • 2011-09-02
    • 2017-01-31
    • 2011-05-08
    相关资源
    最近更新 更多