6月2日 23:07
Next.js 应用有哪些安全风险?环境变量泄露、XSS 和 CSRF 防护实战
Next.js 应用的安全风险主要来自三方面:服务端渲染(SSR)泄露敏感数据、API 路由缺乏认证、客户端代码暴露过多信息。逐个堵住就行。
1. 环境变量:服务端 vs 客户端
Next.js 的环境变量默认只在服务端可用。以 NEXT_PUBLIC_ 开头的才会暴露给浏览器。最常见的错误:把数据库密码、API Key 加了 NEXT_PUBLIC_ 前缀。
bash# .env.local — 只在服务端可用 DATABASE_URL=postgresql://... STRIPE_SECRET_KEY=sk_live_... # .env.local — 暴露给浏览器(谨慎使用) NEXT_PUBLIC_API_URL=https://api.example.com NEXT_PUBLIC_GA_ID=G-XXXXXXX
检查方法:浏览器 F12 > Sources > 搜索你的密钥。如果搜到了,说明 NEXT_PUBLIC_ 用错了。
2. API 路由必须加认证
App Router 的 Route Handlers 默认没有任何认证:
typescript// app/api/users/route.ts — 裸奔的 API,任何人都能访问 export async function GET() { const users = await db.user.findMany(); return Response.json(users); }
加上认证中间件:
typescriptimport { getServerSession } from 'next-auth'; export async function GET(request: Request) { const session = await getServerSession(); if (!session) { return new Response('Unauthorized', { status: 401 }); } const users = await db.user.findMany(); return Response.json(users); }
更高效的方式:用 Next.js 中间件统一拦截,不用每个路由单独写:
typescript// middleware.ts import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export function middleware(request: NextRequest) { const token = request.cookies.get('session-token'); if (!token && request.nextUrl.pathname.startsWith('/api/')) { return new Response('Unauthorized', { status: 401 }); } return NextResponse.next(); } export const config = { matcher: '/api/:path*', };
3. 防止 XSS
React 默认转义 HTML,XSS 风险不大。但 dangerouslySetInnerHTML 是例外:
tsx// 危险:用户输入的 HTML 直接渲染 <div dangerouslySetInnerHTML={{ __html: userContent }} /> // 安全:先用 DOMPurify 清洗 import DOMPurify from 'isomorphic-dompurify'; <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />
另一个 XSS 来源:URL 参数直接插入页面。Next.js 的 useSearchParams() 读取的值如果不转义就渲染,可能被注入。
4. CSRF 防护
SameSite Cookie 是最简单的 CSRF 防护:
typescript// 设置 Cookie 时加 SameSite cookies().set('session-token', token, { httpOnly: true, secure: true, sameSite: 'lax', // 阻止跨站请求携带 Cookie path: '/', maxAge: 60 * 60 * 24 * 7, });
sameSite: 'lax' 允许顶层导航携带 Cookie(用户点链接跳转正常),但阻止跨站 POST 请求携带。对大部分应用够用。
5. Content Security Policy
CSP 限制页面能加载哪些外部资源,防止恶意脚本注入:
typescript// middleware.ts export function middleware(request: NextRequest) { const response = NextResponse.next(); response.headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-eval' https://cdn.example.com; style-src 'self' 'unsafe-inline';" ); return response; }
CSP 配置比较繁琐,建议用 next-safe 库简化。先从 default-src 'self' 开始,逐步放宽需要的域名。
6. 依赖安全审计
bashnpm audit # 检查已知漏洞 npm audit fix # 自动修复 npx better-npm-audit audit # 更详细的审计
定期跑 npm audit,高危漏洞必须修。Next.js 自身也有安全更新——保持版本最新。
安全检查清单
- 环境变量没有敏感信息泄露到客户端
- API 路由都有认证
- Cookie 设置了 httpOnly + secure + sameSite
- dangerouslySetInnerHTML 用了 DOMPurify
- 有 CSP 头
- npm audit 无高危漏洞