我一直有个迷之自信的想法:我的站又小又没流量,谁没事会来攻击我?
这个想法,在去年 9 月的一个晚上,被我数据库里突然多出来的几万条垃圾数据,一巴掌扇醒了。
那天我登录 phpMyAdmin,看到某个表里塞满了乱码和莫名其妙的链接。这些数据不是我的文章,不是评论,就是纯垃圾。当时我第一反应是”谁这么闲?”,第二反应是”他们是怎么进来的?”
查了一圈,最大的嫌疑指向了 SQL 注入。那一刻我才明白——攻击者根本不挑食,他们不挑你,他们挑的是漏洞。你的站再小,只要有洞,就会有人来。
这篇文章,我把 SQL 注入这件事从”以为很遥远”到”亲身经历”再到”怎么防”完整讲一遍。不堆术语,就讲一个普通站长能听懂、能做到的版本。
先把这个”最危险也最被低估”的攻击讲清楚
SQL 注入,说白了就是:攻击者把你网站的表单、URL 参数当成”入口”,塞进去一些恶意的命令,让你网站的数据库去执行这些命令。 执行的结果可能是——偷数据、改数据、删数据,甚至直接把你的库清了。
举个例子(这个例子是我后来为了搞懂,专门做的演示,不是生产环境):
假设你的网站登录框,后端代码是这么写的:
SELECT * FROM users WHERE username = '输入的用户名' AND password = '输入的密码'
正常的用户,输入用户名 admin、密码 123456,拼出来就是查询”用户名是 admin 且密码是 123456 的用户”。没问题。
但攻击者不这么干。他在用户名那个框里,填的是:
admin' OR '1'='1
这下拼出来的语句变成了:
SELECT * FROM users WHERE username = 'admin' OR '1'='1' AND password = '...'
'1'='1' 永远成立。于是这条语句变成了”查询用户名是 admin 的用户”——密码那一关直接被绕过了。攻击者不用知道你密码,就能登录你的后台。
我第一次看到这个例子的时候,后背发凉。原来我那个”输入框多安全”的认知,跟纸糊的一样。
“小站没人攻击”错在哪?
我复盘的时候,脑子里反复冒出一个疑问:我的站日 IP 才几十个,为什么会被盯上?
后来我搞清楚了三个事实,每一个都挺扎心。
事实一:攻击不是你想象的那种”人盯着你打”。 现在绝大多数攻击都是机器人全自动扫描。有的是用工具,比如 sqlmap 这种,对着全网扫。它扫的是一批 IP 段、一批域名,哪句话”响应可疑”就在哪试试。你的站小不小,它真不知道,也不在乎。
事实二:攻击者针对的是”漏洞类型”,不是”你这个人”。 只要你的 WordPress 用了某个带漏洞的老插件、老主题,而网上已经公开了这个漏洞的利用方法,那你就等于把门开了一半。攻击者要的不是你站里的内容,是你的服务器——被打下来之后,拿来挂违规广告、发垃圾信息、当跳板。
事实三:被攻击的代价,小站更扛不住。 大站有专人值守、有安全团队、有异地备份。我这种个人站,出事了全靠自己,一个通宵都未必修得好,还可能连备份都没有,数据说没就没。这一点,我后来才真正体会到。
所以”小站不用管安全”这个想法,本质上是个赌——赌自己不会倒霉。而我赌输了。
我那次到底是怎么被注入的?
准确地说,我最后也没能百分之百锁定攻击入口,但有几个高度可疑的方向,排查日志的时候都冒出来了。
最可疑的:一个多年没更新的老插件。
我装过一个老插件,具体名字不说了,是早年在一个论坛上看到的。它最后一次更新是三年前,作者早就弃坑了。而它的某个功能里,有一个接受 URL 参数的地方,没有做任何过滤。
我在网站日志里搜到了大量带着 union select、' OR '1'='1 这类字符串的请求,目标指向的就是那个插件对应的路径。看到那串记录的时候,我基本确认了:这就是入口。
第二个可疑点:我的数据库账号权限太大了。
这是很多人都会犯的错。为了省事,给网站程序用的那个数据库账号,直接给了”全部权限”(ALL PRIVILEGES)。这意味着,一旦程序被注入,攻击者拿到的是”能对整个库为所欲为”的权限,删库、改表、批量插垃圾,全都干得了。
如果当初我建站的时候,只给那个账号”对当前网站这个库的增删改查”权限,攻击者就算注入成功了,能做的事情也有限得多。
第三个可疑点:我图省事,没开任何 Web 应用防火墙(WAF)。
我当时觉得 WAF 是大站才需要的。结果就是,所有恶意请求长驱直入,服务器层面、应用层面,没有任何一道拦截。
SQL 注入防护,普通人能做的几件事
被搞了一次之后,我把能补的补得七七八八。下面这些,是我认为个人站长”不用懂太多就能做”的防护措施。
第一,更新是第一道防线。 WordPress 核心、主题、插件,能用新的就用新的。安全更新尤其不能拖。那个让我栽跟头的插件,根本原因就是作者弃坑、漏洞没人补。插件市场里能看到”上次更新时间”,超过一年没更新的,能不用就不用。
第二,最小权限原则。 给网站程序分配的数据库账号,只给它真正需要的权限。不要图省事给全部权限。改权限这件事,宝塔面板里点几下就能操作,不难。
第三,装一个安全插件或 WAF。 WordPress 可以装 Wordfence 或者 Sucuri 这类安全插件,它们自带一部分 SQL 注入、XSS 的检测和拦截。服务器层面,宝塔也有免费的 WAF 能开。有总比没有强。
第四,对用户输入做过滤。 这一条偏开发,但如果你用的是主流 CMS 和更新及时的插件,其实大部分已经被处理好了。真正需要注意的是:别乱装来路不明、来历可疑的插件和主题,尤其别用那种”破解版””绿色版”。免费两个字背后,可能就藏着后门。
第五,定期看日志。 这条我已经反复说了。SQL 注入的痕迹是藏不住的——日志里那些 union select、drop table、' or 1=1 的字符串,一眼就能看出来。我在日志排查那篇里给过现成的命令,套用就行。
如果已经被注入了,怎么办?
万一你已经中招,别慌,顺序大概是这样的:
- 先断网止血。 把可疑的插件、主题先停掉,或者直接把网站临时下线,防止攻击者继续利用。
- 查日志定位入口。 找到那些带恶意字符串的请求,确定是哪个文件、哪个插件的问题。
- 改数据库密码、改后台密码、改服务器密码。 三套密码全部换掉,别用弱密码。
- 清理恶意数据。 数据库里多出来的垃圾,要么手动删,要么用备份恢复。详细的排查和清理,我在网站被黑自救那篇里写过完整流程,照着做就行。
- 恢复之后,把上面说的防护措施全部补上。 不然下次还来。
我写这篇文章,就是想跟每一个”觉得自己站小、不会有事”的站长说一句:
安全这件事,从来不是”流量大了才需要”。它更像买保险——你是希望用不上的时候它白搭,还是希望等到真的出事了,才发现自己裸奔了好几年?
我的那几万条垃圾数据,最后删是删掉了,但那个通宵,和那一身冷汗,我记到现在。
原创,首发于 wujianzhan.com。
