Hardening auth untuk aplikasi P2P tanpa server terpusat berarti menerima satu fakta penting: tidak ada otoritas online tunggal yang selalu bisa memverifikasi identitas, memutus sesi, atau membatalkan akses secara instan. Karena itu, fondasi autentikasi harus dipindahkan ke cryptographic identity, kebijakan lokal yang dapat diverifikasi offline, serta protokol handshake yang tahan abuse.

Untuk aplikasi P2P, mesh VPN, atau sistem overlay network yang mirip, pendekatan paling aman biasanya bukan “login dengan password ke peer lain”, melainkan identitas berbasis public key, device enrollment yang eksplisit, rotasi dan revokasi kunci, session bootstrap yang saling mengautentikasi, dan kontrol kerusakan jika node jahat berhasil masuk mesh. Artikel ini membahas desain arsitektur dan praktik engineering yang realistis, termasuk trade-off dibanding auth berbasis server.

Threat model: ancaman apa yang benar-benar perlu ditangani?

Sebelum bicara implementasi, tentukan dulu model ancamannya. Pada aplikasi P2P tanpa server pusat, ancaman yang relevan biasanya bukan hanya pencurian kredensial, tetapi juga manipulasi topologi dan penyalahgunaan protokol.

Aset yang harus dilindungi

  • Identitas node: private key perangkat, key material sesi, token enrollment.
  • Keanggotaan mesh: siapa yang boleh join dan siapa yang harus ditolak.
  • Kerahasiaan trafik: data aplikasi, metadata sensitif, alamat internal.
  • Integritas peer discovery: mencegah peer palsu atau penggantian kunci diam-diam.
  • Ketersediaan: node tidak mudah dijatuhkan lewat handshake flood atau abuse resource.

Ancaman umum

  • Impersonation: penyerang mencoba mengaku sebagai peer sah.
  • Replay attack: handshake atau pesan lama diputar ulang untuk membuat sesi palsu.
  • Key compromise: private key perangkat bocor dari laptop atau ponsel.
  • Malicious insider: node sah yang kemudian bertindak jahat di dalam mesh.
  • DoS pada handshake: penyerang memaksa verifikasi kriptografi atau alokasi resource berlebihan.
  • Stale authorization: node yang sudah dicabut aksesnya masih dipercaya karena peer belum menerima update.

Apa yang tidak otomatis terpecahkan oleh kriptografi

Public key cryptography bisa membuktikan bahwa sebuah node memegang private key yang sesuai. Itu tidak sama dengan membuktikan bahwa node tersebut masih layak dipercaya, tidak terinfeksi, atau tidak menyalahgunakan hak akses. Karena itu, desain auth perlu digabung dengan kebijakan otorisasi lokal, segmentasi akses, dan mekanisme revokasi.

Prinsip desain auth untuk P2P tanpa server pusat

1) Identitas utama harus berbasis public key, bukan password antar-peer

Pada jaringan tanpa otoritas online, password antar-peer cenderung lemah: sulit diputar, rawan phishing, dan mendorong penyimpanan shared secret yang sama di banyak node. Sebaliknya, setiap perangkat sebaiknya memiliki pasangan kunci jangka panjang sendiri.

Model yang umum dipakai:

  • Setiap device menghasilkan identity key pair lokal.
  • Public key atau fingerprint public key menjadi identitas utama device di mesh.
  • Node lain memverifikasi signature saat handshake untuk memastikan lawan bicara benar-benar memegang private key terkait.

Keuntungan utama pendekatan ini adalah tidak ada secret bersama yang harus disalin ke semua peer. Jika satu perangkat bocor, Anda cukup merevokasi identitas perangkat itu, bukan mengganti kredensial seluruh mesh.

2) Pisahkan identitas pengguna dari identitas perangkat

Kesalahan desain yang sering muncul adalah menyamakan “user” dengan “device”. Pada praktiknya, satu pengguna bisa punya beberapa perangkat, dan satu perangkat bisa berpindah status trust.

Lebih aman jika model data dipisah menjadi:

  • User identity: entitas manusia atau akun administratif.
  • Device identity: public key unik per perangkat.
  • Enrollment record: bukti bahwa device tertentu telah diotorisasi untuk user atau network tertentu.

Pemisahan ini membuat revokasi lebih presisi. Anda bisa memblokir satu laptop yang hilang tanpa mematikan seluruh akses user.

3) Gunakan enrollment eksplisit, jangan auto-trust node baru

Dalam mesh, ancaman besar datang dari node baru yang mencoba masuk dengan key yang tampak valid tapi tidak pernah diotorisasi. Karena itu, device enrollment harus eksplisit dan tercatat.

Pola yang lazim:

  • Admin atau perangkat yang sudah dipercaya membuat enrollment token dengan masa berlaku singkat.
  • Perangkat baru menghasilkan key pair sendiri.
  • Perangkat baru menukarkan token enrollment untuk mendapatkan sertifikat keanggotaan, signed allowlist entry, atau record trust lain yang dapat diverifikasi peer lain.

Jika sistem benar-benar tanpa server pusat permanen, token dan approval dapat dipropagasikan melalui beberapa peer yang dipercaya, tetapi prinsipnya tetap: node baru tidak boleh otomatis dipercaya hanya karena bisa bicara protokol.

Arsitektur identitas dan enrollment yang praktis

Opsi trust model

Tidak ada satu model yang cocok untuk semua mesh. Pilihan umumnya:

  • Single offline root + delegated signers: ada root key yang jarang dipakai untuk menandatangani key otorisasi yang lebih operasional.
  • TOFU (Trust On First Use): peer menyimpan fingerprint saat pertama bertemu. Cocok untuk sistem kecil, tapi lemah untuk skala besar atau ancaman MITM saat bootstrap.
  • Web-of-trust sederhana: beberapa peer dapat mengesahkan node baru. Fleksibel, tetapi lebih rumit untuk audit dan revokasi.
  • Signed membership list: daftar anggota mesh ditandatangani oleh satu atau beberapa otoritas dan direplikasi ke peer. Ini sering menjadi trade-off praktis terbaik.

Untuk sebagian besar aplikasi P2P/mesh VPN internal, pendekatan signed membership list dengan offline root dan signing key operasional terbatas biasanya paling mudah dikelola.

Struktur record keanggotaan

Sebuah record membership yang baik minimal memuat:

  • device_id
  • public_key
  • owner atau user_id
  • roles atau scope akses
  • issued_at
  • expires_at
  • revocation_epoch atau version
  • signature dari otoritas trust

Tujuannya bukan membuat format yang rumit, tetapi memastikan peer bisa menjawab dua pertanyaan secara lokal: siapa node ini? dan masih bolehkah dia ada di mesh?

Contoh payload membership yang ditandatangani

{
  "device_id": "dev_7f3c2a",
  "user_id": "alice",
  "public_key": "base64:...",
  "roles": ["mesh-member"],
  "issued_at": 1735689600,
  "expires_at": 1738291200,
  "revocation_epoch": 12,
  "signature": "base64:..."
}

Peer penerima harus memverifikasi signature terhadap trust anchor yang sudah dipin secara lokal. Jangan percaya payload keanggotaan hanya karena dikirim lewat kanal terenkripsi; payload itu sendiri harus dapat diverifikasi.

Session bootstrap antar-peer yang aman

Tujuan handshake

Handshake antar-peer sebaiknya memenuhi empat hal:

  1. Mutual authentication: kedua sisi membuktikan identitasnya.
  2. Forward secrecy: kompromi key jangka panjang tidak otomatis membuka seluruh trafik lama.
  3. Replay resistance: pesan handshake lama tidak bisa dipakai ulang.
  4. Authorization check: identitas valid saja belum cukup; node juga harus masih diizinkan join.

Alur handshake yang direkomendasikan

Secara konseptual, gunakan:

  • Identity key jangka panjang untuk tanda tangan atau binding identitas.
  • Ephemeral key per sesi untuk key agreement.
  • Nonce/challenge dua arah untuk mencegah replay.
  • Membership proof atau sertifikat keanggotaan yang dapat diverifikasi.

Alur sederhananya:

  1. Peer A mengirim hello berisi versi protokol, nonce_A, ephemeral_pub_A, dan identitas atau referensi membership.
  2. Peer B membalas nonce_B, ephemeral_pub_B, membership proof B, serta signature atas transkrip handshake yang mengikat nonce dan ephemeral key.
  3. Peer A memverifikasi membership dan signature B, lalu mengirim signature balasan atas transkrip yang sama.
  4. Kedua pihak menurunkan session key dari key agreement ephemeral dan menandai sesi aktif hanya jika authorization lolos.

Intinya: jangan hanya menandatangani public key lawan. Tanda tangan harus mengikat seluruh konteks handshake—nonce, ephemeral key, identitas peer, dan bila perlu parameter jaringan—agar tidak mudah dipakai dalam serangan reflection atau replay silang protokol.

Contoh pseudo-code verifikasi handshake

func verifyPeerHello(msg, now):
    if msg.timestamp too far from now:
        reject("clock skew or replay window")

    if seenNonce(msg.peer_id, msg.nonce):
        reject("replay detected")

    membership = parseMembership(msg.membership)
    if !verifyMembershipSignature(membership, trustAnchors):
        reject("invalid membership proof")

    if membership.expires_at < now:
        reject("membership expired")

    if isRevoked(membership.device_id, membership.revocation_epoch):
        reject("device revoked")

    transcript = hash(msg.version, msg.nonce, msg.ephemeral_pub, membership.public_key)
    if !verifySignature(membership.public_key, transcript, msg.signature):
        reject("identity signature invalid")

    rememberNonce(msg.peer_id, msg.nonce)
    accept()

Pseudo-code ini sengaja generik. Implementasi nyata harus memakai primitive yang sudah teruji, bukan kriptografi buatan sendiri.

Replay protection dan rate limit handshake

Replay protection tidak cukup hanya dengan timestamp

Timestamp membantu, tetapi tidak cukup sendirian. Jam sistem bisa meleset, dan penyerang bisa memutar ulang paket dalam jendela waktu yang sama. Gabungkan beberapa teknik:

  • Nonce acak per handshake.
  • Penyimpanan cache nonce jangka pendek per peer atau per source.
  • Timestamp dengan toleransi kecil untuk membatasi umur pesan.
  • Session transcript binding agar pesan tidak bisa dipindah ke konteks lain.

Untuk sistem resource terbatas, Anda tidak perlu menyimpan semua nonce selamanya. Simpan nonce dalam jendela pendek yang cukup untuk mencegah replay praktis.

Rate limiting sebelum operasi kriptografi berat

Handshake adalah target DoS yang umum karena sering melibatkan parsing, verifikasi signature, dan alokasi state. Terapkan batasan sebelum masuk ke jalur mahal:

  • Token bucket per IP atau per source endpoint.
  • Batas koneksi belum terautentikasi.
  • Proof-of-work ringan atau cookie challenge jika ancaman flood tinggi.
  • Lazy allocation: jangan alokasikan state sesi penuh sebelum peer lolos pemeriksaan awal.

Urutan pemeriksaan penting. Lakukan validasi murah lebih dulu: ukuran paket, versi protokol, format field, freshness timestamp, lalu baru verifikasi signature atau membership chain.

Contoh urutan pemeriksaan defensif

onIncomingHandshake(packet):
    if packet.size > MAX_HANDSHAKE_SIZE:
        drop()
    if !rateLimiter.allow(packet.source):
        drop()
    if !basicFormatValid(packet):
        drop()
    if !timestampFresh(packet.ts):
        drop()
    if replayCache.has(packet.source, packet.nonce):
        drop()

    // Baru setelah lolos pemeriksaan murah:
    if !verifyCrypto(packet):
        drop()

    establishPendingSession(packet)

Kesalahan umum adalah memverifikasi signature lebih dulu untuk semua paket masuk. Itu membuat CPU Anda menjadi target murah bagi penyerang.

Penyimpanan secret di client

Private key jangan disimpan seperti token biasa

Pada aplikasi P2P, private key perangkat adalah pusat kepercayaan. Menyimpannya di file plaintext atau local storage tanpa proteksi adalah undangan untuk kompromi.

Praktik yang lebih aman:

  • Gunakan secure enclave, keychain, TPM, atau penyimpanan OS yang memang dirancang untuk secret jika tersedia.
  • Jika harus menyimpan di disk, encrypt at rest dengan key yang berasal dari mekanisme OS atau passphrase user.
  • Berikan izin file yang ketat dan hindari world-readable path.
  • Pisahkan identity key jangka panjang dari session key yang hanya hidup di memori.

Jangan menyimpan enrollment token terlalu lama

Enrollment token seharusnya bersifat sementara. Setelah device berhasil memperoleh bukti keanggotaan permanen atau semi-permanen, hapus token tersebut. Banyak insiden terjadi bukan karena protokol lemah, tetapi karena token bootstrap yang seharusnya singkat ternyata tetap tersimpan di disk atau log.

Perlakukan log sebagai sumber kebocoran

Hindari menulis hal berikut ke log:

  • private key atau seed
  • full token enrollment
  • session key
  • payload handshake mentah yang berisi material sensitif

Jika perlu troubleshooting, log-kan fingerprint, device_id, kode error verifikasi, dan hash terpotong, bukan secret utuh.

Rotasi dan revokasi kunci

Rotasi kunci harus direncanakan dari awal

Jika desain awal mengasumsikan public key perangkat tidak akan pernah berubah, Anda sedang menunda masalah. Perangkat hilang, algoritma perlu diganti, atau user berganti laptop. Sistem harus punya jalur resmi untuk key rotation.

Pola yang aman:

  • Device lama menandatangani permintaan rotasi ke key baru, jika masih tersedia.
  • Jika device lama hilang, rotasi dilakukan melalui approval administratif atau quorum trust lain.
  • Peer menerima key baru hanya jika ada bukti transisi yang valid atau record membership baru yang ditandatangani trust anchor.

Revokasi di sistem tanpa server pusat selalu eventual

Inilah trade-off terbesar dibanding auth berbasis server: tanpa otoritas online sentral, revokasi jarang bersifat instan. Node yang offline mungkin belum tahu bahwa suatu device telah dicabut.

Mitigasinya:

  • Membership berumur pendek sehingga akses basi cepat kedaluwarsa.
  • Revocation list atau revocation epoch yang direplikasi antar-peer.
  • Reconnect policy: sesi lama harus dinegosiasikan ulang secara periodik.
  • Scope minimal untuk setiap device agar dampak kompromi lebih kecil.

Jika ancaman revokasi instan sangat kritis, arsitektur murni tanpa server pusat mungkin bukan pilihan terbaik. Anda mungkin tetap memerlukan komponen koordinasi yang sangat kecil, walau bukan jalur data utama.

Hindari sesi abadi

Salah satu kesalahan umum adalah membiarkan sesi terenkripsi bertahan sangat lama setelah autentikasi awal. Dalam konteks revokasi, ini berbahaya karena device yang sudah tidak sah tetap punya kanal aktif.

Lebih aman jika:

  • sesi punya maksimum lifetime
  • rekey dilakukan berkala
  • authorization dicek ulang saat renegosiasi atau saat menerima update revokasi

Validasi peer dan pencegahan node jahat di dalam mesh

Auth yang valid bukan berarti peer aman diberi akses penuh

Begitu node jahat berhasil masuk mesh, masalah bergeser dari autentikasi ke containment. Karena itu, jangan membuat model “sekali join, bebas bicara ke semua node”.

Hardening yang disarankan:

  • Role atau scope per device, bukan hanya per user.
  • ACL antar-peer: node tertentu hanya boleh mengakses subset layanan.
  • Segmentasi overlay: pisahkan domain administrasi, data plane, dan observability.
  • Perintah sensitif butuh otorisasi tambahan, jangan cukup dengan membership biasa.

Deteksi perilaku janggal

Node yang sah tetap bisa bertindak jahat. Tambahkan kontrol operasional seperti:

  • pembatasan jumlah koneksi outbound ke peer lain
  • batas rate untuk request sensitif
  • deteksi scanning alamat internal atau enumerasi peer berlebihan
  • karantina otomatis jika device melanggar kebijakan berulang

Tujuannya bukan membuat IDS kompleks, tetapi mengurangi blast radius insider yang sudah punya identitas sah.

Pin trust anchor, bukan hanya endpoint

Pada jaringan yang endpoint-nya dinamis, validasi berdasarkan alamat IP atau hostname saja tidak cukup. Yang perlu dipin adalah trust anchor, membership signature, atau fingerprint identitas perangkat. Endpoint jaringan bisa berubah; identitas kriptografi tidak.

Audit log minimal yang tetap berguna

Sistem P2P sering menghindari logging karena khawatir bocor metadata. Itu benar, tetapi tanpa audit log minimum, Anda akan kesulitan menelusuri kompromi atau bug revokasi.

Minimal catat peristiwa berikut:

  • device enrollment dibuat, dipakai, kedaluwarsa, atau gagal
  • device baru diterima atau ditolak
  • rotasi key berhasil atau ditolak
  • revokasi diterima dari peer lain
  • handshake gagal dengan alasan yang terstruktur
  • pelanggaran rate limit atau replay detection

Format log sebaiknya memuat:

  • timestamp
  • peer_id atau device_id
  • fingerprint key terpotong
  • event_type
  • decision: allow/deny/quarantine
  • reason_code

Catatan: audit log minimal bukan berarti menyimpan seluruh isi trafik. Simpan metadata yang cukup untuk investigasi, tetapi hindari material rahasia dan payload aplikasi.

Contoh alur login atau join network yang aman

Skenario

Misalkan sebuah aplikasi mesh VPN ingin menambahkan laptop baru milik seorang engineer ke jaringan internal tanpa server pusat permanen.

Alur yang disarankan

  1. Admin membuat enrollment token singkat

    Token memuat scope terbatas, masa berlaku pendek, dan satu kali pakai. Token ini bukan identitas permanen.

  2. Device baru membuat identity key pair lokal

    Private key dibuat dan disimpan di penyimpanan aman perangkat. Public key belum otomatis dipercaya.

  3. Device mengirim request enrollment

    Request berisi public key perangkat, metadata minimal perangkat, dan token enrollment. Jika memungkinkan, request juga ditandatangani dengan key baru agar binding identitas lebih kuat sejak awal.

  4. Peer otorisasi memverifikasi token

    Peer atau signer yang berwenang memeriksa token belum dipakai, belum kedaluwarsa, dan scope-nya cocok. Setelah itu signer menerbitkan membership record yang ditandatangani.

  5. Membership record direplikasi

    Peer lain menerima update allowlist atau revocation epoch baru melalui mekanisme sinkronisasi mesh. Replikasi tidak harus instan, tetapi harus konsisten dan tahan manipulasi.

  6. Device melakukan handshake ke peer mana pun

    Saat koneksi pertama, device mengirim membership proof, nonce, dan ephemeral key. Peer lawan memverifikasi signature trust anchor, status revokasi, dan transcript handshake.

  7. Sesi aktif dengan hak minimum

    Begitu lolos, device hanya mendapat akses sesuai role. Akses administratif atau sensitif perlu otorisasi tambahan, bukan diberikan otomatis kepada semua anggota mesh.

Apa yang membuat alur ini aman?

  • Token bootstrap berumur pendek sehingga tidak menjadi kredensial permanen.
  • Public key device adalah identitas utama, bukan password bersama.
  • Keanggotaan diverifikasi lewat signature trust anchor, bukan asumsi jaringan lokal.
  • Handshake mengikat nonce dan ephemeral key, sehingga replay lebih sulit.
  • Hak akses dibatasi setelah join, sehingga kompromi satu node tidak langsung membuka seluruh mesh.

Trade-off dibanding auth berbasis server

Kelebihan pendekatan P2P

  • Tidak bergantung pada satu titik kegagalan online.
  • Dapat tetap bekerja saat konektivitas ke otoritas pusat tidak ada.
  • Privasi dan kemandirian operasional lebih baik pada beberapa use case.

Kekurangan yang harus diterima

  • Revokasi tidak instan di semua kondisi.
  • Sinkronisasi trust state lebih rumit.
  • Operasional incident response lebih sulit karena tidak ada kill switch sentral.
  • Debugging auth failure lebih menantang karena state tersebar di banyak peer.

Kapan tetap butuh komponen terpusat kecil?

Jika kebutuhan Anda mencakup revokasi hampir real-time, compliance audit ketat, atau kontrol akses dinamis berbasis konteks, sering kali masuk akal untuk tetap memiliki control plane ringan atau otoritas penandatanganan walau jalur data tetap P2P. Ini bukan kegagalan desain; ini kompromi engineering yang masuk akal.

Kesalahan implementasi yang sering terjadi

  • Menganggap TLS transport saja cukup. TLS mengamankan kanal, tetapi belum tentu memodelkan keanggotaan mesh Anda.
  • Menyimpan private key di file tanpa proteksi.
  • Tidak memisahkan user dan device identity.
  • Tidak punya mekanisme revokasi yang bisa dipropagasikan.
  • Sesi terlalu panjang tanpa re-auth atau rekey.
  • Verifikasi kriptografi dilakukan sebelum filter murah, sehingga rentan DoS.
  • Auto-accept node baru karena berasal dari subnet yang “terlihat internal”.

Checklist implementasi hardening auth

  • Setiap device memiliki identity key pair unik.
  • Trust anchor atau public key signer dipin secara lokal.
  • Node baru masuk hanya lewat device enrollment eksplisit.
  • Membership proof memiliki masa berlaku dan dapat diverifikasi offline.
  • Handshake memakai ephemeral key, nonce, dan signature atas transcript.
  • Ada replay cache dan validasi freshness.
  • Ada rate limit dan pembatasan state untuk koneksi belum terautentikasi.
  • Private key disimpan di secure storage atau terenkripsi di disk.
  • Enrollment token sekali pakai dan cepat kedaluwarsa.
  • Ada mekanisme key rotation dan revocation propagation.
  • Sesi punya lifetime maksimum dan rekey berkala.
  • Authorization berbasis scope/role per device, bukan akses penuh default.
  • Ada audit log minimal untuk enrollment, handshake failure, rotasi, dan revokasi.
  • Node yang melanggar kebijakan dapat dikarantina atau dibatasi otomatis.

Penutup

Hardening auth untuk aplikasi P2P tanpa server terpusat bukan soal menyalin pola login aplikasi web ke jaringan mesh. Intinya adalah memindahkan kepercayaan ke identitas kriptografi, enrollment perangkat yang ketat, validasi membership yang bisa diverifikasi offline, dan kontrol kerusakan saat node jahat berhasil masuk.

Jika Anda hanya mengambil satu prinsip dari artikel ini, ambil yang berikut: anggap setiap device sebagai identitas terpisah, buat bukti keanggotaan yang dapat diverifikasi peer lain, dan rancang sistem seolah revokasi tidak akan pernah instan. Dari sana, tambahkan replay protection, rate limiting handshake, penyimpanan secret yang aman, audit log minimal, dan segmentasi akses. Kombinasi itulah yang biasanya membuat mesh tetap bisa dipakai di dunia nyata tanpa mudah runtuh saat satu node bermasalah.