提交在 codeigniter 中启用 CSRF 保护的表单后出现内部服务器错误
Internal server error after submitting a form with CSRF protection enabled in codeigniter
我正在使用 Codeigniter 3.1.3 并在配置文件中启用了 CSRF 保护。如果表单通过验证,我总是从 ajax $.post 得到 500(内部服务器错误)。如果验证失败,我不会收到该错误。有什么想法吗?
这是 codeigniter 配置文件中的 csrf 设置:
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;
这是我在视图中的登录表单 login.php:
<form id="login_form" class="col-12 col-md-8 mx-auto" method="post">
<div class="alert" id="login-alert" role="alert"></div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon1">Username</span>
<input type="text" class="form-control" id="username" name="username" />
</div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon2">Password</span>
<input type="password" class="form-control" id="pwd" name="pwd" />
</div>
<div class="text-center">
<button type="button" id="login_btn" class="btn btn-primary">LOGIN</button>
</div>
</form>
我正在使用 AJAX $.post 提交表单
$("#login_btn").click(function(){
var data = $("#login_form").serialize();
var csrf_name = "<?=$this->security->get_csrf_token_name()?>";
//get_cookie is a function that I defined to retrieve the cookie
var csrf_cookie = get_cookie("csrf_cookie_name");
$.post('index.php/sentinel/verify_user',data+"&"+csrf_name+"="+csrf_cookie,function(data){
if(data && data !== '')
{
data = data.replace(/(<p>)/g,'').replace(/(<\/p>)/g,'<br>');
$("#login-alert").prop('class','alert alert-danger').html(data);
}
else
{
//success
//redirect to the main page
}
});
});
function get_cookie( check_name ) {
var a_all_cookies = document.cookie.split( ';' );
var a_temp_cookie = '';
var cookie_name = '';
var cookie_value = '';
var b_cookie_found = false; // set boolean t/f default f
for ( i = 0; i < a_all_cookies.length; i++ )
{
// now we'll split apart each name=value pair
a_temp_cookie = a_all_cookies[i].split( '=' );
// and trim left/right whitespace while we're at it
cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
// if the extracted name matches passed check_name
if ( cookie_name == check_name )
{
b_cookie_found = true;
// we need to handle case where cookie has no value but exists (no = sign, that is):
if ( a_temp_cookie.length > 1 )
{
cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
}
// note that in cases where cookie is initialized but no value, null is returned
return cookie_value;
break;
}
a_temp_cookie = null;
cookie_name = '';
}
if ( !b_cookie_found )
{
return null;
}
}
这是我的控制器:
public function verify_user(){
$this->form_validation->set_rules('username', 'Username', 'required|alpha');
$this->form_validation->set_rules('pwd', 'Password', 'required|callback_alpha_numeric_dots');
$this->form_validation->set_message('alpha_numeric_dots','Invalid Password.');
if ($this->form_validation->run() == FALSE)
{
echo validation_errors();
}
else
{
$this->form_validation->set_rules('pwd','Password','callback_login_check');
if ($this->form_validation->run() == FALSE)
{
echo validation_errors();
}
else
{
echo '';
}
}
}
public function login_check(){
$data = $this->security->xss_clean($this->input->post());
$rep_info= $this->sentinel_model->user_verify($data);
if($rep_info === FALSE)
{
$this->form_validation->set_message('login_check', 'Incorrect Username or Password');
return FALSE;
}
else
{
//set session data here
$newdata = array(
'id' =>$this->encryption->encrypt($rep_info['user_id']),
'name' => $rep_info['user_name'],
'email' => $rep_info['user_email'],
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
return TRUE;
}
}
public function alpha_numeric_dots($str)
{
return (bool) preg_match('/^[A-Z0-9.]+$/i', $str);
}
我还想在用户成功登录后将他们重定向到另一个视图而不更改 url。最好的方法是什么?
当使用 form_open()
函数及其快速修复时,CSRF
标记作为隐藏输入添加到表单中。
具有 CSRF
令牌值的 cookie 由 Security
class 创建,并在必要时为每个请求重新生成。
如果 $_POST
数据存在,cookie 将由输入 class 自动验证。如果 posted 令牌与 cookie 的值不匹配,CI
将显示错误并且无法处理 $_POST
数据。
所以基本上,这一切都是自动的 - 您所要做的就是在您的 $config['csrf_protection']
中启用它并为您的表单使用 form_open()
功能。
所以客户端你只需要 post
$.post('index.php/sentinel/verify_user',$("#login_form").serialize(),function(data){
});
在您的控制器中
$this->load->helper('form');
并在您查看文件
<?php echo form_open('sentinel/verify_user', 'id="login_form" class="col-12 col-md-8 mx-auto"'); ?>
<div class="alert" id="login-alert" role="alert"></div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon1">Username</span>
<input type="text" class="form-control" id="username" name="username" />
</div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon2">Password</span>
<input type="password" class="form-control" id="pwd" name="pwd" />
</div>
<div class="text-center">
<button type="button" id="login_btn" class="btn btn-primary">LOGIN</button>
</div>
</form>
或
在如下表单中创建隐藏输入
<input type="hidden" name="<?php echo $this->security->get_csrf_token_name(); ?>" value="<?php echo $this->security->get_csrf_hash();?>" />
或
不修改视图文件,(您 posted 的更正版本)
var data = $("#login_form").serialize();
$.post(
'index.php/sentinel/verify_user',
data+"&" + '<?php echo $this->security->get_csrf_token_name(); ?>' +"="+ '<?php echo $this->security->get_csrf_hash(); ?>',
function(data){
});
征求意见
Actually I just noticed that I'm getting 403(Fordidden) error instead
of 500 once i click the login button the 2nd time
来自 the docs:
Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security, but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter
$config['csrf_regenerate'] = TRUE;
将其设置为 FALSE。
我正在使用 Codeigniter 3.1.3 并在配置文件中启用了 CSRF 保护。如果表单通过验证,我总是从 ajax $.post 得到 500(内部服务器错误)。如果验证失败,我不会收到该错误。有什么想法吗?
这是 codeigniter 配置文件中的 csrf 设置:
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
$config['csrf_regenerate'] = TRUE;
这是我在视图中的登录表单 login.php:
<form id="login_form" class="col-12 col-md-8 mx-auto" method="post">
<div class="alert" id="login-alert" role="alert"></div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon1">Username</span>
<input type="text" class="form-control" id="username" name="username" />
</div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon2">Password</span>
<input type="password" class="form-control" id="pwd" name="pwd" />
</div>
<div class="text-center">
<button type="button" id="login_btn" class="btn btn-primary">LOGIN</button>
</div>
</form>
我正在使用 AJAX $.post 提交表单
$("#login_btn").click(function(){
var data = $("#login_form").serialize();
var csrf_name = "<?=$this->security->get_csrf_token_name()?>";
//get_cookie is a function that I defined to retrieve the cookie
var csrf_cookie = get_cookie("csrf_cookie_name");
$.post('index.php/sentinel/verify_user',data+"&"+csrf_name+"="+csrf_cookie,function(data){
if(data && data !== '')
{
data = data.replace(/(<p>)/g,'').replace(/(<\/p>)/g,'<br>');
$("#login-alert").prop('class','alert alert-danger').html(data);
}
else
{
//success
//redirect to the main page
}
});
});
function get_cookie( check_name ) {
var a_all_cookies = document.cookie.split( ';' );
var a_temp_cookie = '';
var cookie_name = '';
var cookie_value = '';
var b_cookie_found = false; // set boolean t/f default f
for ( i = 0; i < a_all_cookies.length; i++ )
{
// now we'll split apart each name=value pair
a_temp_cookie = a_all_cookies[i].split( '=' );
// and trim left/right whitespace while we're at it
cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, '');
// if the extracted name matches passed check_name
if ( cookie_name == check_name )
{
b_cookie_found = true;
// we need to handle case where cookie has no value but exists (no = sign, that is):
if ( a_temp_cookie.length > 1 )
{
cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, '') );
}
// note that in cases where cookie is initialized but no value, null is returned
return cookie_value;
break;
}
a_temp_cookie = null;
cookie_name = '';
}
if ( !b_cookie_found )
{
return null;
}
}
这是我的控制器:
public function verify_user(){
$this->form_validation->set_rules('username', 'Username', 'required|alpha');
$this->form_validation->set_rules('pwd', 'Password', 'required|callback_alpha_numeric_dots');
$this->form_validation->set_message('alpha_numeric_dots','Invalid Password.');
if ($this->form_validation->run() == FALSE)
{
echo validation_errors();
}
else
{
$this->form_validation->set_rules('pwd','Password','callback_login_check');
if ($this->form_validation->run() == FALSE)
{
echo validation_errors();
}
else
{
echo '';
}
}
}
public function login_check(){
$data = $this->security->xss_clean($this->input->post());
$rep_info= $this->sentinel_model->user_verify($data);
if($rep_info === FALSE)
{
$this->form_validation->set_message('login_check', 'Incorrect Username or Password');
return FALSE;
}
else
{
//set session data here
$newdata = array(
'id' =>$this->encryption->encrypt($rep_info['user_id']),
'name' => $rep_info['user_name'],
'email' => $rep_info['user_email'],
'logged_in' => TRUE
);
$this->session->set_userdata($newdata);
return TRUE;
}
}
public function alpha_numeric_dots($str)
{
return (bool) preg_match('/^[A-Z0-9.]+$/i', $str);
}
我还想在用户成功登录后将他们重定向到另一个视图而不更改 url。最好的方法是什么?
当使用 form_open()
函数及其快速修复时,CSRF
标记作为隐藏输入添加到表单中。
具有 CSRF
令牌值的 cookie 由 Security
class 创建,并在必要时为每个请求重新生成。
如果 $_POST
数据存在,cookie 将由输入 class 自动验证。如果 posted 令牌与 cookie 的值不匹配,CI
将显示错误并且无法处理 $_POST
数据。
所以基本上,这一切都是自动的 - 您所要做的就是在您的 $config['csrf_protection']
中启用它并为您的表单使用 form_open()
功能。
所以客户端你只需要 post
$.post('index.php/sentinel/verify_user',$("#login_form").serialize(),function(data){
});
在您的控制器中
$this->load->helper('form');
并在您查看文件
<?php echo form_open('sentinel/verify_user', 'id="login_form" class="col-12 col-md-8 mx-auto"'); ?>
<div class="alert" id="login-alert" role="alert"></div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon1">Username</span>
<input type="text" class="form-control" id="username" name="username" />
</div>
<div class="form-group input-group">
<span class="input-group-addon" id="basic-addon2">Password</span>
<input type="password" class="form-control" id="pwd" name="pwd" />
</div>
<div class="text-center">
<button type="button" id="login_btn" class="btn btn-primary">LOGIN</button>
</div>
</form>
或
在如下表单中创建隐藏输入
<input type="hidden" name="<?php echo $this->security->get_csrf_token_name(); ?>" value="<?php echo $this->security->get_csrf_hash();?>" />
或
不修改视图文件,(您 posted 的更正版本)
var data = $("#login_form").serialize();
$.post(
'index.php/sentinel/verify_user',
data+"&" + '<?php echo $this->security->get_csrf_token_name(); ?>' +"="+ '<?php echo $this->security->get_csrf_hash(); ?>',
function(data){
});
征求意见
Actually I just noticed that I'm getting 403(Fordidden) error instead of 500 once i click the login button the 2nd time
来自 the docs:
Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security, but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter
$config['csrf_regenerate'] = TRUE;
将其设置为 FALSE。