WordPress 遭遇 SQL 注入怎么办?分享我的防范思路

昨天晚上我日常检查日志,发现有一批请求带着奇怪的参数,反复往同一个 URL 提交,参数出现大量 SQL 关键字。我当时心里就咯噔一下,这不是普通的扫描流量,是有人在 SQL 注入。

说实话,这已经不是我第一次遇到这种情况了。

我知道很多刚建站的朋友,对于 WordPress 遭遇 SQL 注入,第一反应就是担心网站会不会被黑、数据会不会丢、要不要重装系统。其实不用那么紧张,只要处理思路对,都能控制住。

这篇文章我想把昨晚的处理过程完整记录下来,包括我是怎么判断确实是 SQL 注入、怎么一步步排查和修复的,还有后面我又做了哪些调整来防止类似的事情再发生。

如果你也担心自己的网站会遇到同样的问题,或者已经中招了正手忙脚乱,希望能帮到你。

我是怎么发现问题的

那天晚上我打开的其实是最普通的访问日志,本来只是随手看看有没有异常流量。结果往下翻的时候,看到一长串长得很奇怪的请求,其中部分日志是这样的:

WordPress 遭遇 SQL 注入
WordPress 遭遇 SQL 注入

第一眼看到我就知道不对劲了。你仔细看异常的日志,参数里出现了 UNIONSELECT 等词。都是标准的 SQL 语句关键字,正常用户点击网站的时候是不可能在网址里带上这些东西的。

更让我警惕的是,这样的请求不止一条,日志里翻了翻,同一个 IP 段在短时间内发了几十条类似的请求,每次参数写法都有点不一样,明显是在用工具一个个尝试不同的注入方式。

这种手法我见得多了,基本可以确定,我的 WordPress 遭遇 SQL 注入是实锤了,不是我多想。

而判断这类攻击其实有几个比较明显的信号,我自己一般会从这几个方面去看:

  • 日志里频繁出现 SQL 关键字:像 UNIONSELECT 等,正常访问根本不会带这些
  • 同一时间段请求量异常:如果攻击的请求数量比较大,网站打开速度会明显变慢,甚至一段时间内直接卡住加载不出来,这也是很多人最先察觉到“网站好像有问题”的原因
  • 网站数据本身发生变化:如果攻击已经得手,最直接的表现就是数据库里的东西被动了手脚,比如后台密码突然登录不进去、用户列表里莫名多出几个自己没建过的管理员账号

我当时的情况还算幸运,从日志时间戳来看,这批请求集中爆发的时间很短,我发现得也算及时,赶紧去后台核实了一下用户列表和最近的登录记录,数据也没有被改动的痕迹。

不过话说回来,就算这次没造成实际损失,也不能掉以轻心。日志里能看到这么多针对性的 SQL 注入尝试,说明网站早就被盯上了,光是这次防住了不代表下次也能防住。

快速止血:先把防护用起来

发现问题的当晚,我第一件事是把最简单粗暴但确实有效的办法先用上:装一个 Wordfence

装个 Wordfence,先扛住大部分攻击

Wordfence 是 WordPress 里比较主流的一款免费安全插件,它自带的规则库就能识别出很大一部分 SQL 注入的攻击特征,遇到可疑请求直接拦下来,不会放行到你的网站逻辑里去。

对大多数中小站长来说,说实话这一步已经能挡住绝大部分的常规攻击了,不需要你懂多少安全知识,装完插件基本就能睡个安稳觉。

不过我自己用了一段时间后,发现了一个问题。

Wordfence 也有短板:本质还是 PHP 代码

Wordfence 虽然好用,但它终究是跑在 WordPress 里面的一个插件,本质上还是 PHP 代码。

也就是说,一个恶意请求发过来,得先经过服务器接收、PHP 解析、加载 WordPress、再由 Wordfence 去判断拦不拦。这个链路走下来,其实已经消耗了一部分资源。

平时攻击量小的时候你根本感觉不出来,但那天晚上攻击请求一多,我就发现网站打开速度肉眼可见地变慢了。虽然 Wordfence 把请求拦住了,服务器也付出了处理成本,导致访客受影响。

把拦截往前挪一步:用 Web 服务器直接挡

想清楚这个问题以后,我在想能不能直接在 Web 服务器那一关就给挡回去。

我自己用的是 OpenResty,它支持写 Lua 脚本,可以在请求刚进来的时候就做一次判断。

所以我写了一个比较简单的脚本,专门检测 URL 参数里有没有 UNION、SELECT、这类明显的 SQL 注入特征,直接返回拒绝,根本不给它进 WordPress 的机会。

-- 【SQL 注入通用拦截】
local uri_decoded = ngx.unescape_uri(req_uri)
if ngx.re.find(uri_decoded, [[(?i)(union.*select|extractvalue\s*\(|updatexml\s*\(|sleep\s*\(|benchmark\s*\(|into.*outfile)]], "jo") then
    ngx.exit(403)
end

虽然拦截规则很简陋,但足够撑过这次攻击了。

这样做的好处很直接:服务器不用为恶意请求消耗大量的 PHP 和数据库的资源,网站的整体响应速度也稳定了不少。如果你用的是 Nginx,其实思路也是一样的,尽可能提前处理风险请求。

如果想要更省心,可以考虑商业防护

自己动手写规则确实有效,但也有个现实问题:你得持续关注新的攻击手法,自己去更新规则。如果你不想天天盯着这些,或者网站流量比较大、比较在意稳定性,我建议可以选择付费服务。

比较常见的选择有这么几种:

  • Wordfence 付费版:相比免费版,功能更多,能识别更多新出现的攻击手法
  • 面板自带的 WAF 服务:如果你用的是宝塔或者 1Panel 这类面板,它们都提供了的 WAF 防护模块,不需要自己写规则,直接开启就能用(可能需要订购专业版)
  • 开源 WAF,比如雷池:如果你不想额外花钱,又希望比插件层面更彻底一些,雷池这类开源 WAF 也是不错的选择,部署在服务器前面统一拦截,规则社区也在持续维护

这几种方案各有侧重,免费插件适合刚起步、预算有限的站点先顶上,付费方案适合已经有一定规模、经不起频繁被攻击折腾的网站。你可以根据自己网站的实际情况,搭配着用。

写在最后

这次 WordPress 遭遇 SQL 注入的经历,给我提了个醒:安全问题不容忽视。

安全防护也不算困难,Wordpress 层面有 Wordfence 兜底,服务器层面有 Lua 脚本可以做前置拦截,再加上必要时候的商业 WAF 加持,层层设防,就能真正把风险降到最低。

不过说到底,应用层的防护只是其中一环。如果你的服务器本身线路不稳定、经常被扫段攻击,或者所在机房本来就容易被针对,那再好的插件规则也是治标不治本。

如果条件允许,建议选择一款高防 VPS,能够保障业务运行在更加安全的环境。

常见问题解答(FAQ)

Q1:WordPress 遭遇 SQL 注入后,网站一定会被攻破吗?

不一定。

SQL 注入分为尝试阶段得手阶段,很多时候日志里能看到大量的注入请求,但只要你的代码或者数据库层面做了基本的参数过滤,攻击者其实是在做无效尝试。

真正判断有没有被攻破,还是要看后台账号、数据库记录有没有异常。

Q2:装了 Wordfence 是不是就可以完全不用管了?

不建议这么想。

Wordfence 能拦住大部分常规攻击,但它运行在 PHP 层面,遇到攻击量大的情况,服务器还是会消耗大量计算资源。条件允许的话,建议在 Web 层完成拦截。

Q3:我不会写 Lua 脚本,还有其他办法在服务器层面拦截吗?

如果你觉得自己写规则门槛高,可以考虑用面板自带的防护功能。比如用1Panel 搭建和管理服务器,它对新手更友好,提供一些安全设置和防护规则可以用。

Q4:网站被攻击导致变慢,还有别的办法优化吗?

除了前置拦截减少无效请求的消耗,合理配置服务器资源、给数据库做适当优化也很重要。如果你的网站访问量突增或者被攻击导致卡顿,可以考虑升级配置。

也不用担心要迁移数据,像搬瓦工等很多商家,都支持补差价升级 VPS。

Q5:免费的防护方案和付费 WAF,差距到底大不大?

免费方案对付常规、批量的攻击基本够用,胜在零成本、上手快。

如果你的网站流量比较大,或者本身就是容易被针对的行业,付费 WAF 在规则更新速度和精细度上会明显更有优势,尤其是应对一些比较新的攻击手法时。

Q6:除了防 SQL 注入,还需要注意哪些安全问题?

SQL 注入只是常见攻击方式之一,实际运维中还会遇到暴力破解后台密码、恶意扫描漏洞插件等情况。如果你的服务器经常暴露在这类攻击风险下,建议选择高防 VPS

发表评论