Codeigniter 4 在 AJAX 模式中重用 CSRF 令牌
Posted
技术标签:
【中文标题】Codeigniter 4 在 AJAX 模式中重用 CSRF 令牌【英文标题】:Codeigniter 4 reuse of CSRF token in AJAX modal 【发布时间】:2021-05-27 23:47:11 【问题描述】:场景:
我正在开发 CMS 系统,我想为对象(页面、帖子、媒体等)添加一些类别。在我看来,为了保存一个新类别,我使用放置在 Bootstrap 模式中的 html 表单,该表单通过 AJAX 发送到我的控制器。整个站点都启用了 CSRF 保护。
第一次发送数据时,我通过表单传递 CSRF 令牌名称和哈希。一旦在控制器中由 php 代码处理,我想在响应中传递 CSRF 值,以便能够在模式中“重用”表单(例如显示错误消息或/和创建另一个类别)。
然而,我无法访问 get_csrf_token_name()
和 get_csrf_hash()
方法将值传回视图。
在我看来 admin/category/create.php:
...
<!-- CREATE CATEGORY MODAL MODAL -->
<div class="modal" id="createCategory" tabindex="-1">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Nová kategorie</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Zavřít"></button>
</div>
<div class="modal-body">
<form action="" method="post" id="createCategoryForm">
<input type="hidden" value="<?= csrf_hash(); ?>" name="<?= csrf_token(); ?>" id="csrf">
<div class="form-group mb-3">
<label for="title" class="form-label">Název kategorie</label>
<input type="text" class="form-control" name="title" id="title" value="">
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" id="createCategoryConfirm">Vytvořit novou kategorii</button>
</form>
</div>
</div>
</div>
</div>
...
<script>
$('#head').on('click', '.create', function()
$('#createCategory').modal('show');
$('#createCategoryForm').attr('action', '<?= base_url(); ?>/admin/category/create');
$('#createCategoryConfirm').click(function(e)
e.preventDefault();
var url = $('#createCategoryForm').attr('action');
var csrfElement = $('#csrf');
var csrfName = csrfElement.attr('name');
var csrfHash = csrfElement.attr('value');
var categoryTitle = $('input[name=title]').val();
var data =
[csrfName]: csrfHash,
'title': categoryTitle
;
console.log(data);
$.ajax(
type: 'ajax',
method: 'POST',
url: url,
data: data,
dataType: 'json',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
headers: 'X-Requested-With': 'XMLHttpRequest',
success: function(result)
console.log(result);
,
error: function(result)
console.log(result);
,
);
);
);
</script>
在我的控制器 Category.php 中:
<?php
namespace App\Controllers\Admin;
use App\Controllers\BaseController;
use App\Models\CategoryModel;
use CodeIgniter\I18n\Time;
class Category extends BaseController
protected $model;
protected $validator;
protected $security;
public function __construct()
$this->model = new CategoryModel();
$this->validation = \Config\Services::validation();
$this->security = \Config\Services::security();
helper(['form', 'date', 'url']);
...
public function create()
$response = [];
// This part of code returns error
//
// $response['csrf'] = array(
// 'name' => $this->security->get_csrf_token_name(),
// 'hash' => $this->security->get_csrf_hash()
// );
$response['security'] = $this->security;
if ($this->request->isAJAX())
$newCategory = [
'title' => $this->request->getVar('title'),
'slug' => url_title($this->request->getVar('title')),
'author' => session()->get('id'),
'created_at' => Time::now('Europe/Prague')->toDateTimeString(),
'updated_at' => Time::now('Europe/Prague')->toDateTimeString(),
'parent' => '0'
];
$this->validation->run($newCategory, 'categoryRules');
if (!empty($this->validation->getErrors()))
$this->model->save($newCategory);
$response['errors'] = $this->validation->getErrors();
echo json_encode($response);
else
$this->model->save($newCategory);
$response['success'] = 'New category was created';
echo json_encode($response);
...
在浏览器控制台中,AJAX 响应为 POST http://localhost/admin/category/create 500 (Internal Server Error)
并具有完整响应:
code: 500
file: "D:\Web\XAMPP\htdocs\lenka\app\Controllers\Admin\Category.php"
line: 38
message: "Call to undefined method CodeIgniter\Security\Security::get_csrf_token_name()"
title: "Error"
有人可以在这里看到问题吗?关于如何在 CI4 中重用 CSRF 令牌有什么好的解决方案吗?我尝试将 CSRF regenerate 的配置值设置为 true 和 false,没有效果。
【问题讨论】:
在您的 ajax 成功中,您需要使用您在控制器中创建的新 csrf 值更新隐藏的输入#csrf 好吧,这就是重点 - 我无法在控制器中生成它们:$this->security->get_csrf_token_name()
和 $this->security->get_csrf_hash()
以 Call to undefined method CodeIgniter\Security\Security::get_csrf_token_name()
结尾
该方法在 CI3.x 中使用,在 CI4.x 中您可以使用 <input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />
参见 docs
【参考方案1】:
在 .ENV 中更新这一行代码 或 应用程序/配置/安全
CSRF 重新生成 = false
【讨论】:
以上是关于Codeigniter 4 在 AJAX 模式中重用 CSRF 令牌的主要内容,如果未能解决你的问题,请参考以下文章
在 CodeIgniter 3 中重定向后 Flashdata 未清除