在我的表格中,我有一个隐藏的字段:
<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,然后在提交表单后记录它。这可以接受吗?
答案 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();