如何简单保护Next.js 14 API端点?小游戏高分提交场景防护方案
针对Next.js 14游戏高分提交端点的防护方案(小型项目适配)
1. 先做服务器端的基础合理性校验
这是最低成本的防护,直接在/api/games/highscore接口里卡死明显不合理的分数:
- 根据你的游戏规则,设定分数上限(比如单局最高10000分,超过直接拒绝);
- 结合游戏时长校验:比如一局游戏最少要30秒才能完成,用户提交的分数对应的时长只有5秒,直接拦截。前端提交分数时顺便传游戏时长,后端做校验。
- 代码示例(Next.js 14 Route Handler):
// app/api/games/highscore/route.ts import { NextResponse } from 'next/server'; export async function POST(request: Request) { const { score, gameDuration, userId } = await request.json(); // 自定义游戏规则的校验逻辑 const MAX_ALLOWED_SCORE = 10000; const MIN_GAME_DURATION = 30; // 单位:秒 if (score > MAX_ALLOWED_SCORE || gameDuration < MIN_GAME_DURATION) { return NextResponse.json({ error: '无效分数' }, { status: 400 }); } // 这里写存储分数到数据库的逻辑 return NextResponse.json({ success: true }); }
2. 绑定用户身份+限制请求频率
- 强制用户登录后才能提交高分,用NextAuth做个简单的邮箱/Google登录就行,门槛极低。后端接口先校验用户session,没登录直接拒绝。
- 限制同一用户的提交频率:比如1分钟内最多提交2次,防止恶意刷分。小型项目用Upstash这种Serverless Redis就行,免费额度足够用,不用自己搭服务。
- 代码示例(结合NextAuth):
// app/api/games/highscore/route.ts import { getServerSession } from 'next-auth/next'; import { authOptions } from '../auth/[...nextauth]/route'; import { NextResponse } from 'next/server'; import { Redis } from '@upstash/redis'; // 从环境变量取Upstash的配置 const redis = new Redis({ url: process.env.UPSTASH_REDIS_URL!, token: process.env.UPSTASH_REDIS_TOKEN!, }); export async function POST(request: Request) { // 校验用户是否登录 const session = await getServerSession(authOptions); if (!session?.user?.id) { return NextResponse.json({ error: '未授权,请先登录' }, { status: 401 }); } const userId = session.user.id; const submitCountKey = `highscore:submit:${userId}`; const currentCount = await redis.get(submitCountKey); // 1分钟内最多提交2次 if (currentCount && parseInt(currentCount) >= 2) { return NextResponse.json({ error: '提交过于频繁,请稍后再试' }, { status: 429 }); } // 更新计数并设置过期时间 await redis.incr(submitCountKey); await redis.expire(submitCountKey, 60); // 后续的分数校验和存储逻辑... return NextResponse.json({ success: true }); }
3. 前端辅助校验(别单独依赖)
在前端加些简单的行为校验,比如记录用户游戏中的关键操作(比如关卡进度、点击次数),提交分数时一起传给后端,后端校验这些操作和分数是否匹配。比如某关卡得1000分需要完成5个任务,用户提交1000分但任务数是0,直接拒绝。
注意:前端逻辑很容易被篡改,所以这个只能当辅助,核心校验必须在后端。
4. 签名验证(进阶防篡改)
如果担心用户篡改前端提交的分数、时长这些数据,可以加签名验证:
- 用户进入游戏时,后端生成一个一次性密钥(或者绑定用户session的密钥)返回给前端;
- 游戏结束后,前端用这个密钥对
score + gameDuration + userId生成HMAC签名,和数据一起提交; - 后端收到后用同样的密钥重新计算签名,对比一致才处理。
- 简化代码示例:
// 前端生成签名(用crypto-js) import crypto from 'crypto-js'; const generateSignature = (score: number, duration: number, userId: string, secret: string) => { const data = `${score}:${duration}:${userId}`; return crypto.HmacSHA256(data, secret).toString(crypto.enc.Hex); }; // 后端验证签名(用Node.js内置crypto) import crypto from 'crypto'; const verifySignature = (score: number, duration: number, userId: string, signature: string, secret: string) => { const data = `${score}:${duration}:${userId}`; const computedSignature = crypto.createHmac('sha256', secret).update(data).digest('hex'); return computedSignature === signature; };
小型项目最优组合
优先用基础分数校验 + 用户身份绑定 + 请求频率限制,这三个组合起来实现成本极低,能挡住绝大多数恶意提交:
- 基础校验直接过滤离谱的分数;
- 用户绑定让恶意刷分需要多注册账号,提高成本;
- 频率限制防止短时间内批量刷分。
如果对防作弊要求稍高,再加个签名验证就行。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

