我正在尝试将CSRF保护整合到我的表单上,并且我已经开始使用我的注册表单,该表单在添加CSRF令牌之前开始工作,但现在只生成一个"无效或意外的令牌"错误。这是我目前的表格:
<form method="post" name="registration_form" action="<?php echo esc_url($_SERVER['PHP_SELF']); ?>">
<input type="hidden" name="<?= $token_id; ?>" value="<?= $token_value; ?>" />
First Name: <input type="text" name='<?=$form_names['firstname'];?>' id='firstname' /><br>
Last Name: <input type="text" name='<?=$form_names['lastname'];?>' id='lastname' /><br>
Phone: <input type="tel" name='<?=$form_names['phone'];?>' id='phone' /><br>
Email: <input type="email" name="<?=$form_names['email'];?>" id="email" /><br>
Username: <input type="text" name='<?=$form_names['username'];?>' id='username' /><br>
Password: <input type="password"
name="<?=$form_names['password'];?>"
id="password"/><br>
Confirm password: <input type="password"
name="<?=$form_names['passwordconf'];?>"
id="confirmpwd" /><br>
<input type="button"
value="Register"
onclick="return regformhash(this.form,
this.form.<?=$form_names['firstname'];?>,
this.form.<?=$form_names['lastname'];?>,
this.form.<?=$form_names['phone'];?>,
this.form.<?=$form_names['username'];?>,
this.form.<?=$form_names['email'];?>,
this.form.<?=$form_names['password'];?>,
this.form.<?=$form_names['passwordconf'];?>);" />
</form>
</body>
我已经包含了一个带有名称/值对标记的隐藏字段,以及每个名称字段的随机标记。令牌都按预期工作,因此问题不在于生成它们。还有一个Javascript文件验证表单输入,我不知道它是否相关,但这里是js验证:
function regformhash(form, firstname, lastname, phone, username, email, password, confirmpwd) {
// Check each field has a value
if (firstname.value == '' || lastname.value == '' || phone.value == '' || email.value == '' || password.value == '' || confirmpwd.value == '') {
alert('You must provide all the requested details. Please try again');
return false;
}
// Check the First Name
re = /^[A-Za-z\s]+$/;
if(!re.test(form.firstname.value)) {
alert("First Name must contain only upper and lower case letters. Please try again");
form.firstname.focus();
return false;
}
// Check the Last Name
re = /^[A-Za-z\s]+$/;
if(!re.test(form.lastname.value)) {
alert("Last Name must contain only upper and lower case letters. Please try again");
form.lastname.focus();
return false;
}
// Check the Phone Number
re = /\d{3}[\-]\d{3}[\-]\d{4}/;
if(!re.test(form.phone.value)) {
alert("Phone Number must be formatted as follows, xxx-xxx-xxxx or (xxx) xxx-xxxx. Please try again");
form.phone.focus();
return false;
}
// Check the username
re = /^\w+$/;
if(!re.test(form.username.value)) {
alert("Username must contain only letters, numbers and underscores. Please try again");
form.username.focus();
return false;
}
// Check that the password is sufficiently long (min 6 chars)
// The check is duplicated below, but this is included to give more
// specific guidance to the user
if (password.value.length < 6) {
alert('Passwords must be at least 6 characters long. Please try again');
form.password.focus();
return false;
}
// At least one number, one lowercase and one uppercase letter
// At least six characters
var re = /(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}/;
if (!re.test(password.value)) {
alert('Passwords must contain at least one number, one lowercase and one uppercase letter. Please try again');
return false;
}
// Check password and confirmation are the same
if (password.value != confirmpwd.value) {
alert('Your password and confirmation do not match. Please try again');
form.password.focus();
return false;
}
// Create a new element input, this will be our hashed password field.
var p = document.createElement("input");
// Add the new element to our form.
form.appendChild(p);
p.name = "p";
p.type = "hidden";
p.value = hex_sha512(password.value);
// Make sure the plaintext password doesn't get sent.
password.value = "";
confirmpwd.value = "";
// Finally submit the form.
form.submit();
return true;
}
我不知道参数名称是否需要与表单名称匹配,他们之前并没有完成任何操作。
最后,&#34;无效或意外的令牌&#34;错误指向结束</body>
,如果这也有帮助。
更新
我将更深入地了解这个特定CSRF如何为这种特定形式工作。该表单包含另一个名为register.inc.php的php文件,它在向数据库添加数据时执行一系列清理,但我还决定将其用于CSRF检查。这是与CSRF相关的基本代码(注意,我还没有在if语句中添加清理功能,我尝试在没有它之前让表单工作,然后再添加它。我有一个评论,它最终会去):
include 'csrf.class.php';
require 'Sessions/session.class.php';
$session = new session();
// Set to true if using https
$session->start_session('_s', false);
$csrf = new csrf();
// Generate Token Id and Valid
$token_id = $csrf->get_token_id();
$token_value = $csrf->get_token($token_id);
// Generate Random Form Names
$form_names = $csrf->form_names(array('firstname','lastname','phone','email', 'username', 'password','passwordconf'), false);
if(isset($_POST[$form_names['email']], $_POST[$form_names['password']])) {
// Check if token id and token value are valid.
if($csrf->check_valid('post')) {
// Get the Form Variables.
// Add Sanitization function here
}
// Regenerate a new random value for the form.
$form_names = $csrf->form_names(array('email', 'password'), true);
}
以下是此处引用的csrf.class.php:
<?php
class csrf{
public function get_token_id() {
if(isset($_SESSION['token_id'])) {
return $_SESSION['token_id'];
} else {
$token_id = $this->random(10);
$_SESSION['token_id'] = $token_id;
return $token_id;
}
}
public function get_token() {
if(isset($_SESSION['token_value'])) {
return $_SESSION['token_value'];
} else {
$token = hash('sha512', $this->random(500));
$_SESSION['token_value'] = $token;
return $token;
}
}
public function check_valid($method) {
if($method == 'post' || $method == 'get') {
$post = $_POST;
$get = $_GET;
if(isset(${$method}[$this->get_token_id()]) && (${$method}[$this->get_token_id()] == $this->get_token())) {
return true;
} else {
return false;
}
} else {
return false;
}
}
public function form_names($names, $regenerate) {
$values = array();
foreach ($names as $n) {
if($regenerate == true) {
unset($_SESSION[$n]);
}
$s = isset($_SESSION[$n]) ? $_SESSION[$n] : $this->random(10);
$_SESSION[$n] = $s;
$values[$n] = $s;
}
return $values;
}
private function random($len) {
if (function_exists('openssl_random_pseudo_bytes')) {
$byteLen = intval(($len / 2) + 1);
$return = substr(bin2hex(openssl_random_pseudo_bytes($byteLen)), 0, $len);
} elseif (@is_readable('/dev/urandom')) {
$f=fopen('/dev/urandom', 'r');
$urandom=fread($f, $len);
fclose($f);
$return = '';
}
if (empty($return)) {
for ($i=0;$i<$len;++$i) {
if (!isset($urandom)) {
if ($i%2==0) {
mt_srand(time()%2147 * 1000000 + (double)microtime() * 1000000);
}
$rand=48+mt_rand()%64;
} else {
$rand=48+ord($urandom[$i])%64;
}
if ($rand>57)
$rand+=7;
if ($rand>90)
$rand+=6;
if ($rand==123) $rand=52;
if ($rand==124) $rand=53;
$return.=chr($rand);
}
}
return $return;
}
}
提交表单时,它会从会话中的表单中保存CSRF令牌,并将其与Post值中的令牌进行比较。如果两者匹配,则继续代码。这是我用来创建CSRF保护的网站Prevent CSRF。