前端阅读 05月30日 22:56
React、Vue、Angular 防 XSS 靠什么?哪些场景会失效?
直接回答React、Vue、Angular 都会默认把模板里的普通文本做 HTML 转义,所以把用户昵称、搜索词、评论摘要渲染成文本时,一般不会直接变成脚本执行。真正的风险通常出现在开发者主动绕过框架保护:React 的 dangerouslySetInnerHTML、Vue 的 v-html、Angular 的 bypassSecurityTrustHtml,以及把不可信数据拼到 URL、CSS、事件处理器或第三方组件配置里。框架能减少常见错误,但不能替你判断一段 HTML 是否可信,也不能保证后端、富文本编辑器、Markdown 渲染器和广告脚本都安全。防 XSS 更稳的做法是分层处理:默认用文本渲染;确实要展示富文本时先用 DOMPurify 这类白名单清洗;URL 只允许 https:、mailto: 等业务需要的协议;再用 CSP 限制脚本来源,降低漏网 payload 的执行概率。不要把“用了 React/Vue/Angular”当成免疫证书,XSS 往往就藏在为了赶需求开的那个逃生口里。必要代码import DOMPurify from 'dompurify';function SafeRichText({ html }: { html: string }) { const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['p', 'a', 'strong', 'em', 'ul', 'ol', 'li', 'code'], ALLOWED_ATTR: ['href', 'title', 'target', 'rel'] }); return <div dangerouslySetInnerHTML={{ __html: clean }} />;}这段代码的重点不是“用了 sanitize 就万事大吉”,而是把允许的标签和属性收窄。富文本业务经常要开放链接、图片或代码块,每多放一个标签,测试用例就要覆盖它的危险属性和协议。尤其是链接,javascript:、data:、奇怪大小写和编码绕过都要检查。追问React、Vue、Angular 的自动转义具体防住了什么?自动转义主要防住“把字符串当成 HTML 解析”的问题,例如用户输入 <img onerror=alert(1)>,框架会把尖括号转成文本显示。它适用于文本节点和大多数属性绑定,但前提是你没有主动要求框架把内容当 HTML 插入。边界在于 URL、CSS、SVG、iframe 等上下文的规则不同,单纯 HTML 转义不一定够。实际项目里最容易踩坑的是把搜索词、昵称这些看似普通的字段临时塞进富文本容器,结果绕过了默认保护。为什么 dangerouslySetInnerHTML、v-html 不能直接用?这类 API 的名字已经说得很直白:它们会跳过模板转义,把字符串交给浏览器按 HTML 解析。如果字符串来自 CMS、评论、客服消息、Markdown 或外部接口,就等于让外部数据参与页面结构生成。取舍点在于富文本确实需要这些 API,否则无法保留段落、链接和强调样式。正确做法不是完全禁用,而是把调用点集中封装,统一清洗、统一审计,避免每个业务组件各写一套临时逻辑。Angular 的安全机制是不是比 React、Vue 更强?Angular 对不同上下文有更细的安全模型,会区分 HTML、Style、URL、Resource URL,并在模板绑定时做相应处理。它的优势是默认约束更明确,团队不容易随手拼接危险模板。边界也很清楚,一旦使用 bypassSecurityTrust...,就是开发者声明“我保证这段内容可信”。踩坑常见于为了解决视频嵌入、富文本预览或老页面迁移而滥用 bypass,最后把安全责任从框架手里拿了回来。只靠前端框架防护够不够?不够,因为 XSS 的入口不一定只在当前前端项目里。后端模板、管理后台、第三方 SDK、富文本编辑器、Markdown 渲染、埋点脚本都可能把不可信数据重新带回页面。组合防护要同时有输出编码、富文本清洗、协议白名单、Cookie 的 HttpOnly/SameSite/Secure、CSP 和依赖升级。这样即使某一层漏掉,攻击者也不容易直接拿到会话或执行任意脚本。团队里怎么把这件事落地?最有效的办法是减少“自由发挥”的入口,例如只提供 SafeHtml、SafeLink、RichTextRenderer 这些经过审计的组件。代码评审重点看是否出现 innerHTML、outerHTML、document.write、字符串形式的 setTimeout、不受控的 iframe src。自动化层面可以加 ESLint 规则和 Semgrep 规则,把危险 API 变成需要解释的例外。边界是安全规则不能阻断正常业务,所以组件要给出可用替代方案,否则大家会绕过规则。