Yii框架无全局自动过滤,必须分层防护:输入用filter验证器清洗(需配合校验器)、输出必用Html::encode()或HtmlPurifier配置白名单,禁用直接取参和safe属性滥用。

Yii框架里没有“全局自动过滤恶意代码”这回事——所有清洗必须明确落在模型规则、输出编码或专用净化组件上,否则 XSS 和注入风险照旧。
model rules() 里的 filter 验证器怎么写才有效
filter 验证器只做数据清洗,不校验合法性,也不能替代验证器。它必须和 string、integer 等验证器配合使用,否则清洗完的数据可能仍非法。
-
['content', 'filter', 'filter' => 'trim']只去首尾空格,content字段若含<script>依然原样保留 -
['id', 'filter', 'filter' => 'intval']会把'123abc'变成123,但不会拒绝该输入;真要拦截非法值,得加['id', 'integer'] - 多个 filter 可叠加,顺序重要:先
trim再strtolower比反过来更合理,避免空格影响大小写转换 - 不能写成
['name', 'trim']—— 这是调用名为trim的验证器(不存在),会报错;必须用['name', 'filter', 'filter' => 'trim']
Html::encode() 是输出环节不可跳过的一步
哪怕模型里做了 trim 和 string 校验,只要没在视图中调用 Html::encode(),XSS 就可能触发。这是防御链上最常被绕过的环节。
-
<?php echo $model->content; ?>—— 危险,直接输出原始内容 -
<?php echo Html::encode($model->content); ?>—— 安全,<变成,<code>"变成" -
Html::encode()默认启用ENT_QUOTES | ENT_SUBSTITUTE,能处理 UTF-8 中的非法字节序列,比裸用htmlspecialchars()更稳妥 - 不要在 JavaScript 中拼接用户数据:
var name = "= Html::encode($model->name) ?>";是 OK 的,但document.getElementById('x').innerHTML = = json_encode($model->content) ?>;仍需额外转义
需要保留 HTML 标签时,必须显式用 HtmlPurifier
HtmlPurifier 不是开箱即用的“安全开关”,它默认禁用所有标签;不配置白名单,结果就是清空全部 HTML —— 包括 <b>、<p> 这类合法标签。
-
<?php echo HtmlPurifier::process($model->content); ?>会按默认规则过滤,但默认只放行极少数标签(如<a>、<br>),且禁用所有属性 - 如需支持
<img src="...">,必须自定义配置:HtmlPurifier::process($content, ['HTML.Allowed' => 'p,b,i,a[href],img[src|alt]']) - 别把
HtmlPurifier当成输入过滤手段——它性能开销大,应在存储前或输出前调用一次,而不是在rules()里反复执行 - 注意命名空间:
use yii\helpers\HtmlPurifier;,漏掉这句会导致类找不到
Controller 里直接用 request->get() 或 filter_input() 是高危操作
绕过模型层直接取参,等于放弃 Yii 的整个验证与过滤体系。即便你手动 trim() 或 intval(),也挡不住后续渲染时的 XSS,更无法触发 safe 白名单控制。
-
$id = Yii::$app->request->get('id');或$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT);—— 这些值未进模型,不会触发任何filter或validate - 正确做法是建一个
SearchForm模型,把参数声明为属性,走load()+validate()流程 -
safe属性只是允许字段被批量赋值,它本身不做任何清洗或校验,标了safe反而更容易引入未过滤数据 - 错误示范:
['content', 'safe']+ 直接echo $model->content→ XSS 立刻触发
真正容易被忽略的点是:过滤和编码必须分层落实——输入清洗靠 filter,类型校验靠 integer/email 等验证器,输出安全靠 Html::encode() 或 HtmlPurifier。少任何一环,防线就断了。


















