CodeIgniter 4 全局 CSRF 过滤器必须显式注册到 Filters.php 的 $globals['before'] 中,仅配置 $csrfProtection 或定义类无效;需设 'before' => ['csrf'],并确保 Security.php 中 $csrfProtection 为 'cookie' 或 'session'。

CodeIgniter 4 的全局过滤器必须显式注册到 Filters.php,否则任何配置或中间件逻辑都不会生效——光改 $csrfProtection 或写个自定义类,请求照样绕过。
CI4 全局启用 CSRF 过滤器必须配 $globals
CSRF 不是“设了配置就自动拦截”,它依赖过滤器链的执行。不把它塞进 $globals['before'],所有 POST 请求都收不到验证。
- 打开
app/Config/Filters.php - 在
$globals数组里加上'before' => ['csrf'](注意不是['csrf' => ['before']]) - 确认
app/Config/Security.php中$csrfProtection是'cookie'或'session',否则过滤器初始化失败 -
$csrfRegenerate = true是默认值,意味着每次请求后 token 都会变——这对 AJAX 很危险,但禁用它会降低防护强度
CI3 的 $config['csrf_protection'] = TRUE 只是开关,不是完整方案
CI3 启用门槛低,但漏掉任一环节就会让保护形同虚设。
- 必须配合表单输出:用
form_open()自动注入,或手写<input type="hidden" name="<?= $this->security->get_csrf_token_name() ?>" value="<?= $this->security->get_csrf_hash() ?>"> - 控制器中读取 POST 数据时,必须用
$this->input->post(null, TRUE)——第二个参数TRUE才触发 CSRF 校验,否则只当普通数据读 -
$config['csrf_regenerate'] = FALSE可缓解多标签页失效问题,但别在高敏感操作(如转账)中长期关闭
自定义全局过滤器(如日志、权限检查)要小心执行时机
所有 before() 过滤器都在路由解析之后、控制器执行之前运行,但无法访问控制器方法名或参数,除非你手动解析 URI。
- 过滤器类需实现
FilterInterface,before()方法接收RequestInterface,可读取 header、query、body - 若需跳过某类请求(如静态资源),在
before()中用$request->getUri()->getPath()匹配路径前缀并直接return $response - 不要在
before()里调用$this->session->get()等依赖服务的代码,除非已确认 session 已启动(CI4 默认已启动,CI3 需确保$autoload['libraries']包含'session') - 抛出异常(如
new \CodeIgniter\Exceptions\PageNotFoundException())会中断流程并进入错误页,比redirect()更干净
过滤器和 XSS 清理别混用,尤其别在验证规则里写 |xss_clean
CI3.0+ 已移除 |xss_clean 验证规则,继续写会导致 $this->form_validation->run() 直接返回 FALSE,且无提示。
- XSS 过滤是输入层的事,应在获取数据后、验证前手动调用
$this->security->xss_clean(),仅对真正需要的字段(如富文本)使用 - CI4 中推荐用
esc()函数在输出时转义,而非在输入时过度清洗——后者可能破坏合法 HTML 或 JSON - 上传图片校验必须传
TRUE给xss_clean()第二个参数:$this->security->xss_clean($file, TRUE),否则只做字符串过滤,不检测嵌入脚本
最常被忽略的是:过滤器注册后,还要检查它是否真在请求生命周期中跑起来了——加一句 log_message('debug', 'csrf filter ran') 到 before() 里,比猜日志强得多。


















