模板插值必须按上下文区分处理:文本用textContent或he.escape(),script内用JSON.stringify(),URL参数用encodeURIComponent(),style/class避免拼接而用CSS变量,template克隆需重置name/id/for并处理file输入限制,前端仍须校验服务端HTML,DOM型XSS需用DOMPurify并禁用eval等危险API。

模板插值必须区分上下文,不能统一用innerHTML
直接把变量塞进innerHTML是高频XSS入口。哪怕模板引擎声明“已转义”,只要遇到{{ safe }}、v-html或dangerouslySetInnerHTML这类绕过机制,风险立刻回归。更隐蔽的是:同一段用户输入可能同时用于textContent、data-id、href和style——此时只做一次HTML实体编码(如he.escape())完全不够。
- 文本内容:用
textContent或he.escape() - 插入
<script></script>内:必须用JSON.stringify()包裹后再拼接 - 作为URL参数:走
encodeURIComponent(),不是encodeURI() - 写入
style或class:避免动态拼接,改用CSS自定义属性 + JS控制
克隆后必须重置name/id/for属性
多次克隆含的模板,会导致表单提交时仅保留最后一个同名字段的值——因为FormData只取同名input的末位。这不是浏览器bug,而是规范行为。
- 克隆后遍历所有表单控件,用
setAttribute('name', `email-${index}`)生成唯一name - 若需保持后端接收结构(如
user[emails][]),改用数组式命名,而非纯数字索引 -
id和for必须同步更新,否则会指向失效节点 -
克隆后值始终为空,这是浏览器安全限制,无法绕过
服务端返回HTML片段时,前端仍需二次校验上下文
即使后端声称“已过滤XSS”,也不能跳过前端校验。DOM型XSS不发请求、不碰数据库,纯靠前端读取location.search或document.referrer后直接塞进innerHTML触发。CSP对它基本无效。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 典型危险代码:
document.getElementById('box').innerHTML = new URLSearchParams(location.search).get('q') - 攻击者传
?q=即可窃取cookie - 正确做法:先过
DOMPurify.sanitize(),再用textContent输出;永远不用eval()、setTimeout(string) -
router.currentRoute.value.query不比location.search更安全,单页应用路由参数同样要对待
避免用document.write()和硬拼HTML字符串
document.write()在页面加载完成后调用会清空整个文档,而硬拼innerHTML字符串容易漏掉闭合标签、引号不匹配或属性未转义,导致DOM结构断裂或XSS漏洞。
- 优先用
insertAdjacentHTML()替代innerHTML,支持'beforeend'等精准位置且不破坏现有节点 - 确保目标元素已挂载——脚本放在
里而目标在底部,就会报Cannot set property 'innerHTML' of null- 复杂交互式表单建议用
+cloneNode(true),而非字符串模板拼接模板插值的真正难点不在语法本身,而在判断数据最终落点——是纯文本、属性值、URL、JS字符串,还是CSS规则。同一个变量,在不同位置需要不同的处理方式,漏掉任何一个上下文,都可能让防护形同虚设。
- 复杂交互式表单建议用
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










