Yii默认不自动转义输出,必须在视图层显式调用Html::encode()处理所有可能含用户输入的变量,否则将触发XSS;该方法将、"、'、&转为HTML实体,是文本级最基础且不可跳过的防护手段。

Html::encode() 必须在视图层调用,不能提前在控制器里 encode
用户输入一旦进入 PHP 变量,就只是字符串;它是否危险,取决于最终怎么被插入 HTML。Yii 默认不做任何自动转义,Html::encode() 是你唯一能依赖的、轻量且可靠的文本级防护手段。
常见错误是:在控制器里对 $model->content 调用一次 Html::encode(),再传给视图,然后在视图中直接 = $content ?> —— 这等于把已编码过的字符串又塞进 HTML,结果就是显示
而不是渲染成段落。
- 编码动作必须发生在「即将插入 HTML 文本上下文」的前一刻,也就是视图文件里
- 哪怕变量来自数据库、缓存或 API 响应,只要内容可能含用户输入,就得在 echo 前加
Html::encode() - 不要用
htmlspecialchars()替代,它不兼容 Yii 的字符集配置(比如处理 GBK 多字节时可能截断)
富文本不能用 Html::encode(),得用 HtmlPurifier 白名单过滤
电商商品描述、后台编辑器提交的新闻正文、用户评论中的格式需求,意味着你不能简单把所有 都转成 <code>。<code>Html::encode() 会把整个富文本变成纯文本,而不用它又等于开门迎 XSS。
正确路径是启用 HtmlPurifier,并配置白名单:
- 先通过 Composer 安装:
composer require ezyang/htmlpurifier - 在应用配置中注册组件:
'htmlPurifier' => ['class' => 'yii\helpers\HtmlPurifier'] - 调用时指定规则,例如只允许
<p></p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2519" title="Yii Framework 2.0.51"><img src="https://img.php.cn/upload/manual/001/503/042/6a6b03d191dbf935.png" alt="Yii Framework 2.0.51" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/gongju/2519" title="Yii Framework 2.0.51" class="overflowclass">Yii Framework 2.0.51</a> <p class="overflowclass">Yii Framework 2.0.51 官方 Basic 应用模板,适合旧项目兼容、升级验证和开发测试。</p> </div> <a rel="nofollow" href="/xiazai/gongju/2519" title="Yii Framework 2.0.51" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>、<strong></strong>、<a></a>,且href必须以https://开头 - 别在控制器里硬写 purifier 配置——统一收口到服务类或行为(Behavior),避免不同页面策略打架
JavaScript 中嵌入用户数据,Json::encode() 比 Html::encode() 有效
下面这段代码看着安全,其实仍可被利用:
<button onclick="alert('<?php echo Html::encode($name); ?>')"></button>
因为 Html::encode() 只防 HTML 上下文,而 onclick 是 JS 执行环境。攻击者输入 test'); alert(1); // 就能闭合引号并执行任意 JS。
- 所有从 PHP 注入到 JS 字符串的地方(
<script></script>内联、data-属性、onclick等),都该用Json::encode() - 它会自动加双引号、转义反斜杠、处理 Unicode,并确保输出是合法 JSON 字面量
- 接着在 JS 里用
const name = = Json::encode($name) ?>;,而不是拼接字符串 - 绝对避免
innerHTML = '<div>' + userStr + '</div>'这类操作
三个最容易漏掉的 XSS 输出点:meta、JS 变量、属性值
XSS 不只藏在 <div>= $content ?></div> 里。这三个位置常被跳过防护:
-
<meta name="description" content="= Html::encode($desc) ?>">——content属性值也是 HTML 上下文,必须转义 -
<script>var title = "= Html::encode($title) ?>";</script>—— 这里仍是 HTML 解析阶段,得用Json::encode(),否则引号和反斜杠会破坏 JS 语法 -
<input value="= Html::encode($value) ?>">—— input 的value属性值属于属性上下文,Html::encode()正确,但若用了单引号包裹属性,则需额外注意
真正麻烦的是那些“看起来不像输出点”的地方:URL 参数拼接、CSS content 属性、SVG 的 onload……只要最终由浏览器解析为可执行内容,就必须按上下文选对编码方式。










