在前后端分离架构大行其道的今天,JSON 接口几乎成了 Web 应用数据交互的唯一通道。很多开发者认为“JSON 不渲染 HTML,天然免疫 XSS”,这种错觉恰恰是风险的温床。本文将梳理 JSON 接口中 XSS 的常见触发方式,并从前端防御、SQL 注入防护以及 Linux 服务器安全加固三个层面,给出一份可落地的安全清单。
一、JSON 接口为什么会有 XSS?
XSS(跨站脚本攻击)的本质是恶意脚本在受害者浏览器中执行。JSON 本身只是数据格式,它不会执行任何东西。问题出在“数据被消费的那一刻”。
常见触发链路有:
-
前端直接将 JSON 字段插入 innerHTML
后端返回{"nickname": "<img src=1 onerror=alert(1)>"},前端用element.innerHTML = data.nickname渲染,脚本立即执行。 -
JSONP 接口的回调函数名未校验
如果接口是callback=alert(1)//,而服务端直接拼接返回alert(1)//({...}),就会造成反射型 XSS。 -
Content-Type 配置错误
接口返回 JSON 数据,但 Content-Type 写成text/html。浏览器会按 HTML 解析,攻击者构造的{"a":"<script>..."}可能被直接执行。 -
前端路由或模板引擎误用
某些模板引擎的“原始 HTML 输出”语法被用在 JSON 字段上,同样会引入 XSS。 -
富文本内容未过滤
评论、昵称、签名等字段允许 HTML,后端只做了 JSON 编码,未做 HTML 净化,前端又原样渲染。
二、XSS 的常见方式与前端如何防御
常见 XSS 类型
- 反射型:恶意脚本来自当前请求,如搜索关键词回显。
- 存储型:恶意脚本存入数据库,所有访问该页面的用户都会中招。
- DOM 型:不经过服务端,前端 JS 从 URL、localStorage 等取数据并写入危险 sink。
前端防御的核心原则
原则一:永远不要信任任何数据,包括来自自己后端的数据。
原则二:根据输出上下文选择正确的编码方式。
具体做法:
-
优先使用 textContent,而不是 innerHTML
el.textContent = data.nickname会把内容当作纯文本,不会解析标签。 -
必须渲染 HTML 时,使用 DOMPurify 等库净化
import DOMPurify from 'dompurify'; el.innerHTML = DOMPurify.sanitize(data.content); -
避免使用 eval、new Function、setTimeout(字符串)
这些是 DOM 型 XSS 的高危 sink。 -
对 URL 参数、hash 做严格校验
不要直接把location.hash写入页面。 -
设置 CSP(内容安全策略)
例如Content-Security-Policy: default-src 'self'; script-src 'self',可以大幅降低 XSS 成功概率。 -
Cookie 加 HttpOnly
即使 XSS 发生,攻击者也无法直接读取会话 Cookie。 -
JSON 接口返回正确的 Content-Type
application/json; charset=utf-8,并加上X-Content-Type-Options: nosniff。
三、MySQL 防止 SQL 注入的几种写法
虽然本文主题是 XSS,但 JSON 接口往往伴随数据库查询,SQL 注入与 XSS 常在同一攻击链中出现。以下写法按推荐程度排序:
-
预处理语句(Prepared Statement)——首选
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?'); $stmt->execute([$email]);参数与 SQL 结构分离,数据库不会把参数当作 SQL 解析。
-
参数化查询 + 类型绑定
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))注意:不要用
%字符串拼接,而是用驱动提供的参数占位符。 -
ORM 框架的标准查询方法
如 Laravel Eloquent、Django ORM、MyBatis 的#{},底层通常使用预处理。 -
输入白名单校验
对于排序字段、表名等无法参数化的位置,使用白名单映射:$allowed = ['name', 'created_at']; $order = in_array($_GET['order'], $allowed) ? $_GET['order'] : 'id'; -
最小权限原则
数据库账号只授予必要的 SELECT、INSERT、UPDATE、DELETE,禁用 FILE、DROP 等。
绝对避免:直接拼接 SQL 字符串、使用 mysql_query 旧扩展、把用户输入当作表名或字段名。
四、Linux 服务器安全加固清单
JSON 接口跑在服务器上,服务器被攻破,一切防御都归零。以下清单建议逐项核对:
账户与权限
- 禁用 root 远程 SSH 登录,使用普通用户 + sudo。
- 使用 SSH 密钥认证,关闭密码登录。
- 删除或锁定不必要的系统账户。
- 遵循最小权限原则,Web 目录不可写可执行。
网络与防火墙
- 只开放必要端口(如 80、443、SSH 自定义端口)。
- 使用 iptables/nftables 或云安全组限制来源 IP。
- 配置 fail2ban 防止暴力破解。
服务与软件
- 及时更新系统与软件补丁。
- 关闭不需要的服务(如 FTP、Telnet)。
- Web 服务器隐藏版本号,禁用目录浏览。
- PHP 禁用
exec、shell_exec、eval等危险函数(如无必要)。
日志与监控
- 开启并集中管理访问日志、错误日志。
- 配置日志轮转,防止磁盘写满。
- 使用 auditd 或 OSSEC 监控关键文件变更。
数据与备份
- 数据库不对外网开放,只允许内网访问。
- 定期备份,并验证恢复流程。
- 敏感数据加密存储,密钥与代码分离。
HTTPS 与安全头
- 全站 HTTPS,使用 HSTS。
- 配置
X-Frame-Options、X-XSS-Protection、Referrer-Policy等安全响应头。
五、总结
JSON 接口本身不是 XSS 的避风港。真正的防御需要贯穿数据流:后端正确设置 Content-Type、对富文本做净化、使用预处理语句防 SQL 注入;前端坚持“输出编码”原则,优先 textContent,必要时用 DOMPurify;服务器层面做好加固与最小权限。只有把每一层都当作可能被突破的防线,才能让 XSS 和注入攻击无处落脚。
安全不是一次性的配置,而是持续的习惯。从今天起,检查你的 JSON 接口返回头,审查前端每一处 innerHTML,加固你的服务器——这三件事,足以挡住大多数自动化攻击。
未经允许不得转载:任鹏个人博客 » JSON 接口中的 XSS 风险与防御:从常见攻击到前端、后端与服务器加固


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