Untuk mengeraskan Next.js Upload API Route di App Router, langsung lakukan validasi file, sanitasi metadata, autentikasi/session kuat, rotasi secret, dan proteksi abuse sebelum mengeksekusi handler upload. Strategi ini menjawab kebutuhan pengembang yang butuh upload aman tanpa mengandalkan asumsi default.
Memahami Risiko Upload di App Router
Upload file adalah permukaan serangan yang menggabungkan input user, penyimpanan file, dan eksekusi backend. Tanpa pembatasan, klien bisa mengirim file berisi skrip berbahaya, oversized payload untuk exhaust memori, atau metadata yang mengelabui sistem autentikasi. Di App Router, route handler berjalan di serverless atau edge runtime, sehingga kontrol dan validasi harus terjadi sebelum disk I/O atau transfer ke cloud storage.
Tujuan utama: validasi konten, lindungi kredensial, dan deteksi pola abuse sedini mungkin. Dengan pendekatan bertingkat, kita bisa menyeimbangkan keamanan dan throughput.
Validasi dan Sanitasi File
Validasi file mencakup setidaknya tiga aspek: tipe MIME & ekstensi, ukuran maksimum, serta metadata (nama file, field form, header tambahan). Untuk App Router, gunakan route.ts dengan parser multipart seperti formidable di server. Yang penting: jangan langsung menulis file ke disk tanpa pengecekan.
Contoh pengecekan sederhana di handler:
import formidable from 'formidable-serverless';
export const POST = async (req: Request) => {
const form = formidable({ maxFileSize: 4 * 1024 * 1024 });
const parsed = await form.parse(req);
const file = parsed.files?.file;
if (!file) return new Response('No file', { status: 400 });
const safeTypes = ['image/png', 'image/jpeg'];
if (!safeTypes.includes(file.mimetype)) {
return new Response('Tipe tidak diperbolehkan', { status: 415 });
}
if (file.size > 4 * 1024 * 1024) {
return new Response('File terlalu besar', { status: 413 });
}
const sanitizedFilename = file.originalFilename?.replace(/[^a-zA-Z0-9._-]/g, '_');
// lanjut ke penyimpanan
};
Gunakan whitelist tipe MIME karena hanya memeriksa ekstensi saja terlalu mudah diakali. Sanitasi nama file mencegah traversal path atau karakter tak valid.
Validasi metadata seperti field tambahan (misal ownerId) juga penting: pastikan berasal dari token yang diverifikasi, bukan dari form mentah.
Autentikasi, Secret Rotation, dan Proteksi Abuse
Lakukan autentikasi dan pengecekan session sebelum memproses upload. Pada App Router, middleware dapat memeriksa cookie/session di edge sebelum masuk ke handler utama.
export const middleware = async (req: NextRequest) => {
const token = req.cookies.get('sessionToken');
if (!token || !await verifySession(token)) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
return NextResponse.next();
};
Pastikan secret (JWT signing key, API key) dirotasi secara berkala. Manfaatkan secret manager (misal AWS Secrets Manager, HashiCorp Vault) agar rotasi tidak menuntut redeploy. Verifikasi signature token terhadap versi aktif secret dan fallback untuk grace period rotasi.
Proteksi abuse tambahan meliputi:
- Upload scan: jalankan antivirus atau scan hash file dengan daftar malware sebelum diterima.
- Chunk limit: batasi jumlah chunk per sesi; jika menggunakan streaming, tetapkan timeout untuk setiap bagian.
- Alarm: kirim notifikasi jika request upload melebihi threshold ukuran atau jumlah kegagalan validasi.
Ketika penggunaan scan pihak ketiga tidak tersedia, tambahkan heuristik seperti menghitung entropy file untuk tersangka kompresi berat.
Rate Limiting Adaptif dan Middleware
Rate limit harus mempertimbangkan autentikasi. Token atau user ID dapat menjadi key untuk hitungan. Rate limit adaptif menyesuaikan batas berdasarkan faktor seperti status user, frekuensi upload terakhir, atau ada tidaknya sinyal abuse.
const RATE_LIMIT = 20; // permintaan per menit untuk user baru
const BURST_LIMIT = 5;
const limiter = createRateLimiter({
window: 60,
max: RATE_LIMIT,
strategy: 'token-bucket',
});
export async function POST(req: Request) {
const userId = await extractUserId(req);
const remaining = await limiter.consume(userId);
if (!remaining) {
return new Response('Too many requests', { status: 429 });
}
// proses upload
}
Gunakan middleware atau edge function untuk menaruh logika ini sedini mungkin agar request ditolak sebelum parser multipart dijalankan. Untuk adaptif rate limit, selama permintaan sukses berturut-turut dalam jangka pendek, kurangi limit untuk user tersebut agar menghentikan pola upload berbahaya.
Konfigurasi Penyimpanan: Disk Lokal vs Cloud
Pilih penyimpanan berdasarkan skenario:
- Disk lokal: cocok untuk pengembangan atau sistem on-premise. Pastikan direktori upload di luar path publik dan gunakan storage yang dihapus secara periodik.
- Cloud storage (S3, GCS): unggulan untuk skala besar. Upload langsung lewat signed URL jika memungkinkan agar server tidak memegang payload besar.
Contoh pola hybrid: handler memvalidasi lalu memindahkan file ke staging directory, lalu mengunggah ke S3 dengan aws-sdk dan menghapus file lokal setelah berhasil:
const client = new S3Client({ region: process.env.AWS_REGION });
await client.send(new PutObjectCommand({
Bucket: process.env.UPLOAD_BUCKET,
Key: `${userId}/${Date.now()}-${sanitizedFilename}`,
Body: fs.createReadStream(tempFile.path),
ContentType: file.mimetype,
}));
await fs.promises.unlink(tempFile.path);
Untuk signed URL, handler hanya menghasilkan URL untuk diunggah langsung oleh klien, memperkecil beban server.
Strategi Testing, Observability, dan Respons Abuse
Uji upload dengan kerangka tes integrasi yang mensimulasikan file berbahaya, ukuran besar, dan metadata tidak valid. Gunakan fixture file nyata (misal file gambar kecil dan dummy script tersembunyi) agar validasi dan ekspektasi error bisa dipastikan. Tambahkan tes yang mensimulasikan rate limit untuk memastikan respons 429.
Observability penting untuk mendeteksi abuse. Log setiap validasi gagal dengan metadata berikut:
- IP atau user ID
- Jenis kesalahan (tipe file, ukuran, rate limit)
- Timestamp dan route
Forward log ini ke platform monitoring (Grafana, DataDog). Gunakan metrik custom seperti upload.validation.failures, upload.rate.limit.exceeded, dan upload.scan.failed. Setup alarm ketika metrik di atas melonjak dalam satu menit.
Jika abuse terjadi, buat respons otomatis: misalnya blokir user/session untuk sementara (backoff), kirim notifikasi kepada tim keamanan, dan reset token jika diperlukan. Pastikan sistem rotasi secret dapat mencabut akses lama seperti token API.
Dengan validasi berlapis, middleware adaptif, dan observability menyeluruh, Upload API Route Next.js menjadi lebih tahan terhadap abuse sambil tetap memberikan pengalaman pengguna yang lancar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!