TOTP: Autentikator 2FA โ Cara Kerja dan Membangunnya Sendiri
Kenapa kode 6 digit di Google Authenticator bisa dipercaya, dan bagaimana Anda bisa membangun sistem yang sama tanpa biaya sepeser pun.
๐งช Coba Demo TOTP Live โ โ enroll, scan QR, dan verifikasi langsung di browser. Gratis, tanpa registrasi.
Apa Itu TOTP?
TOTP (Time-based One-Time Password) adalah standar terbuka (RFC 6238) untuk menghasilkan kode sekali pakai yang berubah setiap 30 detik. Inilah yang dipakai Google Authenticator, Authy, dan aplikasi 2FA lainnya.
Contoh nyata di kehidupan sehari-hari:
- Login ke Google/GitHub โ muncul permintaan "masukkan kode 6 digit"
- Kode itu diambil dari aplikasi auth di HP Anda
- Kode berikutnya akan berbeda 30 detik kemudian
Pertanyaannya: dari mana asal kode itu? Ternyata jawabannya sangat sederhana โ matematika yang bisa dijalankan siapa pun.
Kenapa 2FA Lebih Aman dari Password Saja?
Password bisa dicuri: phishing, database bocor, keylogger. Tapi untuk menipu 2FA, penyerang harus mendapatkan akses fisik ke HP Anda โ dan itu jauh lebih sulit.
TOTP bekerja dengan prinsip:
Secret + Jam = Kode
- Secret: kombinasi huruf yang hanya diketahui server Anda dan HP pengguna
- Jam: waktu sekarang, dibagi 30 detik (counter)
- Kode: hasil perhitungan HMAC dari keduanya
Karena kode dihitung offline di HP dari secret + jam, tidak ada API berbayar, tidak ada server pihak ketiga, dan tidak ada koneksi internet yang dibutuhkan.
Cara Kerja di Balik Layar
Alur TOTP secara teknis:
1. Saat enroll: server menghasilkan secret acak โ dikirim ke HP via QR code
2. Setiap 30 detik:
counter = floor(timestamp / 30)
hash = HMAC-SHA1(secret, counter) โ satu-satunya operasi matematika
kode = 6 digit pertama dari hash โ angka yang Anda lihat
3. Saat verifikasi: server menghitung kode yang sama untuk saat ini
โ cocok? Berarti yang mengetik memang pemilik HP yang sah
HMAC-SHA1 adalah fungsi hash bawaan PHP โ tidak perlu instalasi apapun.
Membangun Autentikator TOTP Sendiri
Kabar baiknya: library TOTP bisa ditulis dalam ~150 baris PHP murni, tanpa composer package, tanpa biaya. Ini prinsip yang saya pakai saat membangunnya untuk sistem SIMRS (verifikasi CPPT dokter):
1. Library Inti (RFC 6238)
<?php
class Totplib {
private $period = 30; // interval 30 detik
private $digits = 6; // panjang kode
private $algo = 'sha1'; // algoritma HMAC
public function generate_code($secret, $time = null) {
$time = $time ?? time();
$counter = intdiv($time, $this->period);
// Base32 decode secret (format standar QR TOTP)
$secret_bin = $this->base32_decode($secret);
// HMAC-SHA1 dari counter
$hash = hash_hmac($this->algo, pack('N*', 0) . pack('N*', $counter), $secret_bin, true);
// Dynamic truncation (RFC 4226 bagian 5.3)
$offset = ord($hash[19]) & 0x0F;
$code = (ord($hash[$offset]) & 0x7F) << 24
| (ord($hash[$offset+1]) & 0xFF) << 16
| (ord($hash[$offset+2]) & 0xFF) << 8
| (ord($hash[$offset+3]) & 0xFF);
return str_pad($code % 1000000, $this->digits, '0', STR_PAD_LEFT);
}
public function verify_code($secret, $code, $window = 1) {
// Cek kode sekarang + window ยฑ1 (toleransi beda jam ยฑ30 detik)
for ($i = -$window; $i <= $window; $i++) {
$time = time() + ($i * $this->period);
if (hash_equals($this->generate_code($secret, $time), $code)) {
return true;
}
}
return false;
}
private function base32_decode($s) { /* ... standar RFC 4648 ... */ }
}
2. Enroll: Secret + QR Code
// Generate secret acak 20 byte
$secret = strtoupper(bin2hex(random_bytes(10)));
// Format: "JBSWY3DPEHPK3PXP" (base32, dipindai QR oleh Google Auth)
// URL QR (standar otpauth)
$qr_url = "otpauth://totp/" . urlencode("SIMRS Anda:" . $nik)
. "?secret=" . $secret
. "&issuer=" . urlencode("SIMRS Anda");
// Render QR dengan library qrcode โ pengguna scan โ selesai
3. Anti-Replay: Kenapa Kode Tidak Bisa Dipakai Dua Kali
Ini bagian yang sering dilupakan. Tanpa proteksi ini, penyerang yang menangkap kode (misal dari keyboard logger) bisa memakainya lagi. Solusinya: simpan counter terakhir yang berhasil:
// Simpan setelah verifikasi sukses
if ($row['last_counter'] !== null && $counter <= $row['last_counter']) {
return false; // kode sudah dipakai sebelumnya โ tolak!
}
Sederhana tapi efektif โ setiap kode hanya berlaku sekali.
Checklist Keamanan yang Perlu Diperhatikan
Kalau membangun sendiri, jangan lupa:
hash_equals()untuk membandingkan kode โ bukan==(mencegah timing attack)- Secret jangan pernah dikirim via URL yang bisa ter-log โ hanya lewat QR/HTTPS
- Anti-replay wajib โ kode boleh dipakai sekali saja
- Secret hanya milik pemiliknya โ jangan tampilkan di halaman admin umum
- Hapus sekali bersih โ kalau user ingin daftar ulang, generate secret BARU (bukan reuse yang lama)
Perbandingan: Bangun Sendiri vs Layanan Berbayar
| Aspek | Bangun Sendiri | Layanan Berbayar |
|---|---|---|
| Biaya | Rp 0 โ library PHP murni | Per-signature / langganan bulanan |
| Ketergantungan | Nol โ server sendiri | Tergantung vendor |
| Internet | 100% offline | Butuh API call |
| Kustomisasi | Penuh โ alur sesuai kebutuhan | Terbatas |
| Standar | RFC 6238 (sama) | RFC 6238 (sama) |
Untuk kebutuhan akuntabilitas internal (misal: verifikasi siapa yang menyetujui catatan medis), solusi sendiri sudah lebih dari cukup โ dan jujur, gratis selamanya.
Kesimpulan
TOTP bukan teknologi ajaib โ hanya HMAC + jam. Yang membuatnya aman adalah secret yang rahasia, bukan kompleksitas algoritmanya. Karena itu:
- โ Bangun sendiri: mudah, gratis, sesuai standar
- โ Google Authenticator: aplikasi gratis, kompatibel
- โ 100% offline, tanpa langganan
- โ Tidak perlu layanan berbayar untuk akuntabilitas internal
Satu-satunya "biaya" adalah waktu Anda: ~1 menit per orang untuk enroll sekali di awal. Setelah itu, proteksi 2FA aktif selamanya.
Artikel ini ditulis berdasarkan pengalaman nyata membangun sistem TOTP sendiri untuk verifikasi CPPT di SIMRS menggunakan PHP murni (RFC 6238) โ gratis, offline, tanpa pihak ketiga.
๐งช Ingin langsung mencoba? Buka Demo TOTP Live โ enroll, pindai QR, aktifasi, dan uji verifikasi anti-replay langsung di browser Anda. Semua berjalan lokal di server, 100% offline.