Rekomendasi Keamanan Upload Dir pada Aplikasi Web

Ilustrasi folder terkunci dan file PHP yang diblokir
Kunci script inti, jinakkan folder upload.

Tidak sedikit serangan yang terjadi terhadap website yang mengincar File Upload Vulnerabilities, khususnya website yang berbasis engine populer seperti WordPress. Polanya hampir selalu sama: penyerang menemukan celah di form upload, plugin, atau theme, lalu mengunggah web shell berekstensi .php. Setelah web shell bisa dieksekusi, penyerang bebas menyisipkan malware ke file inti aplikasi.

Ilustrasi folder terkunci dan file PHP yang diblokir

Di tulisan Mitigasi Malware di Web Server saya sempat menyinggung chattr sebagai bonus. Kali ini kita bahas lebih lengkap, ditambah satu lapisan lagi: memastikan folder upload tidak bisa mengeksekusi PHP. Dua langkah ini saling melengkapi. Yang pertama menjaga file inti agar tidak bisa diubah, yang kedua membuat file yang berhasil diunggah tidak ada gunanya.

A Glance of chattr

chattr (change attribute) adalah perintah Linux untuk mengatur atribut file di level filesystem. Atribut ini berbeda dengan permission biasa (chmod/chown). Atribut yang paling berguna untuk kita adalah i atau immutable.

File atau direktori yang diberi atribut +i tidak bisa diubah, dihapus, diganti nama, atau ditimpa. Ini berlaku untuk semua user, termasuk root, sampai atributnya dicabut kembali. Jadi walaupun penyerang berhasil menjalankan kode sebagai user web server, file inti aplikasi tetap aman.

Beberapa hal yang perlu diketahui:

  • Hanya root (atau proses dengan capability CAP_LINUX_IMMUTABLE) yang bisa memasang dan mencabut atribut ini. User hosting biasa tidak bisa.
  • Didukung filesystem umum seperti ext4, XFS, dan Btrfs. Tidak berlaku di NFS dan sebagian filesystem jaringan.
  • Untuk melihat atribut yang terpasang, gunakan lsattr.

Utilize chattr on Dir App

Prinsipnya sederhana: kunci semua direktori yang berisi script, biarkan hanya direktori upload yang bisa ditulis. Untuk WordPress, contohnya seperti ini:

cd /var/www/situs
chattr -R +i wp-admin wp-includes
chattr -R +i wp-content/themes wp-content/plugins
chattr +i index.php wp-config.php .htaccess

Periksa hasilnya dengan lsattr. Huruf i menandakan atribut immutable sudah aktif.

lsattr -d wp-includes index.php wp-content/uploads

Terminal chattr dan lsattr menolak perubahan file

Setiap percobaan mengubah atau menghapus file yang dikunci akan berakhir dengan pesan Operation not permitted, bahkan jika dijalankan sebagai root.

Disable chattr saat update

Konsekuensinya, update core, plugin, dan theme dari dashboard akan gagal selama direktori terkunci. Ini memang yang kita inginkan, karena update pun bisa menjadi jalur masuk backdoor. Update dilakukan secara sadar: buka kunci, update, periksa, lalu kunci kembali.

Supaya tidak repot mengetik ulang, saya memakai script kecil /root/wp-lock.sh:

#!/bin/bash
# Pemakaian: wp-lock.sh lock|unlock /var/www/situs

MODE=$1; DIR=$2
[ "$MODE" = "lock" ] && FLAG="+i" || FLAG="-i"

cd "$DIR" || exit 1
chattr -R $FLAG wp-admin wp-includes wp-content/themes wp-content/plugins
chattr $FLAG index.php wp-config.php .htaccess wp-content/uploads/.htaccess
echo "$DIR: $MODE"

Alur update menjadi:

/root/wp-lock.sh unlock /var/www/situs
wp core update && wp plugin update --all
wp core verify-checksums && wp plugin verify-checksums --all
/root/wp-lock.sh lock /var/www/situs

Jangan kunci direktori wp-content/uploads, wp-content/cache, atau direktori lain yang memang harus ditulis aplikasi. Kalau dikunci, upload gambar dan plugin cache akan berhenti bekerja.

Additional Restriction

Direktori upload harus tetap bisa ditulis, dan di sinilah web shell biasanya diletakkan. Karena tidak bisa dikunci, kita pastikan saja tidak ada file PHP yang bisa dieksekusi dari sana. Folder upload hanya berisi gambar dan dokumen, jadi tidak ada alasan sah untuk menjalankan PHP di dalamnya.

Struktur direktori WordPress dengan atribut immutable dan folder upload

Apache

Buat file wp-content/uploads/.htaccess:

<FilesMatch "\.(php|php[0-9]|phtml|phar)$">
    Require all denied
</FilesMatch>

Pastikan AllowOverride di virtual host mengizinkan .htaccess. Lalu kunci file .htaccess ini dengan chattr +i, karena penyerang yang paham biasanya akan menimpa atau menghapus .htaccess terlebih dahulu.

chattr +i wp-content/uploads/.htaccess

Banyak tutorial menyarankan php_flag engine off. Cara ini hanya berlaku jika PHP berjalan sebagai mod_php. Di server yang memakai PHP-FPM, baris tersebut tidak berpengaruh, bahkan bisa memicu error 500. FilesMatch lebih aman karena bekerja di level Apache.

Nginx

Nginx tidak membaca .htaccess, jadi aturannya ditulis di konfigurasi server block. Letakkan sebelum blok location ~ \.php$, karena Nginx memakai regex location pertama yang cocok.

location ~* ^/wp-content/uploads/.*\.(php|php[0-9]|phtml|phar)$ {
    deny all;
}

Uji dengan membuat file PHP dummy di folder upload lalu mengaksesnya dari browser. Hasil yang benar adalah 403 Forbidden, bukan halaman kosong dan bukan output PHP.

echo '<?php echo "jalan";' > wp-content/uploads/test.php
curl -I https://situs-anda.ac.id/wp-content/uploads/test.php
rm wp-content/uploads/test.php

Bagaimana dengan OJS?

Prinsipnya sama. Pastikan files_dir di config.inc.php berada di luar public_html, sehingga file naskah yang diunggah penulis tidak bisa diakses langsung lewat URL. Direktori public/ yang memang harus bisa diakses publik diberi aturan blokir PHP seperti di atas. Untuk direktori script OJS seperti lib, classes, dan plugins, gunakan chattr +i dengan alur update yang sama.

Penutup

Tidak ada satu cara yang membuat website kebal. Tetapi dua langkah ini mengubah situasi secara signifikan: celah upload yang dulu berarti server diambil alih, sekarang paling jauh hanya menghasilkan file sampah di folder upload. Tetap rutin periksa folder tersebut, misalnya dengan:

find wp-content/uploads -type f -name "*.php"

Kalau perintah di atas mengembalikan hasil, saatnya mulai berburu malware.

Comments

No comments yet. Why don’t you start the discussion?

Tinggalkan Balasan