Security hardening for production readiness
- Add security headers (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, etc.) - Strengthen password requirements (10+ chars, mixed case, numbers) - Increase shared list slug entropy from 4 to 16 bytes - Add rate limiting to login, registration, upload, and restore endpoints - Add file magic number validation for image uploads (JPEG, PNG, WebP, HEIC) - Add CSV row limit (50k) to restore endpoint - Update client-side registration form to match new password policy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,10 @@ import {
|
||||
validateBackupData,
|
||||
executeRestore,
|
||||
} from "@/lib/backup"
|
||||
import { rateLimit } from "@/lib/rate-limit"
|
||||
|
||||
const VALID_MODES = ["merge-skip", "merge-update", "replace"] as const
|
||||
const MAX_CSV_ROWS = 50000
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const session = await auth()
|
||||
@@ -15,6 +17,15 @@ export async function POST(request: Request) {
|
||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
|
||||
}
|
||||
|
||||
// Rate limit: 3 restores per user per hour
|
||||
const rl = rateLimit(`restore:${session.user.id}`, 3, 60 * 60 * 1000)
|
||||
if (!rl.success) {
|
||||
return NextResponse.json(
|
||||
{ error: "Too many restore attempts. Please try again later." },
|
||||
{ status: 429 }
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
const formData = await request.formData()
|
||||
const file = formData.get("file") as File | null
|
||||
@@ -59,6 +70,13 @@ export async function POST(request: Request) {
|
||||
)
|
||||
}
|
||||
|
||||
if (rows.length > MAX_CSV_ROWS) {
|
||||
return NextResponse.json(
|
||||
{ error: `CSV exceeds maximum of ${MAX_CSV_ROWS.toLocaleString()} rows` },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Check for _type column
|
||||
if (!("_type" in rows[0])) {
|
||||
return NextResponse.json(
|
||||
|
||||
Reference in New Issue
Block a user