模板标签输出了脚本开标签,内容怎么会被当成代码执行
站点内容被当成代码执行,只需要一步:模板引擎在渲染时收到的文本里含有一段开标签,而它把这个位置当作代码区开始解释。PbootCMS 的更新记录里就修过这样一条——站点标签输出脚本开标签的风险,同时增强了标签页参数过滤。修复的两个动作正好对应两层收口:输出位要过滤,进入标签的参数也要校验。凡是允许后台编辑的内容会流进模板或脚本引擎的系统,都面临同一条边界。
数据变成代码的那一步
模板文件里本来就有代码:标签语法、条件、循环都是给引擎看的指令。危险发生在「数据出口」被当成「代码入口」的时刻——引擎把用户可控的文本直接拼进待解释的源码,这段文本一旦带有引擎认识的起始标记,后面的内容就进入了指令流。从这一刻起,它不再是被显示的数据,而是被执行逻辑的一部分;同一条字符串在纯文本出口只是文字,在解释器入口就是行为。所以「内容怎么会执行」的答案是:它被放进了会解释它的位置。
标签位为什么要过滤
站点标签的输出位置很特殊:它常出现在模板拼装的最外层,有的实现还会把标签参数直接编译进模板源码。三个入口源源不断供给内容:后台编辑者录入、表单与评论提交、外部采集来的文章。任一路的内容带上了起始标记,且出口没过滤,问题就会在渲染时引爆。所以修复方案里「增强标签页参数过滤」与「输出位不再产生开标签」两件事必须同时做:参数面收窄可控输入的形态,输出面保证即使漏进来也不会被解释。
转义要按输出上下文分
同一段文本的去向不同,危险字符就不同,转义无法用一套通用清洗代替:
| 输出上下文 | 危险字符形态 | 正确做法 |
|---|---|---|
| HTML 正文 | 标签起始符与实体 | 按 HTML 实体转义 |
| 属性值 | 引号分隔符与尖括号 | 属性上下文专用转义并加引号 |
| 脚本字符串 | 引号、反斜杠与结束标记 | 按脚本语法转义或改走数据接口 |
| URL 参数 | 保留字符与编码注入 | 百分号编码并校验协议头 |
原则是消费者的解释语法决定转义方式;「先全局删一遍特殊字符再到处复用」的做法会把合法内容删坏,还漏掉上下文化攻击。
越靠前的过滤越省事
分层收口时优先级从前往后:录入与导入阶段做敏感词过滤与关键词替换,把明显畸形挡在入库前,AnQiCMS 的内容安全设置管的就是这一段;渲染阶段按上下文转义,这是防御跨站脚本的正解;接口与认证层收住注入类攻击面,AnQiCMS 内置防 SQL 注入与 XSS 攻击的防护属于这一层。越靠前,越能把问题留在数据形态、不让它靠近解释器;越靠后,越要依赖每一处出口的自觉。AnQiCMS 的可视化模板编辑允许直接修改模板代码,改模板的人自己也要守住这条边界:录入内容进模板时保持「它是数据」的定位。
常见问题
后台只有我能登录,还需要担心模板注入吗? 需要。可控内容不只来自登录者:采集来的文章、用户上传的文件名、评论都可能是源头,权限模型挡不住「数据里带的标记」。
把尖括号全局删掉不是更省心? 会误伤合法文本,也挡不住非 HTML 解释位置的注入。按输出上下文转义才不会两头不讨好。
模板引擎自带的自动转义够用吗? 默认场景够用,但自动转义通常只按 HTML 正文处理。属性、脚本、URL 位置要显式核对,混排模板里的「非 HTML 上下文」正是绕过点。