我的PHP表单Key类出现问题


Something wrong with my PHP form Key class

我将遵循本教程,尝试制作一个PHP表单密钥验证脚本。由于某些原因,我的构造函数没有为$old_formKey变量创建值。

教程提到Singleton更安全,但它没有深入到实现中。我知道Java面向对象编程的基本原理,但对PHP面向对象编程原理了解不多。我只是想通过使类变量为静态来扩展它——我认为这就是我的问题所在。然而,当调用我的构造函数时,它应该给$old_formKey $_POST[form_key]"if isset()"的值

我无法让构造函数将旧formKey的值放在所需的变量空间中。

所以这就是我遇到问题的地方。

<?php
class formKey
{
    private static $formKey;
    private static $old_formKey;
    public function validate()
    {
        echo $_POST['form_key'];
        //We use the old formKey and not the new generated version
        if($_POST['form_key'] == $old_formKey) {
            //The key is valid, return true.
            return true;
        }
        else {
            //The key is invalid, return false.
            return false;
        }
    }
}
?>

我的formKey验证脚本看起来像这样。

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    //Validate the form key
    if(!isset($_POST['form_key']) || !$formKey->validate()) {
        //Form key is invalid, show an error
        $error_msg = 'Security Error.';
        $die = "die";
    }
    else {
        /*continue validation*/
    } 
}
?>

脚本返回错误消息,然后显示它,因为$old_formKeyvalidate()方法内部从未给定值。

由于某些原因,我无法从validate()方法中修改类变量。很抱歉,如果以前已经解决过这个问题。我真的看了看却找不到!

function __construct()
{
    //We need the previous key so we store it
    if(isset($_SESSION['form_key']))
    {
        self::$old_formKey = $_SESSION['form_key'];
    }
}

对不起,我忘了包含我的构造函数。它已添加到上面。

是否扩展formKey类?

class B extend formKey{
    public function validate($formKey, $oldFormKey)
    {
        return $formKey == $oldFormKey;
    }
}

像这样称呼

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
    $oldFormKey = "abc";
    $formKey = new B();
    if (!isset($_POST['form_key']) 
        || !$formKey->validate($_POST['form_key'], $oldFormKey)) {
        //Form key is invalid, show an error
        $error_msg = 'Security Error.';
        $die = "die";
    } else {
        //continue validation 
    } 
}

它可能对您有用,而且,我很好奇"由于某种原因,我无法从validate()方法中修改类变量"

要使变量通过对象(__construct()validate()),您需要在类作用域中分配它们,然后从同一作用域调用它们:

class formKey
    {
        private $formKey,
                $old_formKey;
        public function __construct()
            {
                // I just set to false as default
                $this->old_formKey = false;
                // Assign here
                if(isset($_SESSION['form_key']))
                    $this->old_formKey = $_SESSION['form_key'];
            }
        public function validate()
            {
                // Use $this-> to recall it from the construct
                return ($_POST['form_key'] == $this->old_formKey);
            }
    }

正如我作为评论所写的那样,你提到的教程(如Dagon所写)已经过时,其次是完全伪造的。

这与验证表单无关,本主题的重点是识别表单。

您生成一个唯一的标识符密钥,该密钥由服务器(本例为PHP)生成,以便跟踪表单状态。如果唯一密钥发生变化,与服务器存储的不同,则表单可能会在无法识别的地方被拒绝(这并不意味着表单无效)。

本教程使用了面向对象的方法,所以我会尊重这一点。以下步骤正在进行

  1. 生成一个唯一的密钥并将其存储在用户(或访问者,取决于此处的术语;从现在起,我将把它们描述为usersSESSION
  2. 以窗体形式输出
  3. 在提交时识别表单,并将(未识别)密钥与存储在SESSION 中的

    4.1.当身份符合时验证表单

    4.2.如果无法识别,则拒绝表单

从生成实例开始,类的布局非常简单,它不需要是单例,也不应该静态地包含任何

类的基础可以分为三个部分,创建存储识别

class FormIdentifier {
  const CONTAINER_KEYSPACE = 'form_keys';
  /**
   * Generate a key
   * @return string
   */
  public function generateKey() {
    // you can use any complicated mumbo-jumbo to generate a key instead
    $key = uniqid();
    // store it
    $this->storeKey($key);
    // return for use, e.g. in a form
    return $key;
  }
  /**
   * Store a key into users session
   */
  protected function storeKey($key) {
    session_start();
      $_SESSION[self::CONTAINER_KEYSPACE][] = $key;
    session_write_close();
  }
  /**
   * Identifies a key against the keys in the users stored session.
   * @return true if identified, false otherwise
   */
  public function identifyKey($key) {
    session_start();
      if( ($found = search_array($key, $_SESSION[self::CONTAINER_KEYSPACE])) !== false ) {
        unset($_SESSION[self::CONTAINER_KEYSPACE][$found]);
        session_write_close();
        return true;
      } 
    session_write_close();
    return false;
  }
}

要生成密钥,我们不会将HTML输出与类和方法混合使用。FormIdentifier的目的只是创建存储识别表单密钥,而不是其他。因此,在表单中使用的示例

<form>
  <input type="hidden" name="form_key" value="<?php (new FormIdentifier)->generateKey() ?>" />
</form>

您也可以将返回的密钥存储在某个地方,并以不同的方式使用它,无论您需要什么。

<?php $key = (new FormIdentifier)->generateKey(); ?>
<input type="hidden" name="form_key" value="<?= $key ?>" />

要识别(并最终验证)表单,您可以指定密钥发布的表单,并将其与存储在用户会话中的密钥进行比较。这里使用的结构最有可能向用户显示密钥不匹配的通知。这完全取决于您希望如何实现这一步骤,您可以将其封装在一个函数中,甚至可以将其与类FormIdentifier组合。

/**
 * Simple if/else, a POST was made so act on `form_key`s presence only
 */
if($_POST && array_key_exists('form_key', $_POST)) {  
  if((new FormIdentifier)->identifyKey($_POST['form_key')) {
    // identity was verified  
    // validate your form
    $fv = new FormValidator($_POST);
    // or whatever ..
    $fv->validate();
  }
  else {
    // unable to determine identity
    // do something silly ..
  }
}

一些注意事项

  • 提供的代码均未经过测试
  • 重要的是要意识到,演示逻辑应该与这里所做的所有步骤分开
  • 停止阅读两年以上的教程!如果作者不介意更新内容,那么也不介意阅读