JSON 接口中的 XSS 风险与防御:从常见攻击到前端、后端与服务器加固

在前后端分离架构大行其道的今天,JSON 接口几乎成了 Web 应用数据交互的唯一通道。很多开发者认为“JSON 不渲染 HTML,天然免疫 XSS”,这种错觉恰恰是风险的温床。本文将梳理 JSON 接口中 XSS 的常见触发方式,并从前端防御、SQL 注入防护以及 Linux 服务器安全加固三个层面,给出一份可落地的安全清单。

一、JSON 接口为什么会有 XSS?

XSS(跨站脚本攻击)的本质是恶意脚本在受害者浏览器中执行。JSON 本身只是数据格式,它不会执行任何东西。问题出在“数据被消费的那一刻”。

常见触发链路有:

  1. 前端直接将 JSON 字段插入 innerHTML
    后端返回 {"nickname": "<img src=1 onerror=alert(1)>"},前端用 element.innerHTML = data.nickname 渲染,脚本立即执行。

  2. JSONP 接口的回调函数名未校验
    如果接口是 callback=alert(1)//,而服务端直接拼接返回 alert(1)//({...}),就会造成反射型 XSS。

  3. Content-Type 配置错误
    接口返回 JSON 数据,但 Content-Type 写成 text/html。浏览器会按 HTML 解析,攻击者构造的 {"a":"<script>..."} 可能被直接执行。

  4. 前端路由或模板引擎误用
    某些模板引擎的“原始 HTML 输出”语法被用在 JSON 字段上,同样会引入 XSS。

  5. 富文本内容未过滤
    评论、昵称、签名等字段允许 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 常在同一攻击链中出现。以下写法按推荐程度排序:

  1. 预处理语句(Prepared Statement)——首选

    $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
    $stmt->execute([$email]);
    

    参数与 SQL 结构分离,数据库不会把参数当作 SQL 解析。

  2. 参数化查询 + 类型绑定

    cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
    

    注意:不要用 % 字符串拼接,而是用驱动提供的参数占位符。

  3. ORM 框架的标准查询方法
    如 Laravel Eloquent、Django ORM、MyBatis 的 #{},底层通常使用预处理。

  4. 输入白名单校验
    对于排序字段、表名等无法参数化的位置,使用白名单映射:

    $allowed = ['name', 'created_at'];
    $order = in_array($_GET['order'], $allowed) ? $_GET['order'] : 'id';
    
  5. 最小权限原则
    数据库账号只授予必要的 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 禁用 execshell_execeval 等危险函数(如无必要)。

日志与监控

  • 开启并集中管理访问日志、错误日志。
  • 配置日志轮转,防止磁盘写满。
  • 使用 auditd 或 OSSEC 监控关键文件变更。

数据与备份

  • 数据库不对外网开放,只允许内网访问。
  • 定期备份,并验证恢复流程。
  • 敏感数据加密存储,密钥与代码分离。

HTTPS 与安全头

  • 全站 HTTPS,使用 HSTS。
  • 配置 X-Frame-OptionsX-XSS-ProtectionReferrer-Policy 等安全响应头。

五、总结

JSON 接口本身不是 XSS 的避风港。真正的防御需要贯穿数据流:后端正确设置 Content-Type、对富文本做净化、使用预处理语句防 SQL 注入;前端坚持“输出编码”原则,优先 textContent,必要时用 DOMPurify;服务器层面做好加固与最小权限。只有把每一层都当作可能被突破的防线,才能让 XSS 和注入攻击无处落脚。

安全不是一次性的配置,而是持续的习惯。从今天起,检查你的 JSON 接口返回头,审查前端每一处 innerHTML,加固你的服务器——这三件事,足以挡住大多数自动化攻击。

未经允许不得转载:任鹏个人博客 » JSON 接口中的 XSS 风险与防御:从常见攻击到前端、后端与服务器加固

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏