Lewati ke isi

Keamanan/Cyber Security

Membaca Log Server untuk Deteksi Serangan

Belajar membaca log akses Nginx dan log login SSH untuk mengenali scanning, brute force, dan injeksi, lengkap dengan perintah grep dan awk siap pakai.

Terbit 6 menit baca

Jawaban singkat

Serangan hampir selalu meninggalkan jejak di log. Di log akses Nginx, cari lonjakan 404 dari satu IP, path sensitif seperti /.env atau /wp-login.php, dan pola injeksi di URL. Di log autentikasi, cari Failed password dan Invalid user. Setelah itu, kumpulkan log ke Grafana Loki agar mudah dipantau.

Daftar isi
  1. Langkah 1: Kenali di mana log berada
  2. Langkah 2: Cari IP yang paling ramai
  3. Langkah 3: Kenali tanda pemindaian
  4. Langkah 4: Deteksi brute force login
  5. Langkah 5: Tangkap percobaan injeksi
  6. Langkah 6: Kumpulkan log ke Grafana dan Loki
  7. Ringkasan pola dan perintah
  8. Pertanyaan yang sering diajukan

Kapan terakhir kali kamu benar-benar membuka log servermu? Bagi banyak pemilik website, jawabannya "waktu ada masalah". Padahal log adalah tempat pertama serangan terlihat, sering berhari-hari sebelum website terasa aneh.

Untuk mulai, kamu tidak perlu alat mahal. Dengan grep, awk, dan sedikit kebiasaan, kamu sudah bisa mengenali pemindaian, tebak password, dan percobaan injeksi. Panduan ini memakai Nginx dan SSH di Linux, tapi polanya mirip untuk web server lain.

Langkah 1: Kenali di mana log berada

Di sebagian besar distribusi Linux, log akses dan error Nginx ada di /var/log/nginx/access.log dan /var/log/nginx/error.log. Log login SSH ada di /var/log/auth.log (Debian, Ubuntu) atau /var/log/secure (keluarga RHEL seperti AlmaLinux dan Rocky). Di sistem yang hanya memakai journald, pakai journalctl -u ssh atau journalctl -u sshd.

Format bawaan log akses Nginx disebut combined. Satu baris berisi IP pengunjung, waktu, baris permintaan (metode, path, protokol), kode status, ukuran respons, referer, dan user agent. Kalau memakai pemisah spasi di awk, IP ada di kolom $1, path di $7, dan status di $9. Ini berlaku untuk format combined standar. Kalau kamu memakai log_format sendiri, sesuaikan nomornya.

Langkah 2: Cari IP yang paling ramai

Serangan otomatis biasanya datang dari sedikit IP dengan volume besar. Mulailah dengan melihat siapa yang paling sering mengetuk pintu.

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

IP dengan ribuan permintaan belum tentu jahat. Bisa jadi itu crawler mesin pencari, monitor uptime, atau kantor sendiri di balik satu IP. Cek user agent-nya, lalu bandingkan dengan pola di langkah berikutnya.

Langkah 3: Kenali tanda pemindaian

Pemindai mencoba banyak path yang tidak ada, jadi jejaknya berupa banyak 404 dari satu IP dalam waktu singkat.

awk '$9 == 404 {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Cari juga permintaan ke path sensitif yang biasa diincar:

grep -E '/\.env|/\.git/|wp-config|phpmyadmin|/vendor/phpunit|\.bak$|\.sql' /var/log/nginx/access.log | tail -50

Kalau websitemu bukan WordPress, permintaan ke /wp-login.php atau /xmlrpc.php hampir pasti dari bot pemindai. Yang perlu dicemaskan bukan permintaannya, tapi respons 200 untuk path seperti /.env atau /.git/config. Itu berarti file rahasia benar-benar bisa diunduh.

grep -E '/\.env|/\.git/' /var/log/nginx/access.log | awk '$9 == 200'

Langkah 4: Deteksi brute force login

Untuk SSH, dua pola paling umum adalah Failed password (password salah untuk user yang ada) dan Invalid user (nama user tidak ada di server).

grep 'Failed password' /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head
grep 'Invalid user' /var/log/auth.log | awk '{print $8}' | sort | uniq -c | sort -rn | head

Perintah kedua menunjukkan nama user yang paling sering dicoba, biasanya admin, root, test, atau nama aplikasi umum. Posisi kolom bisa berbeda antar versi OpenSSH dan format syslog, jadi cek satu baris contoh dulu sebelum mempercayai hasilnya.

Untuk login website, cari banyak POST ke halaman login dari satu IP:

awk '$6 ~ /POST/ && $7 ~ /login/ {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Kalau polanya terlihat, langkah lanjutnya adalah mematikan login SSH dengan password (lihat SSH key vs password), memasang pembatasan laju, dan mengaktifkan 2FA di panel admin.

Langkah 5: Tangkap percobaan injeksi

Percobaan SQL injection, path traversal, dan XSS sering terlihat langsung di URL. Karakter khusus biasanya ter-encode, jadi cari bentuk asli dan bentuk encode-nya.

grep -iE "union(\+|%20)select|%27|'--|\.\./|%2e%2e|<script|%3cscript|etc/passwd" /var/log/nginx/access.log | tail -50

Hasil grep ini pasti mengandung positif palsu, misalnya kata pencarian pelanggan yang kebetulan mengandung tanda kutip. Fokuskan perhatian pada IP yang mengirim banyak variasi pola dalam waktu singkat, dan periksa kode statusnya. Respons 500 berulang pada permintaan aneh layak dicek lebih jauh, karena bisa menandakan aplikasi tidak menangani input dengan baik.

Ingat, permintaan dengan metode POST tidak mencatat isi body di log akses bawaan. Injeksi lewat form tidak akan terlihat di sini. Untuk itu kamu butuh log aplikasi atau WAF. Konsepnya dibahas di apa itu WAF.

Langkah 6: Kumpulkan log ke Grafana dan Loki

grep cocok untuk investigasi, tapi melelahkan bila server lebih dari satu. Di titik ini, log perlu dikumpulkan ke satu tempat. Salah satu kombinasi open source yang populer adalah Grafana Loki untuk menyimpan log dan Grafana untuk dasbor serta peringatan.

Pengirim log yang dulu umum dipakai, Promtail, sudah berstatus end of life sejak 2 Maret 2026 menurut dokumentasi Grafana. Untuk instalasi baru, gunakan Grafana Alloy, yang juga menyediakan alat konversi dari konfigurasi Promtail.

Setelah log masuk, kueri LogQL sederhana sudah sangat membantu. Contoh, menghitung 404 per menit:

sum(count_over_time({job="nginx"} |= " 404 " [1m]))

Dari sini kamu bisa membuat panel "permintaan per status", "IP teratas", dan "percobaan login gagal", lalu memasang peringatan bila angkanya melonjak. Untuk pemantauan uptime yang melengkapi dasbor log, lihat memantau server dengan Uptime Kuma dan Grafana.

Ringkasan pola dan perintah

Yang dicariSumber logTanda yang perlu dicurigai
Pemindaianaccess.log NginxBanyak 404 dari satu IP, path seperti /.env, /.git, phpmyadmin
File bocoraccess.log NginxStatus 200 untuk path sensitif
Brute force SSHauth.log atau secureFailed password dan Invalid user berulang dari satu IP
Brute force webaccess.log NginxBanyak POST ke halaman login dari satu IP
Injeksiaccess.log Nginxunion select, ../, &lt;script di URL, diikuti 500

Pertanyaan yang sering diajukan

Seberapa sering log perlu dibaca?

Untuk server kecil, cek singkat mingguan sudah jauh lebih baik daripada tidak sama sekali. Begitu log terkumpul di Grafana dan Loki, biarkan peringatan otomatis yang berjaga, dan kamu cukup meninjau dasbornya secara berkala.

Apakah IP penyerang sebaiknya langsung diblokir?

Boleh untuk pola yang jelas, tapi jangan jadikan satu-satunya pertahanan karena IP mudah berganti. Alat seperti fail2ban memblokir otomatis berdasarkan log, sementara perbaikan celahnya tetap yang utama.

Log memenuhi disk, apa yang harus dilakukan?

Pastikan logrotate aktif agar log dipotong dan dikompres berkala. Simpan salinan jangka panjang di tempat terpisah bila dibutuhkan untuk investigasi.

Bagaimana kalau websiteku di balik CDN?

IP di log bisa berupa IP CDN, bukan pengunjung asli. Atur modul real IP di Nginx sesuai dokumentasi CDN-mu agar IP asli tercatat.

Sebelum menutup terminal, pastikan hal-hal ini sudah beres:

  • Lokasi log akses, error, dan login sudah kamu ketahui.
  • Perintah IP teratas dan 404 per IP sudah dicoba sekali.
  • Tidak ada respons 200 untuk /.env atau /.git.
  • Login SSH dengan password sudah dimatikan atau dibatasi.
  • Logrotate aktif, dan rencana mengumpulkan log ke Loki sudah ada.

Sumber & referensi

Baca juga