Fitur upload file sering kali menjadi target empuk bagi hacker. Sebuah file gambar, jika tidak dicek dengan benar, bisa saja berisi kode PHP berbahaya yang dapat mengambil alih server. Contoh kasus nyata: Banyak situs diretas hanya karena folder upload-nya bisa mengeksekusi file .php yang disamarkan sebagai gambar. Dalam artikel ini, kita akan membahas Keamanan File Upload di PHP:
-
Validasi ekstensi & ukuran file
-
Filter MIME type asli file
-
Proteksi folder upload agar tidak dieksekusi sebagai script
-
Contoh implementasi upload aman di PHP
1. Risiko Upload Tanpa Validasi
Contoh upload yang tidak aman:
<?php move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']); ?>
Jika pengguna mengupload file bernama:
shell.php
dan server kamu tidak memiliki proteksi, maka file itu bisa diakses lewat:
https://example.com/uploads/shell.php
Artinya, hacker bisa menjalankan perintah di server kamu langsung dari browser.
2. Validasi Ekstensi File
Langkah pertama adalah membatasi jenis file yang boleh diupload.
<?php
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
$file_name = $_FILES['file']['name'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_ext)) {
die("Ekstensi file tidak diizinkan!");
}
?>
Tips:
-
Gunakan
pathinfo()untuk mengambil ekstensi file. -
Hindari
explode()karena bisa dimanipulasi dengan nama file sepertifile.php.jpg.
3. Validasi MIME Type Asli File
Ekstensi saja tidak cukup, karena hacker bisa mengganti nama file shell.php menjadi shell.jpg.
Gunakan fungsi finfo_file() untuk membaca MIME type asli dari file.
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);
$allowed_mime = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($mime, $allowed_mime)) {
die("Tipe file tidak valid!");
}
?>
Penjelasan:
-
finfo_file()membaca isi file, bukan hanya nama. -
Ini mencegah file PHP yang disamarkan menjadi gambar.
4. Batasi Ukuran File Upload
Batasi ukuran maksimal file untuk mencegah DoS attack (pengiriman file besar tanpa batas).
<?php
$max_size = 2 * 1024 * 1024; // 2 MB
if ($_FILES['file']['size'] > $max_size) {
die("Ukuran file terlalu besar. Maksimal 2MB!");
}
?>
Kamu juga bisa atur di php.ini:
upload_max_filesize = 2M post_max_size = 3M
5. Ganti Nama File dengan Aman
Hindari menyimpan file dengan nama asli pengguna. Gunakan nama acak agar tidak mudah ditebak.
<?php
$new_name = uniqid('img_', true) . '.' . $file_ext;
$target = 'uploads/' . $new_name;
?>
Keuntungan:
-
Tidak bentrok antar file
-
Mencegah orang menebak nama file upload
6. Proteksi Folder Upload
Jangan pernah biarkan folder uploads/ menjalankan file PHP. Ada dua cara yang wajib kamu lakukan:
a. Buat file .htaccess di dalam folder uploads/:
# Mencegah eksekusi file PHP
<FilesMatch "\.php$">
Deny from all
</FilesMatch>
# Izinkan hanya file gambar
<FilesMatch "\.(jpg|jpeg|png|gif)$">
Allow from all
</FilesMatch>
b. Alternatif: Simpan file di luar public_html
Misalnya:
/project_root/uploads_private/
Lalu akses file hanya melalui script PHP yang aman.
7. Contoh Lengkap Upload Aman di PHP
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$allowed_ext = ['jpg', 'jpeg', 'png', 'gif'];
$allowed_mime = ['image/jpeg', 'image/png', 'image/gif'];
$max_size = 2 * 1024 * 1024; // 2MB
$file = $_FILES['file'];
$file_name = $file['name'];
$file_tmp = $file['tmp_name'];
$file_size = $file['size'];
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
// Validasi ekstensi
if (!in_array($file_ext, $allowed_ext)) {
die("Ekstensi file tidak diizinkan!");
}
// Validasi MIME
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file_tmp);
finfo_close($finfo);
if (!in_array($mime, $allowed_mime)) {
die("Tipe file tidak valid!");
}
// Validasi ukuran
if ($file_size > $max_size) {
die("Ukuran file terlalu besar. Maksimal 2MB!");
}
// Rename dan upload
$new_name = uniqid('img_', true) . '.' . $file_ext;
$target = 'uploads/' . $new_name;
if (move_uploaded_file($file_tmp, $target)) {
echo "<div class='alert alert-success'>Upload berhasil: $new_name</div>";
} else {
echo "<div class='alert alert-danger'>Gagal mengupload file.</div>";
}
}
?>
<form method="post" enctype="multipart/form-data">
<label>Pilih File Gambar:</label>
<input type="file" name="file" required>
<button type="submit">Upload</button>
</form>
8. Tips Tambahan untuk Keamanan Upload
| Risiko | Solusi |
|---|---|
| File PHP tersimpan di folder upload | Gunakan .htaccess atau folder private |
| File terlalu besar | Batasi ukuran di PHP dan server |
| Nama file berbahaya | Gunakan uniqid() atau hash |
| MIME palsu | Validasi dengan finfo_file() |
| Folder terbuka untuk umum | Tambahkan index.html kosong di folder upload |
Kesimpulan
Mengizinkan pengguna mengupload file bisa sangat berbahaya jika tidak diatur dengan benar.
Dengan langkah-langkah berikut:
-
Validasi ekstensi
-
Cek MIME type asli
-
Batasi ukuran file
-
Lindungi folder upload
maka sistem kamu akan jauh lebih aman dari serangan yang umum terjadi di aplikasi PHP.
Keamanan bukan hanya tentang mencegah hacker, tapi juga tentang melindungi data dan kepercayaan pengguna.