CodeIgniter中$this->input->post('field', TRUE)的XSS清理仅作基础标签剥离,与防SQL注入无关;CI4已弃用全局XSS过滤,应禁用并改用esc()输出转义+输入验证双层防护。

用 $this->input->post() 时别开全局 XSS 过滤
CodeIgniter 的 $this->input->post('field', TRUE) 第二个参数开启的是 XSS 清理,但它只对字符串做 strip_tags() 和基础字符替换,不处理单引号、分号、反斜杠等 SQL 关键字符 —— 所以它跟防 SQL 注入完全无关。更关键的是:$config['global_xss_filtering'] = TRUE 在 CI4 中已被弃用,在 CI3 中也仅作用于 GET/POST/COOKIE 的原始值,且会破坏合法 HTML(比如富文本编辑器存的 <p>),反而掩盖真实问题。
- 真正需要 XSS 防护的地方是输出环节,不是输入环节
- 若业务必须接收 HTML(如文章内容),应改用白名单过滤库(如 HTMLPurifier),而不是依赖
xss_clean() - CI4 中推荐直接禁用全局过滤,靠
esc()+ 输入验证双层控制
表单验证必须显式声明规则,不能只靠“过滤”
很多开发者以为开了 XSS 过滤就安全了,结果在数据库写入前没做任何验证,导致空邮箱、超长用户名、非法手机号直接入库。CI 的表单验证不是可选项,而是数据进入业务逻辑前的强制闸门。
- 用
$validation->setRules()明确字段类型、长度、格式,例如'email' => 'required|valid_email|is_unique[users.email]' -
is_unique规则底层走的是 Query Builder,自动参数绑定,安全;但注意它只校验“值是否存在”,不替代数据库唯一索引 - 自定义规则里禁止拼接 SQL,比如
"SELECT COUNT(*) FROM ... WHERE name = '{$name}'"—— 必须用$builder->where('name', $name)或问号绑定
所有动态输出必须过 esc(),且按上下文选类型
用户提交的昵称、评论、标题,哪怕经过验证和过滤,只要没在输出时转义,就可能触发 XSS。CI4 的 esc() 不是万能胶布,它必须配合上下文使用,否则等于没转。
- HTML 内容用
esc($data, 'html')(默认行为) - 写进
<script>里的变量用esc($data, 'js'),否则引号逃逸或闭合标签会出事 - 作为 URL 参数拼接时用
esc($data, 'url'),避免?id=1&next=javascript:alert(1)这类跳转 - 绝对不要在 JS 字符串里直接插 PHP 变量:
var name = "= $name ?>";→ 应写成var name = = esc($name, 'js') ?>;
CSRF 令牌不是加个 helper 就完事
= csrf_field() ?> 只是生成隐藏域,真正起作用的是请求到达时框架是否校验它。如果漏配过滤器、或 AJAX 请求没传令牌头,整个防护形同虚设。
- CI4 要在
app/Config/Filters.php的$globals['before']里明确加入'csrf' - AJAX 请求需从 Cookie 读取
csrf_cookie_name值(默认是ci_csrf_token),并设请求头X-CSRF-TOKEN - CSRF 令牌默认 2 小时过期(
$csrfExpire),长周期后台操作要考虑刷新机制,否则中途失效会导致表单提交静默失败 - 不要把 CSRF 令牌写死在 JS 文件里,也不要在 API 接口中返回它给未认证用户
esc() 管输出上下文,CSRF 管请求来源。任何一个环节跳过或错配类型,防线就断了。


















