MFA dua langkah (TOTP)
Lapisan keamanan kedua setelah password menggunakan kode 6 digit bergulir dari aplikasi autentikator dan kode pemulihan darurat.
Membaca sekitar 2 menit
Lapisan keamanan kedua setelah password menggunakan kode 6 digit bergulir dari aplikasi autentikator dan kode pemulihan darurat.
Rahasia TOTP dienkripsi dengan AES-256-GCM sebelum disimpan ke database, sedangkan kode pemulihan disimpan sebagai hash SHA-256 sekali pakai.
Login dibagi menjadi dua tahap cookie terpisah supaya pengguna belum mendapat sesi penuh sebelum lolos tantangan MFA.
Kenapa password saja tidak cukup untuk akun admin
Di dalam sistem manajemen role, akun Super Admin memegang kunci tertinggi untuk mengubah hak akses seluruh pengguna. Jika password bocor atau ditebak, penyerang bisa mengambil alih seluruh sistem. Karena itu ditambahkan verifikasi dua langkah berbasis waktu (TOTP) yang kompatibel dengan Google Authenticator, Authy, dan 1Password.
Memisahkan sesi tantangan dari sesi penuh
Saat pengguna yang mengaktifkan MFA memasukkan email dan password yang benar, server belum memberikan cookie session. Sebagai gantinya, server menerbitkan cookie sementara mfa_challenge yang hanya berlaku 5 menit dan ber-audience khusus. Sesi penuh baru dibuat setelah kode 6 digit berhasil diverifikasi.
Rahasia MFA di database pun tidak boleh disimpan telanjang; bila isi tabel bocor, penyerang tetap tidak boleh bisa mencetak kode OTP sendiri.
Enkripsi AES-256-GCM dan hash kode pemulihan
Ada dua data sensitif saat MFA diaktifkan: secret TOTP dan daftar kode pemulihan darurat (recovery codes). Keduanya diperlakukan berbeda sesuai sifat penggunaannya:
export async function enableMfa(
userUuid: string,
secret: string,
recoveryCodes: string[]
) {
return prisma.$transaction(async (tx) => {
await tx.userSession.deleteMany({ where: { userUuid } });
return tx.user.update({
where: { uuid: userUuid },
data: {
mfaEnabled: true,
mfaSecret: encryptMfaSecret(secret), // dienkripsi AES-256-GCM
mfaRecoveryCodes: recoveryCodes.map(hashRecoveryCode), // di-hash SHA-256
sessionVersion: { increment: 1 },
},
});
});
}Detail keamanan yang dijaga
- Secret TOTP perlu dibaca kembali oleh server saat memverifikasi kode 6 digit, sehingga disimpan dalam bentuk terenkripsi AES-256-GCM dengan IV acak dan authentication tag.
- Kode pemulihan tidak pernah perlu ditampilkan ulang setelah halaman ditutup, sehingga disimpan satu arah menggunakan hash SHA-256 dan langsung dihapus satu per satu begitu terpakai.
- Percobaan menebak kode 6 digit dibatasi ketat per user dan per alamat IP melalui tabel mfa_attempts agar tidak bisa ditembus dengan brute-force.
Ringkasnya
Menambahkan MFA bukan sekadar mencocokkan angka 6 digit, melainkan merancang alur tiket sementara, mengenkripsi rahasia di penyimpanan, dan menyediakan jalur penyelamatan akun lewat kode pemulihan sekali pakai.