WordPress 被黑客入侵?为什么迁移到 Next.js + Supabase 是最佳解决方案
我已经数不清有多少客户带着同样故事的某个变体来找我们:"我们的WordPress网站被黑了。我们清理了。它又被黑了。我们放弃了。"最后一个案例是一家中型电商公司,他们的WooCommerce店铺在一个看起来合法的插件更新中被注入了信用卡盗刷程序。他们在有人发现之前泄露了三周的客户支付数据。这不是极端情况。这在WordPress生态中就是家常便饭。
这篇文章不是为了抨击WordPress。它为互联网的很大一部分提供了很好的支持是有理由的。但是2005年让它易于使用的架构,正是2025年让它成为自动化攻击磁铁的同一架构。如果你被黑过——或者你厌倦了花钱购买本身就是攻击向量的安全插件——这是你迁移到更从根本上安全的东西的指南。
目录
- WordPress安全问题是架构性的
- 2025年常见的WordPress攻击向量
- 为什么无头架构消除了整个攻击类别
- Next.js + Supabase:安全优先的技术栈
- 攻击面对比:WordPress vs 无头
- 迁移指南:WordPress到Next.js + Supabase
- 迁移后的安全加固
- WordPress安全的真实成本 vs 迁移
- 常见问题

WordPress安全问题是架构性的
让我明确一点:WordPress核心团队做了很好的安全工作。WordPress核心,保持更新,是相当安全的。但没人只运行WordPress核心。平均的WordPress网站安装了20-30个插件。每一个都是你没有编写的依赖项,由你不认识的人维护,有权访问你的数据库、文件系统和用户数据。
在"WordPress安全最佳实践"文章中一直被忽视的是:问题不是WordPress网站所有者疏忽。问题是WordPress的架构要求你直接在服务器上从第三方安装可执行的PHP代码以获得基本功能。这相当于给在你家工作的每个承包商永久地复制一份你家的钥匙。
WPScan的漏洞数据库在2024年追踪了超过7,900个新的WordPress漏洞,其中插件约占96%。Sucuri的2024威胁报告发现,WordPress占他们清理的所有CMS感染的约95%。Patchstack报告称,2024年33%的WordPress关键漏洞在披露时没有可用的补丁。
这些不是可以通过更好的编码实践修复的错误。它们是架构本身的突现属性。
2025年常见的WordPress攻击向量
在我们谈论解决方案之前,让我们列出你实际在防范什么。我个人分类过数十个被攻破的WordPress网站,攻击落入可预测的模式。
通过插件的SQL注入
WordPress使用一个架构文档完善的MySQL数据库。每个接受用户输入并触及数据库的插件都是一个潜在的SQL注入点。$wpdb->prepare()函数存在,但它是可选的。插件开发者忘记了它、误用了它,或者对"简单"查询完全跳过它。
我曾经追踪过一个注入,它来自一个已经停止维护18个月但仍然安装在200,000多个网站上的联系表单插件。攻击者使用基于UNION的注入来转储wp_users表,获取admin密码哈希,然后离线破解弱密码。
-- 日志中典型WordPress SQL注入看起来像这样
GET /wp-content/plugins/vulnerable-plugin/ajax.php?id=1%20UNION%20SELECT%201,user_login,user_pass,4,5%20FROM%20wp_users--
PHP对象注入和远程代码执行
WordPress对serialize()和unserialize()的大量使用创造了PHP对象注入的机会。当插件反序列化用户控制的数据时(许多确实这样做),攻击者可以制作在反序列化过程中执行任意代码的有效载荷。
在2024年,一个流行备份插件中的关键RCE漏洞(安装在500万+网站上)允许未认证的攻击者执行任意PHP代码。修复花了11天才发布。11天内安装该插件的每个网站都易受攻击。
插件供应链攻击
这是最让我害怕的。攻击者购买具有大量安装基础的已放弃的插件,推送包含后门的"安全更新",WordPress自动更新机制将恶意软件分发到运行该插件的每个网站。这发生在Display Widgets(300,000个安装)和Social Warfare(70,000个安装)上,这些只是被发现的。
对wp-login.php的暴力破解攻击
每个WordPress网站默认暴露/wp-login.php和/xmlrpc.php。自动化僵尸网络不断攻击这些端点。Wordfence在2024年报告在其网络中每月阻止平均30亿个恶意请求。即使有速率限制和双因素认证,你也在花费服务器资源处理这些攻击。
通过主题和插件的跨站脚本(XSS)
WordPress中的存储XSS特别危险,因为admin仪表板和公众网站共享相同的会话上下文。通过评论注入的XSS有效载荷、表单提交或易受攻击的插件设置可以升级为完全的admin访问权限。
为什么无头架构消除了整个攻击类别
这里事情变得有趣。无头架构不仅仅减少了攻击面——它通过移除使攻击成为可能的条件来消除整个攻击类别。
在传统的WordPress设置中,呈现HTML的同一个服务器还要:
- 运行来自20多个第三方插件的PHP代码
- 管理用户认证
- 连接到数据库
- 提供admin界面
- 处理文件上传
- 处理表单提交
这对单个应用程序来说是很多责任。在使用Next.js和Supabase的无头设置中,这些责任分布在隔离的服务中:
- 前端(Next.js on Vercel/Netlify): 从CDN提供的静态HTML/JS。在大多数情况下,公共互联网上没有暴露服务器端运行时。
- 数据库 + 认证(Supabase): 带有行级安全的托管Postgres,从不直接暴露给最终用户。
- API层: 具有明确、最小端点的无服务器函数。
- CMS(如果需要): 在自己的隔离基础设施上运行的无头CMS。
没有PHP可以注入。没有写入权限的插件目录。admin和公众网站之间没有共享会话。没有wp-login.php供机器人攻击。
你不需要WAF来保护一个不存在的攻击面。

Next.js + Supabase:安全优先的技术栈
让我们具体说明为什么这个特定的组合从安全角度工作得很好。
Next.js:不运行代码的前端
当你用静态生成(SSG)或增量静态再生(ISR)构建Next.js网站时,部署的是CDN上的HTML、CSS和JavaScript文件。没有应用服务器实时处理请求。你不能SQL注入一个CDN。
对于动态功能,Next.js Server Actions和Route Handlers作为无服务器函数运行。每个函数:
- 在自己的执行上下文中隔离
- 无状态(请求之间没有共享内存)
- 短暂(冷启动、执行、终止)
- 显式定义(没有端点自动发现)
// Next.js Route Handler -- 显式、类型化、最小化
import { createClient } from '@/lib/supabase/server'
import { NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
const ContactSchema = z.object({
name: z.string().min(1).max(100),
email: z.string().email(),
message: z.string().min(10).max(5000),
})
export async function POST(request: NextRequest) {
const body = await request.json()
const parsed = ContactSchema.safeParse(body)
if (!parsed.success) {
return NextResponse.json({ error: 'Invalid input' }, { status: 400 })
}
const supabase = await createClient()
const { error } = await supabase
.from('contact_submissions')
.insert(parsed.data)
if (error) {
return NextResponse.json({ error: 'Submission failed' }, { status: 500 })
}
return NextResponse.json({ success: true })
}
将其与必须挂接到WordPress的action系统、包含自己的AJAX处理程序、管理自己的nonce验证,并构建自己的SQL查询的WordPress联系表单插件进行比较。Next.js版本的移动部分更少,通过Zod验证输入,并通过Supabase客户端使用参数化查询。
Supabase:具有行级安全的Postgres
Supabase为你提供一个带有一个关键安全功能的托管PostgreSQL数据库:行级安全(RLS)。你不是信任应用代码来强制访问控制(WordPress模型),而是在数据库级别定义安全策略。
-- 只有经认证的用户可以读取自己的数据
CREATE POLICY "Users can view own profile"
ON profiles
FOR SELECT
USING (auth.uid() = user_id);
-- 公众可以插入联系表单但不能读取
CREATE POLICY "Anyone can submit contact form"
ON contact_submissions
FOR INSERT
WITH CHECK (true);
CREATE POLICY "Only admins can read submissions"
ON contact_submissions
FOR SELECT
USING (auth.jwt() ->> 'role' = 'admin');
即使攻击者找到了一种方式来进行任意Supabase查询(在没有PHP执行上下文的情况下已经困难得多),RLS策略防止他们访问他们不应该看到的数据。这是WordPress根本无法提供的深度防御,因为它的权限系统是用PHP代码实现的,而不是在数据库层。
Supabase还通过内置支持电子邮件/密码、魔法链接、OAuth提供商和多因素认证来处理认证。不需要插件。没有第三方代码在你的服务器上运行。
攻击面对比:WordPress vs 无头
让我们并排放置。
| 攻击向量 | WordPress | Next.js + Supabase |
|---|---|---|
| SQL注入 | 高风险 -- 插件构建原始查询 | 接近零 -- 通过Supabase客户端的参数化查询,RLS作为备份 |
| PHP/远程代码执行 | 高风险 -- 插件执行服务器端PHP | 不适用 -- 没有PHP运行时 |
| 插件供应链 | 关键风险 -- 自动更新分发恶意软件 | 不适用 -- 没有插件生态系统 |
| 暴力破解(登录) | 总是暴露(wp-login.php、xmlrpc.php) |
通过Supabase Auth或单独仪表板的admin访问,无需公开登录端点 |
| XSS(存储) | 高风险 -- shared admin/public上下文 | 低风险 -- React默认转义输出,admin和public是单独的应用 |
| 文件上传利用 | 高风险 -- 上传的PHP文件可以执行 | 低风险 -- 上传到对象存储(Supabase存储/S3),从不作为代码执行 |
| 数据库暴露 | 服务器被攻破时直接MySQL访问 | 数据库位于Supabase基础设施后面,RLS策略作为最后防线 |
| 源的DDoS | 服务器必须处理每个请求 | CDN上的静态资产,源很少被访问 |
| 已知路径枚举 | wp-admin、wp-content、wp-includes都可扫描 |
没有可预测的路径,没有暴露的admin路由 |
迁移指南:WordPress到Next.js + Supabase
好的,你被说服了(或者你被黑的网站说服了你)。这是如何实际做这件事的。我们在Social Animal运行了足够多次的迁移以拥有可重复的过程。
第1阶段:分类和内容审计(第1周)
在你接触任何代码之前,你需要理解你实际拥有什么。
- 导出所有WordPress内容使用WP-CLI或REST API。不要依赖XML导出——它们会遗漏meta字段和自定义post类型。
- 列出所有功能由插件提供。制作一个电子表格:插件名称、它做什么、你是否真正需要它,以及什么替代它。
- 映射URL结构用于SEO保留。每个现有URL都需要在Next.js中重定向或匹配路由。
- 识别动态功能 -- 表单、搜索、用户帐户、电商 -- 需要API端点。
# 通过REST API导出WordPress内容
curl -s "https://yoursite.com/wp-json/wp/v2/posts?per_page=100&page=1" | jq '.' > posts_page1.json
curl -s "https://yoursite.com/wp-json/wp/v2/pages?per_page=100" | jq '.' > pages.json
curl -s "https://yoursite.com/wp-json/wp/v2/media?per_page=100" | jq '.' > media.json
第2阶段:Supabase架构和数据迁移(第2周)
根据内容审计设计你的Supabase数据库架构。不要只是复制WordPress架构——它充斥着meta表和序列化数据blob。
-- 干净、目标导向的架构
CREATE TABLE posts (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
title TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
content TEXT,
excerpt TEXT,
featured_image TEXT,
status TEXT DEFAULT 'draft' CHECK (status IN ('draft', 'published', 'archived')),
published_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
author_id UUID REFERENCES auth.users(id)
);
-- 立即启用RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Published posts are public"
ON posts FOR SELECT
USING (status = 'published');
CREATE POLICY "Authors can manage own posts"
ON posts FOR ALL
USING (auth.uid() = author_id);
编写一个迁移脚本(Node.js或Python),将WordPress JSON导出转换为你的新架构,并将其插入Supabase。
第3阶段:Next.js构建(第3-5周)
构建你的Next.js前端。如果你在一个了解技术栈的团队中工作,这进展很快。如果你需要帮助,我们的Next.js开发团队已经进行了足够多次的迁移以对正确的模式有强有力的观点。
关键的架构决定:
- 内容页面的静态生成 -- 博文、登陆页、关于页。这些变成CDN上的HTML文件。
- 动态数据的Server Components -- 实时从Supabase获取数据并缓存。
- 表单提交的Route Handlers -- 联系表单、新闻通讯注册等。
- 重定向的中间件 -- 处理所有你的旧WordPress URL。
// next.config.ts -- 处理WordPress URL重定向
const nextConfig = {
async redirects() {
return [
{
source: '/category/:slug',
destination: '/blog/category/:slug',
permanent: true,
},
{
source: '/:year(\\d{4})/:month(\\d{2})/:slug',
destination: '/blog/:slug',
permanent: true,
},
// wp-login.php -- 向机器人发送410
{
source: '/wp-login.php',
destination: '/gone',
permanent: true,
},
{
source: '/wp-admin/:path*',
destination: '/gone',
permanent: true,
},
]
},
}
第4阶段:测试和SEO验证(第6周)
- 针对新网站运行Screaming Frog以验证每个旧URL要么解析要么重定向。
- 验证结构化数据(JSON-LD)存在于所有页面。
- 测试所有表单和动态功能。
- 运行Lighthouse和Core Web Vitals检查——你几乎肯定会看到改进,因为你现在从CDN提供服务。
- 使用Vercel Analytics或你首选的工具设置监控。
第5阶段:启动和DNS切换(第6-7周)
部署到Vercel或Netlify,更新DNS,并设置监控。将旧的WordPress实例保持离线但可访问30天,以防你需要参考任何内容。
如果你的网站有大量流量或电商功能,考虑无头CMS集成以进行内容管理,并与我们谈论Astro作为替代前端针对内容密集型网站,其中构建性能很重要。
迁移后的安全加固
一旦你在新堆栈上,这是你的安全检查清单:
- 在每个表上启用Supabase RLS。 没有例外。如果一个表没有策略,它要么无法访问(好的默认值),要么完全开放(坏)。
- 为所有秘密使用环境变量。 Vercel和Netlify都处理得很好。永远不要提交API密钥。
- 设置Supabase数据库备份。 时间点恢复在Pro计划上可用($25/月)。
- 在你的Next.js中间件中配置内容安全策略头。
- 启用Vercel的DDoS保护(包含在所有计划中)。
- 设置正常运行时间监控 -- 我们使用Better Uptime,但Checkly和Vercel的内置监控也有效。
- 季度审计你的Supabase RLS策略。 使用Supabase的SQL编辑器用不同的用户上下文测试策略。
// middleware.ts -- 安全头
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('X-Frame-Options', 'DENY')
response.headers.set('X-Content-Type-Options', 'nosniff')
response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
response.headers.set(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';"
)
response.headers.set(
'Permissions-Policy',
'camera=(), microphone=(), geolocation=()'
)
return response
}
WordPress安全的真实成本 vs 迁移
让我们谈谈钱,因为那是实际驱动决定的。
| 成本类别 | WordPress(年度) | Next.js + Supabase(年度) |
|---|---|---|
| 托管 | $300-1,200(托管WP) | $0-240(Vercel Pro) |
| 安全插件(Wordfence/Sucuri) | $200-500 | $0(不需要) |
| SSL/CDN | $0-200 | $0(包含) |
| 恶意软件清理(如果被黑) | 每次事件$500-2,500 | N/A |
| 开发人员在安全补丁上的时间 | $2,000-5,000 | $500-1,000 |
| 数据库(Supabase) | 包含在托管中 | $0-300(免费层到Pro) |
| 总计 | $3,000-9,400 | $500-1,540 |
这还没有考虑停机时间的成本、失去的客户信任以及如果客户数据被泄露可能的监管处罚。一次GDPR可报告的数据泄露可能花费数万美元的法律和合规费用。
迁移本身通常花费$10,000-40,000,取决于网站复杂性。对于大多数业务,在仅仅1-2年内减少的安全支出就能收回——并且你还获得了一个更快、更可维护的网站。查看我们的定价页面以获取关于迁移项目的具体信息。
常见问题
WordPress真的那么不安全,还是这被夸大了? WordPress核心维护得很好。问题是几乎没有人只运行核心。插件生态系统是96%漏洞的所在地,你无法在不使用插件的情况下运行有用的WordPress网站。这不是夸大——Sucuri在2024年从超过60,000个WordPress网站中清理了恶意软件。架构要求你信任服务器上的第三方PHP代码,这个信任经常被利用。
我可以改用更好的安全插件而不是迁移吗? 安全插件本身是在服务器上运行的PHP代码,具有深层系统访问权限。Wordfence和Sucuri维护得很好,但它们是架构问题的创可贴。它们还增加服务器负载,可能与其他插件冲突,并且多年来有自己的漏洞。你在添加复杂性来解决复杂性问题。
WordPress到Next.js迁移通常需要多长时间? 对于标准业务网站(10-50页、博客、联系表单),我们通常在5-7周内完成迁移。具有WooCommerce的电商网站更复杂,可能花费8-14周,取决于产品目录大小和自定义功能。如果你有更简单的网站,联系我们,我们可以给你更具体的时间表。
当从WordPress迁移时,我会失去我的SEO排名吗? 如果你做对了,不会。关键步骤是:保留所有URL结构或设置适当的301重定向、维护你的结构化数据标记、保持你的内容完整,并将更新的网站地图提交给Google Search Console。我们大多数迁移客户在2-3个月内看到排名改进,因为当你移到CDN提供的静态网站时,Core Web Vitals分数会大幅提高。
内容编辑呢?WordPress对非技术用户很容易。 这是一个合理的关切。你有选择:Supabase配合自定义admin仪表板,或一个无头CMS如Sanity、Contentful或Payload CMS,它为内容编辑提供类似于WordPress的可视编辑体验。我们定期处理无头CMS集成,可以推荐适合你团队需求的合适选择。
Supabase对于生产使用足够安全吗? Supabase在AWS基础设施上运行,具有SOC 2 Type II合规性。底层数据库是PostgreSQL,具有强大的安全记录。行级安全策略在数据库级别强制访问控制,这实际上比WordPress的PHP权限系统更安全。Supabase也在付费计划上提供时间点恢复、加密连接和网络限制。
如果我的WordPress网站被黑了,我需要立即帮助怎么办? 首先,立即将网站离线以停止进一步的损害和数据泄露。其次,保留法证证据(数据库转储、访问日志、文件系统快照)。第三,不要只是清理它并把它放回去——你可能在几周内被重新感染。将这个事件用作迁移的催化剂。联系我们的团队,我们可以帮助进行立即分类和迁移规划。
我可以一次迁移所有内容,还是可以增量进行? 增量迁移是可能的但增加复杂性。你可以在保持WordPress作为无头CMS后端临时运行Next.js作为前端,然后完全逐步淘汰WordPress。然而,这意味着WordPress仍在运行,在过渡期间仍需要安全维护。对于大多数网站,干净的切换更快、更便宜,并更快地消除安全风险。