设置auth_token的功能

时间:2011-02-15 15:09:10

标签: php forms token

在我的表格中,我有一个隐藏的字段:

<input type="hidden" name="auth_token" value="<?php echo $auth_token; ?>">

此值也存储在会话和变量中:

$_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);  #  TODO: put this in a function
$auth_token = $_SESSION['auth_token'];

提交表单时,会比较两个值。这是一个基本的表单令牌。

这应该被制作成两个函数,还是只有一个函数被重构? set_form_token()get_form_token(),get_form_token()返回会话值,然后我可以在主代码中对它进行比较。这样做的正确方法是什么?

修改

考虑到Joel L和RobertPitt的答案,我已经做了这些:

function set_auth_token()
{
   if (!isset($_SESSION['auth_token']))
   {
      $_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
   }
}

function get_auth_token()
{
   if (isset($_SESSION['auth_token']))
   {
      return $_SESSION['auth_token'];   
   }
   else
   {
      die('No auth token.');
   }
}

function check_auth_token()
{
   if (array_key_exists('auth_token', $_SESSION) && array_key_exists('auth_token', $_POST))
   {
      if ($_SESSION['auth_token'] === $_POST['auth_token'])
      {
         # what happens if user fills the form in wrong first time(?)
         $_SESSION['auth_token'] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
      }
      else
      {
         return false;
      }
   }
   else
   {
      return false;
   }
}

然后我可以检查check_auth_token是否返回false,然后在提交表单后记录它。这可以接受吗?

2 个答案:

答案 0 :(得分:1)

在我的应用程序中,我实际上有以下帮助函数来使用标记:

generateToken() // generate and return hash, used in login process.
                // hash then saved to session

getToken() // returns user's token from session

tokenField() // shortcut for echo '<input type="hidden" ... value="getToken()" />';
             // used in page templates

checkToken() // get token from either 1) $_POST 2) request header or 3) $_GET
             // and compare with getToken(). generate error if invalid.

checkToken()函数检查3个位置,因为请求可以是GET或POST,其中任何一个都可以通过AJAX。我让我的AJAX助手自动在每个请求的标题中插入令牌。)

这样,我只需要在需要检查的地方调用checkToken(),因此可以非常轻松地更改impelmentation细节。

例如,我只需更改getToken()checkToken()即可开始使用一次性令牌。

如果您在代码中的任何位置手动比较if (get_form_token() == $token),则没有这种灵活性。

答案 1 :(得分:0)

首先,您应该准确理解工作流程是什么,Joel L非常简单地解释了这一点。

你应该将方法封装在一个类中以保持所有内容,例如sp:

class FormTokenizer
{
    private $context = "";

    public function __construct($auth_token = "auth_token")
    {
        $this->context = $context;
    }

    public function generateToken()
    {
        $_SESSION[form_tokens][$this->context] = hash('sha256', rand() . time() . $_SERVER['HTTP_USER_AGENT']);
        return $this;
    }

    public function getToken()
    {
        return isset($_SESSION[form_tokens][$this->context]) ? $_SESSION[form_tokens][$this->context]  : false;
    }

    function generateField()
    {
        return sprintf('<input type="hidden" name="a_%s" value="%s">',$this->context,$this->getToken());
    }

    public function validateToken()
    {
        if(isset($_POST["a_" . $this->context]))
        {
            return $this->getToken() == $_POST["a_" . $this->context];
        }
        return false;
    }
}

,一个简单的用法是:

$Token = new FormTokenizer("registration");

if(isset($_POST))
{
    if($Token->validateToken() === false)
    {
        //Token Onvalid
    }
}

//Generate a fresh token.
$hidden_input = $Token->generateToken()->generateField();