diff --git a/app/layout.tsx b/app/layout.tsx index 207d5184c..853ec3208 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -13,7 +13,7 @@ export async function generateMetadata(): Promise { const updatedAt = "updatedAt" in settings && settings.updatedAt ? new Date(settings.updatedAt).getTime() - : Date.now(); + : "default"; const faviconUrl = `/api/favicon?v=${updatedAt}`; const metadataBase = process.env.AUTH_URL ? new URL(process.env.AUTH_URL) diff --git a/proxy.ts b/proxy.ts index 8c2f055b5..2ce34ea38 100644 --- a/proxy.ts +++ b/proxy.ts @@ -11,15 +11,19 @@ import { isSuspiciousRequest, logSuspiciousRequest } from "@/lib/security/reques function isHighFrequencyReadApi(pathname: string, method: string) { if (method !== "GET") return false; if (/^\/api\/canvas\/[^/]+\/detail-archives$/.test(pathname)) return true; + if (/^\/api\/canvas\/[^/]+$/.test(pathname)) return true; return [ "/api/models", "/api/canvas", + "/api/canvas-skill-tags", "/api/nav-links", "/api/site-settings", "/api/messages", "/api/history", + "/api/vote", "/api/video-tasks", + "/api/user/image-stats", "/api/tutorial-videos", "/api/user/membership-summary", "/api/user/account-center", @@ -63,6 +67,11 @@ export async function proxy(request: NextRequest) { // 可以在这里添加更严格的检查 } + // 浏览器会自动拉取 favicon,不应参与通用 API 限流。 + if (pathname === "/api/favicon") { + return NextResponse.next(); + } + // 🛡️ 安全检查3:速率限制 // 对API路径应用速率限制 if (pathname === "/api/chat") { @@ -126,6 +135,21 @@ export async function proxy(request: NextRequest) { { status: 429 } ); } + } else if (pathname === "/api/canvas/auto-title" && request.method === "POST") { + const canvasRateLimit = checkRateLimit(request, rateLimiters.canvas); + if (!canvasRateLimit.allowed) { + console.warn(`[Security] Canvas auto-title rate limit exceeded for IP: ${clientIP}`, { + pathname, + resetTime: new Date(canvasRateLimit.resetTime).toISOString(), + }); + return NextResponse.json( + { + error: "Too many canvas requests", + retryAfter: Math.ceil((canvasRateLimit.resetTime - Date.now()) / 1000), + }, + { status: 429 } + ); + } } else if ( pathname.startsWith("/api/realtime/") || pathname.startsWith("/api/fal/proxy")