Implementasi HMAC di Go untuk Otentikasi Pesan
Saat aplikasi saya berhubungan dengan data yang sensitif, memastikan integritas dan keaslian pesan jadi hal penting. Bayangin kalau ada pihak ketiga yang coba mengutak-atik pesan di perjalanan, atau bahkan melakukan replay attack dengan mengirim ulang pesan lama. Nah, salah satu cara sederhana tapi kuat untuk mengatasi ini adalah dengan HMAC (Hash-based Message Authentication Code).
Di postingan ini, kita akan lihat bagaimana cara bikin dan memverifikasi HMAC di Go menggunakan algoritma hash SHA-512, lengkap dengan penggunaan nonce dan timestamp supaya lebih aman.
Apa itu HMAC?
HMAC pada dasarnya menggabungkan fungsi hash dengan kunci rahasia. Tujuannya: memastikan pesan memang datang dari pihak yang sah dan tidak diubah.
Prosesnya kira-kira begini:
- Generate HMAC – pesan, kunci rahasia, plus info tambahan (seperti nonce dan timestamp) diproses jadi sebuah kode unik.
- Verifikasi HMAC – penerima melakukan hal yang sama, lalu membandingkan hasilnya dengan HMAC yang dikirim. Kalau sama, berarti pesan valid.
Contoh Implementasi di Go
package main
import (
"crypto/hmac"
"crypto/sha512"
"encoding/hex"
"fmt"
"time"
)
func main() {
message := "this is a sample message"
key := "secret"
nonce := "random"
timestamp := time.Now().Unix()
allowedTimestampDiff := int64(60) // 60 detik
usedNonces := make(map[string]bool)
// Generate HMAC
generatedHMAC := generateMAC(message, key, nonce, timestamp)
fmt.Println("Generated HMAC:", generatedHMAC)
// Verifikasi HMAC asli
isValid := verifyHMAC(message, key, generatedHMAC, nonce, timestamp, allowedTimestampDiff, usedNonces)
fmt.Println("Validasi HMAC:", isValid)
// Verifikasi dengan HMAC palsu
fake := verifyHMAC(message, key, "incorrect", nonce, timestamp, allowedTimestampDiff, usedNonces)
fmt.Println("Validasi HMAC palsu:", fake)
// Coba kirim ulang dengan nonce yang sama
replay := verifyHMAC(message, key, generatedHMAC, nonce, timestamp, allowedTimestampDiff, usedNonces)
fmt.Println("Validasi dengan nonce sama:", replay)
}
func generateMAC(message, key, nonce string, timestamp int64) string {
data := fmt.Sprintf("%s:%d:%s", message, timestamp, nonce)
h := hmac.New(sha512.New, []byte(key))
h.Write([]byte(data))
return hex.EncodeToString(h.Sum(nil))
}
func verifyHMAC(message, key, receivedHMAC, nonce string, timestamp int64, allowedTimestampDiff int64, usedNonces map[string]bool) bool {
expectedHMAC := generateMAC(message, key, nonce, timestamp)
// Bandingkan HMAC
expectedBytes, _ := hex.DecodeString(expectedHMAC)
receivedBytes, _ := hex.DecodeString(receivedHMAC)
if !hmac.Equal(expectedBytes, receivedBytes) {
return false
}
// Cek timestamp
now := time.Now().Unix()
if timestamp < now-allowedTimestampDiff || timestamp > now+allowedTimestampDiff {
return false
}
// Cek nonce
if usedNonces[nonce] {
return false
}
usedNonces[nonce] = true
return true
}
Penjelasan Singkat
-
generateMAC
– bikin HMAC dari kombinasi pesan + timestamp + nonce dengan kunci rahasia. -
verifyHMAC
– verifikasi dengan:- Membandingkan HMAC yang diterima dengan hasil generate ulang.
- Memastikan timestamp masih dalam rentang wajar (contoh: 60 detik).
- Mengecek apakah nonce sudah pernah dipakai (untuk mencegah replay).
-
main
– contoh penggunaan: verifikasi HMAC asli, HMAC palsu, dan pesan dengan nonce yang sama.
Kenapa Perlu Nonce & Timestamp?
- Nonce: mencegah serangan replay. Kalau nonce sudah pernah dipakai, langsung ditolak.
- Timestamp: mencegah pesan lama dipakai ulang. Jadi kalau ada jeda waktu terlalu jauh, pesan dianggap tidak valid.
Kesimpulan
Dengan HMAC + SHA-512, ditambah nonce dan timestamp, kita bisa bikin sistem otentikasi pesan yang relatif sederhana tapi kuat di Go. Teknik ini sering dipakai di API, protokol komunikasi, atau sistem di mana kita perlu memastikan pesan benar-benar otentik dan tidak diutak-atik.