一次 Web 安全事件复盘:从 XSS 到服务器入侵

事件背景

去年年底,我们团队接手了一个电商类项目的安全整改工作。该平台在上线三个月后遭遇了一次完整的攻击链:攻击者从一个不起眼的评论框 XSS 漏洞入手,逐步渗透到后台管理系统,最终拿到了数据库服务器的 Shell 权限。本文对这起事件做一次完整复盘,并围绕 XSS 防御、SQL 注入防护和 Linux 服务器加固三个层面,梳理可落地的安全实践。

攻击链路还原

攻击者的路径并不复杂,但每一步都精准利用了开发过程中的疏漏:

  1. 入口:商品评论区未对用户输入做 HTML 转义,攻击者提交了一段携带恶意脚本的评论内容。
  2. 触发:管理员在后台审核评论时,脚本在管理员浏览器中执行,窃取了后台 Session Cookie。
  3. 横向移动:攻击者利用窃取的会话登录后台,发现订单查询接口存在 SQL 注入点。
  4. 提权:通过 SQL 注入写入 WebShell,进而利用服务器上配置不当的 MySQL 账户和弱口令 SSH,最终拿到服务器控制权。

这条链路说明一个道理:安全没有单点问题,任何一个环节的失守都可能被放大为系统性灾难。

一、XSS 的常见方式与前端防御

常见 XSS 类型

  • 反射型 XSS:恶意脚本作为请求参数传入,服务器直接将其拼接到响应页面中。常见于搜索框、错误提示页。
  • 存储型 XSS:恶意内容被持久化到数据库,所有访问该页面的用户都会中招。评论区、用户昵称、商品描述是高发区。
  • DOM 型 XSS:不经过服务器,前端 JavaScript 直接从 location.hashdocument.referrer 等来源取数据并插入 DOM。

前端防御要点

第一,输出编码是根本。 根据输出位置选择编码方式:HTML 内容区做实体编码,属性值加引号并编码,JavaScript 上下文做 Unicode 转义,URL 参数做百分号编码。不要试图用黑名单过滤 <script>,绕过方式太多了。

第二,善用框架的默认保护。 React、Vue 等现代框架默认对插值内容做转义。真正危险的是 dangerouslySetInnerHTMLv-html 这类逃生舱,使用前必须用 DOMPurify 等库做净化。

第三,配置 Content-Security-Policy。 一个合理的 CSP 能极大限制脚本执行来源,即使存在注入点,攻击者也无法加载外部恶意脚本:

Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'

第四,敏感 Cookie 加 HttpOnly。 这样即使发生 XSS,攻击者也无法通过 document.cookie 读取会话凭证,能有效阻断从 XSS 到账户劫持的关键一步——本次事件中,如果后台 Cookie 设置了 HttpOnly,攻击链在第二步就会断掉。

二、MySQL 防止 SQL 注入的几种写法

SQL 注入的根源是用户输入被当作 SQL 代码执行。以下是几种正确的防护写法,按推荐程度排序。

1. 参数化查询(首选)

无论使用 PDO、MySQLi 还是各类 ORM,预处理语句都是最可靠的方式:

$stmt = $pdo->prepare('SELECT * FROM orders WHERE user_id = ? AND status = ?');
$stmt->execute([$userId, $status]);

参数与 SQL 结构分离,数据库层面保证输入只被当作数据,而非代码。

2. 命名占位符

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

可读性更好,适合参数较多的场景。

3. 白名单校验

对于排序字段、表名等无法用参数占位的位置,必须用白名单:

$allowed = ['created_at', 'price', 'sales'];
$orderBy = in_array($_GET['sort'], $allowed, true) ? $_GET['sort'] : 'created_at';

4. 最小权限原则

应用连接数据库的账户只授予必要的权限,禁用 FILEDROP 等高危权限。本次事件中,Web 应用使用的是 root 账户,这才让攻击者能够写入文件。

需要避免的做法

  • 用字符串拼接构造 SQL;
  • 依赖 addslashes() 或手写转义函数;
  • 只在部分参数上做过滤,遗漏 ORDER BYLIMIT 等位置。

三、Linux 服务器安全加固清单

拿到服务器权限往往意味着事件进入最严重阶段。以下清单可作为日常加固的参考:

账户与认证

  • 禁用 root 远程登录,改用普通用户 + sudo;
  • 全面启用 SSH 密钥认证,关闭密码登录;
  • 修改默认 SSH 端口,配合 fail2ban 防暴力破解;
  • 定期清理无用账户和过期密钥。

网络与访问控制

  • 用防火墙(iptables/firewalld/安全组)只放行必要端口;
  • 数据库、Redis 等服务只监听内网地址,绝不暴露公网;
  • 部署 WAF,对常见注入、XSS 特征做拦截。

系统与补丁

  • 开启自动安全更新,及时修补内核和组件漏洞;
  • 卸载不必要的软件包和服务,减少攻击面;
  • 关闭危险的内核参数,如限制 dmesg 访问。

监控与审计

  • 部署日志集中收集,保留至少 180 天;
  • 对关键文件(如 Web 目录、/etc/passwd)做完整性监控;
  • 配置异常登录、异常进程告警。

数据与备份

  • 数据库定期备份并验证可恢复性;
  • 备份文件与生产环境隔离存储,避免被一并加密勒索。

复盘总结

这起事件给我们的最大教训是:安全防护必须覆盖完整链路,而不是只盯着某一个点。 如果评论框做了输出编码,如果后台 Cookie 加了 HttpOnly,如果数据库账户遵循最小权限,如果 SSH 禁用了密码登录——任何一层生效,攻击都无法走到最后。

对开发团队而言,把参数化查询、输出编码、CSP、最小权限这些基础实践固化为代码规范和上线检查项,远比事后补救更有价值。安全不是一次性的项目,而是需要持续维护的工程习惯。

未经允许不得转载:任鹏个人博客 » 一次 Web 安全事件复盘:从 XSS 到服务器入侵

赞 (0) 打赏

评论 0

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

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

支付宝扫一扫打赏

微信扫一扫打赏