Tidak setiap peristiwa keamanan dapat dicegah oleh kode, sehingga aplikasi yang siap produksi juga disiapkan untuk mendeteksi peristiwa yang lolos. Log dan peringatan keamanan adalah pasangan untuk kebutuhan itu, yaitu catatan terstruktur atas peristiwa penting beserta mekanisme yang menaikkan sinyal ketika pola berbahaya terbentuk. OWASP Top 10:2025 menaungi kegagalan di area ini pada kategori A09 Security Logging and Alerting Failures, dan kata Alerting pada judul edisi 2025 menegaskan bahwa catatan tanpa peringatan belum menjadi kontrol. Topik ini membahas peristiwa yang dicatat, data yang dijauhkan dari log, serta mesin aturan sederhana yang menaikkan peringatan dari deretan peristiwa.
Mendeteksi yang tidak dapat dicegah#
Kontrol pencegahan bekerja dengan menolak permintaan, sedangkan kontrol deteksi bekerja dengan membaca jejak yang ditinggalkan peristiwa. Keduanya saling melengkapi, bukan saling menggantikan. Serangan credential stuffing, misalnya, tidak memerlukan kerentanan apa pun pada aplikasi karena permintaannya valid secara teknis, sehingga satu-satunya harapan mendeteksinya adalah pola kegagalan login yang tercatat. Pola serupa berlaku untuk penolakan otorisasi dan perubahan peran, yaitu peristiwa yang sah secara teknis tetapi menandakan bahaya bila muncul dalam jumlah atau urutan yang tidak wajar. Apabila pola itu hanya tersimpan di dalam berkas log, keberhasilan serangan baru disadari pada forensik pasca insiden, jauh setelah akun yang bersangkutan dikuasai.
Posisi OWASP pada edisi 2025 mempertegas titik tersebut. Kategori A09:2025 Security Logging and Alerting Failures mengelompokkan aplikasi yang tidak mencatat peristiwa keamanan, mencatat tanpa melindungi lognya, atau mencatat tetapi tidak pernah menaikkan peringatan. Log yang tidak pernah dibaca hanyalah alat forensik, sedangkan log yang ditopang aturan peringatan menjadi kontrol yang bekerja pada saat serangan berlangsung. Pemantauan sistem pada umumnya dibahas pada jalur Observability, sedangkan topik ini membatasi diri pada peristiwa keamanan aplikasi.
Peristiwa yang dicatat dan yang dijauhkan#
Daftar peristiwanya pendek dan stabil di banyak aplikasi, yaitu peristiwa yang menyentuh identitas, peran, dan akses. Tabel berikut merangkum kelompok yang wajib dicatat beserta level yang lazim.
| Peristiwa | Level lazim | Alasan dicatat |
|---|---|---|
| Login berhasil | INFO | Dasar korelasi dengan peristiwa lain |
| Login gagal | WARNING | Pola berulang menandakan serangan kredensial |
| Perubahan peran | WARNING | Perubahan hak adalah peristiwa berisiko tinggi |
| Penolakan otorisasi | WARNING | Percobaan akses di luar hak pengguna |
| Perubahan konfigurasi penting | WARNING | Konfigurasi baru dapat membuka celah |
Satu baris log keamanan memuat bidang yang tetap, yaitu waktu, aktor, tindakan, objek, hasil, dan sumber permintaan. Format terstruktur dipilih karena aturan peringatan membaca bidang, bukan membaca kalimat. Daftar yang dijauhkan sama pentingnya dengan daftar yang dicatat. Kata sandi, token, dan data pembayaran tidak pernah ditulis ke log karena log dibaca banyak pihak dan hidup lama. Penyamaran nilai yang memang perlu dirujuk sudah diperlihatkan pada topik Paparan Data Sensitif di modul Kegagalan Kriptografi dan Data.
Log keamanan ditempatkan pada penyimpanan terpisah yang aksesnya dibatasi, karena penyerang yang berhasil masuk akan mencoba menghapus jejaknya. Masa simpannya dinyatakan sebagai kebijakan, misalnya 90 hari untuk keperluan investigasi, dan salinan yang lebih tua dihapus secara terjadwal. Retensi yang panjang tanpa kontrol akses hanya menambah tumpukan data sensitif, sedangkan retensi yang terlalu pendek memutus investigasi yang lambat.
Log terstruktur dan mesin aturan#
Skrip berikut memperlihatkan kedua bagian tersebut dalam satu berkas. Bagian pertama mencatat peristiwa melalui modul logging dengan format terstruktur, dan bagian kedua berupa mesin aturan yang menaikkan peringatan bila lima kegagalan login terjadi dalam jendela 60 detik untuk pengguna yang sama atau bila peran seorang pengguna berubah. Waktu pada latihan ini diberikan sebagai parameter, bukan dibaca dari jam, sehingga keluarannya dapat direproduksi. Simpan berkas berikut, lalu jalankan dengan perintah python3 peringatan-keamanan.py.
"""Log keamanan terstruktur dengan mesin aturan ambang sederhana.
Peristiwa dicatat melalui modul logging dengan waktu tetap yang
diberikan sebagai parameter, sehingga keluarannya deterministik.
Mesin aturan menaikkan peringatan bila lima kegagalan login terjadi
dalam jendela 60 detik untuk pengguna yang sama, serta bila peran
seorang pengguna berubah.
"""
import logging
import sys
from datetime import datetime, timedelta
AMBANG_KEGAGALAN = 5
JENDELA = timedelta(seconds=60)
class FormatterWaktuTetap(logging.Formatter):
"""Formatter yang membaca waktu dari atribut peristiwa, bukan dari jam."""
def formatTime(self, record, datefmt=None):
waktu = getattr(record, "waktu", None)
if waktu is not None:
return waktu.strftime("%Y-%m-%d %H:%M:%S")
return super().formatTime(record, datefmt)
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(
FormatterWaktuTetap("%(asctime)s %(levelname)s %(name)s: %(message)s")
)
log_keamanan = logging.getLogger("keamanan")
log_keamanan.addHandler(handler)
log_keamanan.setLevel(logging.INFO)
log_peringatan = logging.getLogger("peringatan")
log_peringatan.addHandler(handler)
log_peringatan.setLevel(logging.WARNING)
class MesinAturan:
"""Menaikkan peringatan dari deretan peristiwa keamanan."""
def __init__(self):
self.kegagalan = {}
def login_gagal(self, pengguna, waktu, sumber):
log_keamanan.warning(
"login_gagal pengguna=%s sumber=%s", pengguna, sumber,
extra={"waktu": waktu},
)
jendela = [
w for w in self.kegagalan.get(pengguna, []) if waktu - w <= JENDELA
]
jendela.append(waktu)
self.kegagalan[pengguna] = jendela
if len(jendela) >= AMBANG_KEGAGALAN:
log_peringatan.critical(
"ambang terlampaui: %d kegagalan login '%s' dalam 60 detik",
len(jendela), pengguna,
extra={"waktu": waktu},
)
def peran_berubah(self, pengguna, peran_lama, peran_baru, waktu):
log_keamanan.info(
"peran_berubah pengguna=%s dari=%s menjadi=%s",
pengguna, peran_lama, peran_baru,
extra={"waktu": waktu},
)
log_peringatan.warning(
"perubahan peran '%s' dari %s menjadi %s perlu ditinjau",
pengguna, peran_lama, peran_baru,
extra={"waktu": waktu},
)
def utama():
mesin = MesinAturan()
print("== deretan peristiwa keamanan ==")
deret_login = [
("budi", "09:00:02", "198.51.100.24"),
("budi", "09:00:09", "198.51.100.24"),
("budi", "09:00:15", "198.51.100.24"),
("budi", "09:00:21", "198.51.100.24"),
("budi", "09:00:28", "198.51.100.24"),
("citra", "09:00:35", "192.0.2.7"),
("citra", "09:00:41", "192.0.2.7"),
]
for pengguna, jam, sumber in deret_login:
jam, menit, detik = (int(bagian) for bagian in jam.split(":"))
waktu = datetime(2026, 11, 9, jam, menit, detik)
mesin.login_gagal(pengguna, waktu, sumber)
mesin.peran_berubah("dewi", "anggota", "admin", datetime(2026, 11, 9, 9, 5, 0))
utama()== deretan peristiwa keamanan ==
2026-11-09 09:00:02 WARNING keamanan: login_gagal pengguna=budi sumber=198.51.100.24
2026-11-09 09:00:09 WARNING keamanan: login_gagal pengguna=budi sumber=198.51.100.24
2026-11-09 09:00:15 WARNING keamanan: login_gagal pengguna=budi sumber=198.51.100.24
2026-11-09 09:00:21 WARNING keamanan: login_gagal pengguna=budi sumber=198.51.100.24
2026-11-09 09:00:28 WARNING keamanan: login_gagal pengguna=budi sumber=198.51.100.24
2026-11-09 09:00:28 CRITICAL peringatan: ambang terlampaui: 5 kegagalan login 'budi' dalam 60 detik
2026-11-09 09:00:35 WARNING keamanan: login_gagal pengguna=citra sumber=192.0.2.7
2026-11-09 09:00:41 WARNING keamanan: login_gagal pengguna=citra sumber=192.0.2.7
2026-11-09 09:05:00 INFO keamanan: peran_berubah pengguna=dewi dari=anggota menjadi=admin
2026-11-09 09:05:00 WARNING peringatan: perubahan peran 'dewi' dari anggota menjadi admin perlu ditinjauTujuh peristiwa login gagal pada keluaran berakhir dengan dua hasil yang berbeda. Lima kegagalan pengguna budi terjadi dalam 26 detik dari alamat sumber yang sama, sehingga kegagalan kelima menaikkan peringatan berlevel CRITICAL. Dua kegagalan pengguna citra tidak menyentuh ambang dan tidak menaikkan apa pun, sehingga gangguan wajar dari pengguna sungguhan tidak membanjiri kanal peringatan. Peristiwa perubahan peran pada akhir keluaran diperlakukan berbeda, yaitu satu peristiwa saja cukup menaikkan peringatan karena perubahan hak jarang terjadi dan dampaknya besar.
Kesalahan umum#
Kesalahan berikut sering ditemukan saat log dan peringatan keamanan disiapkan.
- Mencatat segalanya dengan harapan analisis nanti. Volume yang besar menyembunyikan sinyal yang penting dan menaikkan biaya simpan, sedangkan daftar peristiwa yang terpilih jauh lebih mudah diawasi.
- Menulis data sensitif ke log karena terasa berguna saat debugging. Log dibaca banyak pihak dan hidup lama, sehingga salinan token atau kata sandi di dalamnya menjadi kebocoran tersendiri.
- Menetapkan ambang peringatan tanpa menguji kebisingannya. Ambang yang terlalu rendah melatih operator mengabaikan peringatan, sedangkan ambang yang terlalu tinggi meloloskan serangan yang lambat.
- Menyimpan log di tempat yang sama dengan aplikasi dan dengan hak akses yang sama. Penyerang yang menguasai aplikasi dapat menyunting jejaknya, sehingga log perlu penyimpanan dan akses yang terpisah.
Ringkasan#
- Log keamanan mencatat peristiwa identitas, peran, dan akses dalam format terstruktur, tanpa kata sandi, token, atau data pembayaran.
- Log yang ditopang aturan peringatan menjadi kontrol pada saat serangan berlangsung, sedangkan log yang tidak dibaca hanya membantu forensik setelah insiden.
- Aturan peringatan yang sehat menggunakan ambang dan jendela waktu yang teruji, dan peristiwa berisiko tinggi seperti perubahan peran langsung menaikkan peringatan.
Referensi#
- A09:2025 Security Logging and Alerting Failures — OWASP Top 10 — Kategori OWASP Top 10:2025 yang menaungi kegagalan pencatatan dan peringatan keamanan.
- Logging Cheat Sheet — OWASP — Panduan peristiwa yang dicatat, data yang dijauhkan dari log, dan proteksi log itu sendiri.