Checklist Review Keamanan Upload File
Upload file adalah pipeline, bukan sekadar field formulir. Nama file, header MIME, dan ekstensi berasal dari penyerang. File Upload Cheat Sheet OWASP serta CWE-434 menyarankan penanganan berlapis.
Petakan setiap tahap
Telusuri penerimaan, pemeriksaan tipe, penyimpanan, scanning, transformasi, pengambilan, dan penghapusan. Contoh: invoice.pdf.php tidak boleh menjadi executable hanya karena web server membaca ekstensi terakhir. Contoh lain: SVG dapat memuat konten aktif walau MIME yang diklaim adalah gambar.
Matriks kontrol upload
| Tahap | Kontrol | Kasus uji |
|---|---|---|
| terima | allowlist bisnis dan batas ukuran | polyglot ditolak |
| simpan | nama buatan sistem di luar web root | path langsung tidak dapat dieksekusi |
| proses | parser terisolasi dan timeout | arsip rusak tidak menghabiskan worker |
| sajikan | disposition dan cek akses | URL file privat ditolak |
Aturan keputusan: bila aplikasi tidak dapat mem-parsing atau menyajikan format dengan aman, jangan terima format tersebut.
Urutan remediasi
Izinkan format yang dibutuhkan saja, periksa magic byte, simpan di luar jalur executable, scan asinkron, dan otorisasi setiap unduhan. Hasil antivirus tidak membuktikan dokumen aman; isolasi parser tetap diperlukan. Audit kode dapat meninjau jalur storage dan retrieval.
Perlakukan pemrosesan sebagai eksekusi tidak tepercaya
Validasi kebutuhan bisnis sebelum menerima format. Dekode nama file sebelum memeriksa ekstensi, gunakan allowlist sempit, periksa signature tipe, dan beri identifier buatan server. Content-Type berguna sebagai telemetri tetapi bukan otoritas. Simpan objek di luar jalur web yang executable dan petakan retrieval melalui otorisasi, bukan nama filesystem. Hasil scanner dapat menambah sinyal; hasil itu tidak membuat parser aman.
Jalankan konversi, preview, dan ekstraksi arsip pada worker terbatas CPU, memori, waktu, dan ukuran output. Tolak atau karantina bila pemeriksaan tidak meyakinkan. Jalur unduh harus memeriksa ulang kepemilikan dan memilih Content-Disposition secara sengaja. Uji arsip oversized, signature tidak cocok, ekstensi ganda, nama mirip traversal, konten aktif, dan retrieval tanpa otorisasi. Owner: pemilik layanan upload. Lulus: sampel ditolak tidak dieksekusi, tidak tersimpan sebagai konten tersedia, dan tidak mencapai pengguna lain. Gagal: sampel melewati satu tahap. Pengecualian mencatat format, alasan, isolasi, approver, perbaikan, dan kedaluwarsa.
Kontrak storage dan retrieval
Kembalikan object ID aplikasi, bukan storage path. Hubungkan objek dengan owner, scope otorisasi, format terdeteksi, status scan, aturan retensi, dan hasil pemrosesan. Simpan objek pending agar tidak tersedia. Bila preview diperlukan, gunakan origin terpisah atau layanan terisolasi, bukan byte asli secara inline. Buktikan identifier tebakan tidak dapat melewati otorisasi.
Tanda terima rantai upload
Output yang diharapkan: ID objek upload, MIME yang diklaim, signature terdeteksi, ukuran byte, status karantina, exit code converter, hasil otorisasi retrieval. Bukti ini menghubungkan tahap upload dengan state objek yang tercatat.
Kegagalan teruji: File bernama PDF berisi signature executable. Layanan intake harus mengarantina file dan tidak boleh menjalankan konversi preview atau menerbitkan link unduh.
Kasus tepi: Upload yang tadinya berotorisasi dapat menjadi tidak berotorisasi setelah keanggotaan akun berubah. Retrieval harus memeriksa akses saat ini, bukan mempercayai izin saat upload.
Uji penutupan: Coba unduh memakai object ID tebakan setelah scan selesai. Penutupan lulus bila nama storage tetap tersembunyi dan otorisasi menolak request.
Drill containment parser
Pilih sampel rusak dengan sengaja untuk setiap format yang diterima. Uji harus menunjukkan worker mana yang menerimanya, berapa lama pemrosesan berjalan, bagaimana output dibatasi, dan di mana status gagal disimpan. Penanganan arsip memerlukan perhitungan terpisah untuk jumlah entri, jumlah byte setelah ekspansi, dan arsip bertingkat; file terkompresi di bawah batas request masih dapat menghabiskan converter. Jangan ekstrak ke path yang diturunkan dari nama upload. Path sementara buatan sistem memerlukan cleanup saat timeout dan worker restart.
Uji retrieval mencakup lebih dari header respons. Verifikasi objek tidak tersedia saat scanning, objek terhapus tidak dapat muncul lagi dari cache turunan, dan keputusan berbagi ditegakkan pada setiap unduhan. Ketika distribusi publik diperlukan, gunakan kebijakan terpisah untuk laporan penyalahgunaan dan penghapusan konten, bukan memberi URL publik kepada upload privat secara default. Perubahan remediasi selesai hanya setelah fixture lama yang berbahaya dan fixture normal yang diterima sama-sama melewati state pipeline yang diharapkan.
Output operasional harus mengidentifikasi penolakan terjadi pada intake, scan, konversi, storage, atau retrieval. Konversi gagal tidak boleh meninggalkan turunan publik. Jalankan ulang file diterima sama setelah worker restart untuk membuktikan cleanup tidak menghapus konten disetujui atau mengekspos byte karantina.
Keputusan tipe file harus diberi versi bersama requirement produk. Saat format baru diminta, nilai riwayat parser, perilaku konten aktif, kebutuhan preview, retensi, dan distribusi publik sebelum menambahkannya ke allowlist. Format yang diterima hanya untuk penyimpanan arsip dapat memiliki kontrol berbeda dari format yang dirender browser. Wajibkan fixture berbahaya baru dan fixture normal sebelum rollout. Ini menjaga daftar penerimaan yang berkembang tidak menjadi janji kompatibilitas tanpa review.