XSS(跨站脚本攻击)长期位居 OWASP Top 10 之列,却也是最容易被“甩锅”的漏洞之一。前端认为后端应该过滤所有危险字符,后端认为前端应该负责转义和校验,最终导致防御出现真空地带。本文从协作视角出发,厘清前后端在 XSS 防御中的边界与职责,并指出常见误区。
一、XSS 的三种常见方式
理解防御的前提是理解攻击路径。XSS 通常分为三类:
- 存储型 XSS:恶意脚本被存入数据库(如评论、昵称、文章内容),所有访问该页面的用户都会中招。危害最大,常见于社区、论坛类应用。
- 反射型 XSS:恶意脚本作为请求参数(如搜索词、错误提示)被服务端直接拼接到 HTML 中返回,诱导用户点击链接后触发。
- DOM 型 XSS:不经过服务端,前端 JavaScript 直接从
location.hash、document.referrer等来源取数据并写入 DOM,导致脚本执行。
三者的共同点是:不可信数据最终进入了 HTML 解析上下文。因此防御的核心不是“过滤所有字符”,而是“在正确的边界做正确的处理”。
二、前端的防御职责与常见误区
前端最容易被误解为“应该拦截所有 XSS”。实际上,前端能做的和该做的有明确范围。
前端该做的
- 输出编码:在将数据插入 DOM 时,根据上下文进行转义。例如使用
textContent而非innerHTML,或使用成熟的转义库(如 DOMPurify)处理富文本。 - 避免危险 API:慎用
innerHTML、outerHTML、document.write、eval、setTimeout(string)等。React、Vue 等框架默认对插值进行转义,但dangerouslySetInnerHTML、v-html会绕过保护,需格外警惕。 - DOM 型 XSS 防御:对
location、URLSearchParams、postMessage等来源的数据,在使用前进行校验或编码。 - CSP 配合:通过 Content-Security-Policy 限制内联脚本和外部脚本来源,作为纵深防御的一层。
前端常见误区
- 误区一:前端过滤了,后端就不用管了。 攻击者可以绕过前端直接构造请求,前端校验只是用户体验优化,不是安全边界。
- 误区二:用正则替换
<script>就安全了。 XSS 载荷形式多样,如<img src=x onerror=alert(1)>、<svg onload=...>,黑名单过滤极易被绕过。 - 误区三:所有输出都用 HTML 转义。 如果数据要放入 JavaScript 变量、URL 参数或 CSS 中,HTML 转义不仅无效,还可能引入新问题。必须按上下文选择编码方式。
三、后端的防御职责与边界
后端是 XSS 防御的最后一道防线,但同样不是“万能过滤器”。
后端该做的
- 输入校验:对格式、长度、类型做白名单校验。例如邮箱必须符合邮箱格式,年龄必须是数字。校验的目的是保证数据符合业务预期,而非“过滤 XSS”。
- 输出编码:在将数据渲染到 HTML 模板时,使用模板引擎的自动转义功能(如 Jinja2、Thymeleaf、Go template)。如果必须输出富文本,使用服务端 HTML 净化库(如 OWASP Java HTML Sanitizer、bleach)进行白名单净化。
- 设置安全响应头:
Content-Security-Policy、X-Content-Type-Options: nosniff、X-XSS-Protection(现代浏览器已弱化)等。 - Cookie 安全:设置
HttpOnly防止脚本读取会话 Cookie,设置Secure和SameSite减少攻击面。
后端常见误区
- 误区一:在入库时统一转义。 这样会导致数据被多次转义,且无法适应不同输出上下文。正确做法是“存储原始数据,输出时按上下文编码”。
- 误区二:只依赖 WAF。 WAF 可以拦截已知攻击模式,但无法覆盖所有变种,也不能替代代码层面的防御。
- 误区三:认为 API 返回 JSON 就安全。 如果前端将 JSON 数据直接插入 HTML,仍然会触发 XSS。安全与否取决于最终渲染上下文,而非数据格式。
四、MySQL 防止 SQL 注入的几种写法
虽然本文主题是 XSS,但 SQL 注入与 XSS 常在同一协作场景中出现,且防御思路有相通之处:分离代码与数据。
-
参数化查询(首选) :
SELECT * FROM users WHERE username = ? AND password = ?;使用预编译语句,数据永远不被解释为 SQL 代码。
-
ORM 框架:如 MyBatis 的
#{}、Hibernate 的命名参数,底层仍是参数化查询。避免使用${}拼接。 -
存储过程:在数据库层封装查询逻辑,但需注意存储过程内部也可能存在拼接问题。
-
白名单校验:对于无法参数化的部分(如表名、排序字段),使用严格白名单映射,而非转义。
-
最小权限原则:数据库账号只授予必要权限,避免
DROP、FILE等高危操作。
五、Linux 服务器安全加固清单
XSS 防御不止于应用层,服务器加固是整体安全的基础。以下清单可作为协作团队的共同基线:
- 系统更新:定期更新内核与软件包,订阅安全公告。
- 最小化服务:关闭不必要的端口和服务,使用
ss -tulnp定期审查。 - SSH 加固:禁用 root 直接登录,使用密钥认证,修改默认端口,配置
fail2ban。 - 防火墙:使用 iptables/nftables 或云安全组,仅放行必要端口。
- 权限管理:遵循最小权限原则,Web 目录不可写,敏感文件权限设为 600。
- 日志与监控:启用 auditd,集中收集日志,设置异常告警。
- 备份与恢复:定期备份关键数据,并验证恢复流程。
- Web 服务加固:隐藏版本号,禁用目录列表,配置安全响应头。
六、协作的关键:明确边界,统一标准
前后端协作防御 XSS 的核心在于:
- 约定数据流:明确哪些数据不可信,在哪个环节做何种处理。
- 统一编码规范:前端按上下文编码,后端按输出场景转义,避免重复或遗漏。
- 共享安全库:团队维护统一的净化、转义工具,减少人为错误。
- 安全测试左移:在 CI 中集成 SAST/DAST 工具,尽早发现 XSS 和注入问题。
- 定期演练:通过红蓝对抗验证防御有效性,而非仅依赖代码审查。
XSS 防御不是某一端的责任,而是贯穿数据全生命周期的协作工程。只有边界清晰、职责明确、标准统一,才能真正堵住漏洞。
未经允许不得转载:任鹏个人博客 » 前后端协作防御 XSS:边界、职责与常见误区


朋友圈点赞图在线生成源码