个人博客第一次被攻击,评论区被植入恶意代码全记录

前言

今天访问自己的博客时突然发现,页面居然弹出了一个 alert(1) 对话框,再一查是多了一个不存在的异常请求地址:/x。

第一反应是网站被黑了。
排查下来,确实是一次评论区的恶意代码注入攻击。

这篇文章记录完整的发现过程和修复方案,包括封禁攻击者 IP、删除恶意评论、修复主题漏洞三步。

攻击是怎么发生的

这种攻击叫 XSS(跨站脚本攻击),原理不复杂:攻击者把恶意代码注入到网页中,其他访客打开页面时代码自动执行。

这次的攻击路径是这样的:

攻击者在 Twikoo 评论区提交了一条评论,把昵称设成了 <img src=x onerror=alert(1)>

安知鱼主题的最新评论侧边栏组件会调用 Twikoo 的 API 获取最近评论,然后把评论数据拼成 HTML 渲染到页面上。

问题出在拼接 HTML 的环节。
主题模板直接把用户昵称拼进了 innerHTML,没有做任何 HTML 转义,浏览器就把它当成了真正的 <img> 标签来渲染,加载失败后触发了弹窗。

因为 404 页面也带侧边栏最新评论,所以访问任何不存在的路径都会触发弹窗。

攻击者用 alert(1) 只是证明能打
真正危险的攻击可以窃取用户 Cookie、劫持登录态、注入钓鱼页面,后果严重得多。

第一步:全局封禁攻击者 IP

发现攻击后,第一件事是切断攻击来源。

从 Twikoo 后台和 Nginx 访问日志中定位到攻击者的 IP 地址,然后直接在云服务器安全组里封禁。

在阿里云 ECS 的安全组规则里添加一条入站拒绝规则,把攻击者 IP 的所有流量拦在外面,一劳永逸。

封禁 IP 是应急措施,能争取处置时间,但不是长久之计。
攻击者可以换 IP 再来,所以还需要从应用层面加固。

第二步:删除恶意评论,开启评论审核

评论系统的加固分两个动作。

先从 Twikoo 后台手动删除昵称为 <img src=x onerror=alert(1)> 的那条恶意评论,清除已经注入的攻击载荷。

然后在 Twikoo 管理后台开启评论审核功能。
开启后,新提交的评论不会直接显示,需要管理员审核通过后才能展示。

这样即使有人再提交恶意内容,也不会直接暴露给其他访客。

评论审核的代价是降低了互动即时性,但对于个人博客来说,这个权衡是值得的。
安全优先。

第三步:修复评论插件 Bug 并上线

前面两步是治标,这一步才是治本。

漏洞的根因在安知鱼主题的两个模板文件里,侧边栏最新评论组件和中控台最新评论组件都有同样的问题。

两个文件的 generateHtml 函数把 Twikoo 返回的用户数据(昵称、头像、评论内容、链接)直接拼进了 innerHTML,没有做任何 HTML 转义,所以攻击者的昵称被浏览器当成了真正的 HTML 标签来执行。

修复方法是对所有来自用户的数据做 HTML 实体编码,把 <>" 等特殊字符转义成浏览器不会解析的格式。
转义之后,<img src=x onerror=alert(1)> 这种恶意昵称只会被当成普通文字显示,不会被执行。

修复完成后构建验证通过,提交推送到线上。

攻击复盘

回顾这次事件,有几个教训值得记住。

这类攻击的入口往往是评论区、留言板这类用户可自由输入的地方。
任何把用户输入直接拼进 HTML 的操作都是潜在漏洞。

对所有来自用户的数据做 HTML 转义,是前端项目的基本安全底线。
浏览器自带的防护机制(CSP 等)只是辅助,最根本的还是开发者在代码层面做好输入过滤和输出转义。

如果你的博客也用安知鱼主题,建议检查一下评论区组件有没有同样的问题。

你的博客遇到过类似的安全问题吗?评论区聊聊你的经历和应对方式。