Formulir unggah yang menerima gambar adalah jalan untuk menaruh berkas di server Anda. Validasi mengurangi apa yang lolos; ia tidak membuat direktorinya aman. Yang membuatnya aman adalah server webnya menolak MENJALANKAN apa pun di sana, berkasnya ternyata apa pun.
Nginx
location ^~ /uploads/ {
location ~ \.php$ { deny all; }
add_header X-Content-Type-Options nosniff;
}
Apache dan LiteSpeed
# /var/www/site/uploads/.htaccess
php_flag engine off
<FilesMatch "\.(php|phar|phtml|cgi|pl)$">
Require all denied
</FilesMatch>
Options -ExecCGI -Indexes
Validasi juga, dengan benar
- Periksa jenisnya yang sungguhan, bukan nama yang dikirim sebuah peramban:
finfo_file()di PHP. - Ganti nama tiap unggahan dengan nama yang Anda hasilkan sendiri. Jangan pernah mempertahankan nama berkas dari pengunjungnya.
- Tolak ekstensi ganda - berkas bernama invoice.php.jpg bukanlah kebetulan.
- Kodekan ulang gambarnya. Melewatkan sebuah foto melalui pustaka gambar mencabut apa pun yang tersembunyi di dalamnya.
$f = new finfo(FILEINFO_MIME_TYPE);
$type = $f->file($tmp);
if (!in_array($type, ['image/jpeg','image/png','image/webp'], true)) {
// reject
}
$name = bin2hex(random_bytes(16)) . '.webp';
Lebih baik lagi, simpan di tempat yang tak terjangkau web
Simpan unggahannya di luar akar dokumen dan sajikan lewat skrip yang memeriksa siapa yang meminta. Lebih lambat satu milidetik, dan sesudah itu tak ada alamat mana pun yang bisa menjalankan apa pun.
Ujilah. Taruh sendiri sebuah berkas PHP yang tak berbahaya di direktori unggahan lalu mintalah ia: Anda harus mendapat 403 atau teks sumbernya, jangan pernah keluarannya. Ini makan semenit dan itulah satu-satunya bukti.