Setiap artikel di blog ini ada gambar headernya. Dan gambar-gambar itu saya upload sendiri lewat panel admin — lewat sistem upload yang juga saya bangun sendiri. Kelihatannya hal yang biasa, tapi proses membangunnya ternyata lebih berlapis dari yang saya kira di awal.
Di artikel ini saya ceritakan proses itu — termasuk beberapa lubang keamanan yang hampir saya lewatkan.
Versi Awal: Terlalu Naif
Versi pertama sistem upload saya waktu itu kurang lebih begini: ambil file dari form, cek ekstensinya, kalau jpg/png/gif ya simpan langsung ke folder /uploads/. Selesai.
Terdengar masuk akal, kan? Ternyata tidak.
Masalah pertama: cek ekstensi berdasarkan nama file itu tidak aman. Seseorang bisa upload file berbahaya dengan nama shell.php.jpg — ekstensinya terakhir .jpg, tapi sebenarnya mengandung kode PHP. Di beberapa konfigurasi server, file itu bisa dieksekusi sebagai PHP.
Masalah kedua: saya tidak memvalidasi bahwa file yang diupload benar-benar gambar. Saya hanya percaya pada ekstensi nama filenya.
Waktu itu saya belum tahu masalah-masalah ini. Saya cukup beruntung tidak ada yang mengeksploitasinya sebelum saya sempat memperbaiki.
Perbaikan: Validasi yang Lebih Ketat
Setelah baca-baca soal keamanan file upload, saya mulai perbaiki satu per satu.
Langkah pertama: validasi MIME type menggunakan finfo_file(), bukan dari ekstensi nama file. Fungsi ini membaca isi file langsung untuk menentukan jenisnya — jauh lebih andal dari sekadar cek ekstensi.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($_FILES['gambar']['tmp_name']);
$allowed = ['image/jpeg', 'image/png', 'image/webp'];
if (!in_array($mime, $allowed)) {
// tolak
}
Langkah kedua: rename file yang diupload dengan nama yang di-generate secara acak — bukan pakai nama file aslinya. Nama file asli dari pengguna tidak bisa dipercaya; bisa mengandung karakter aneh, spasi, atau bahkan path traversal seperti ../../config.php.
Saya pakai kombinasi timestamp dan random string untuk nama file baru:
$ext = 'jpg'; // atau ambil dari MIME type
$nama_baru = uniqid() . bin2hex(random_bytes(4)) . '.' . $ext;
Langkah ketiga: simpan file di folder yang tidak bisa diakses langsung via browser, atau setidaknya pastikan folder uploads tidak mengizinkan eksekusi script PHP. Ini dikonfigurasi di level server/htaccess.
Resize Otomatis — Fitur yang Jadi Kebutuhan
Masalah berikutnya yang muncul bukan soal keamanan, tapi soal performa. Beberapa kali saya upload gambar dari kamera HP yang ukurannya bisa sampai 4-5 MB. Kalau langsung disimpan dan ditampilkan begitu saja, halaman jadi lambat karena harus load gambar sebesar itu.
Solusinya: resize otomatis saat upload. PHP punya ekstensi GD yang bisa manipulasi gambar. Saya buat fungsi sederhana yang resize gambar ke lebar maksimal 1200px sambil menjaga aspect ratio-nya, lalu simpan dengan kompresi JPEG sekitar 85% — cukup untuk jaga kualitas tapi ukuran file jauh lebih kecil.
Hasilnya gambar yang tadinya 4 MB bisa jadi sekitar 200-400 KB. Perbedaan loading yang sangat signifikan terutama untuk pengunjung dengan koneksi lambat.
Satu Hal yang Masih Perlu Diperbaiki
Sampai hari ini, sistem upload saya belum punya fitur hapus gambar yang tidak terpakai secara otomatis. Jadi kalau saya ganti gambar header sebuah artikel, gambar lama masih tersimpan di server dan memenuhi storage perlahan-lahan.
Bukan masalah besar sekarang, tapi kalau dibiarkan lama-lama juga tidak bagus. Ini ada di daftar yang ingin saya perbaiki — bersama dengan beberapa hal lain yang sudah ada di antrian.
Membangun sistem upload sendiri memang lebih rumit dari kelihatannya. Tapi dari proses itu saya belajar banyak soal keamanan file upload dan manipulasi gambar di PHP — hal yang tidak mungkin saya pelajari kalau saya cukup pakai plugin siap pakai.
Pernah punya pengalaman bikin atau debug sistem upload? Lubang keamanan apa yang pernah kamu temukan? Cerita di komentar ya.
Belum ada komentar. Jadilah yang pertama menulis.
Tulis Komentar