CSRF保护需显式启用过滤器,CI4须在Filters.php中配置'csrf',CI3需设$config['csrf_protection']=TRUE;AJAX需动态更新token,手动生成表单勿漏隐藏域;CSRF仅防请求冒用,不防SQL注入或XSS。

CSRF保护默认不生效,光改配置没用
CodeIgniter 4 的 $csrfProtection 在 app/Config/Security.php 里设成 'cookie' 或 'session',只是“准备好”了,不是“已启用”。真正拦截请求的是过滤器机制——不把它加进 app/Config/Filters.php,所有 POST 请求照样畅通无阻。
- 必须在
$globals或对应方法的$methods中显式加入'csrf',例如:$globals = ['before' => ['csrf']] - 只在控制器里调用
$this->security->getCSRFTokenName(),但没配过滤器?那只是白生成一个 token,验证逻辑压根不会跑 - CI3 更简单粗暴:
$config['csrf_protection'] = TRUE写进application/config/config.php就算启用,但同样要配合表单输出({csrf_token})和输入校验($this->input->post(null, TRUE))才真正起效
AJAX 提交必崩的真相:token 过期太快
CI4 默认开启 $regenerate = true,每次请求都刷新 CSRF token。前端如果只在页面加载时读一次 csrf_token() 和 csrf_hash(),第二次 AJAX 就会 403——因为服务端的 token 已变,而你发的还是旧值。
- 别用
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': 'xxx' } })硬编码初始值,那是快照,一用就废 - 正确做法:监听每次响应头或 JSON 返回里的新 token,全局更新 JS 变量,比如:
window.csrfToken = data.csrf_token - CI3 没这么激进,默认不自动刷新;若想多标签兼容,可设
$config['csrf_regenerate'] = FALSE,但注意这会略微降低防护强度
手动生成表单或 JS 提交时漏掉隐藏域
用 DataTable 行点击、Uppy 文件上传、或纯 JS 动态创建 <form> 时,最容易忘塞 CSRF 隐藏字段——结果一提交就是 500 或 403,日志里还看不到明显报错。
- CI4 推荐在模板中用
<input type="hidden" name="= csrf_token() ?>" value="= csrf_hash() ?>"> - CI3 对应是
<input type="hidden" name="=$this->security->get_csrf_token_name()?>" value="=$this->security->get_csrf_hash()?>"> - 如果走 API 路线(如 Uppy 上传),建议后端在 OPTIONS 预检响应里带
Access-Control-Allow-Headers: X-CSRF-TOKEN,前端再用 header 方式传,避免混在 body 里被过滤器忽略
CSRF 不是银弹,别指望它防 SQL 注入或 XSS
开了 CSRF 保护 ≠ 网站安全了。像 id=123 直接拼进 SQL 删除整张表,跟 CSRF 完全无关;用户输入没过滤、模板里没用 esc() 输出,照样被 XSS 打穿。
- CSRF 只管“是不是用户本意发起的请求”,不管“请求内容是否合法”
- 真正防删库得靠查询构建器、参数化绑定、权限中间件、以及
$this->request->getPost(null, FILTER_SANITIZE_STRING)这类输入清洗 - 前后端分离场景下,跨域 + CSRF + Token 刷新三者叠加,最容易卡在“前端拿不到新 token”或“OPTIONS 预检没放行 header”,这时候看浏览器 Network 的 Request Headers 和 Response Headers 最直接










