Encryption dari chapter sebelumnya menjaga data dari pihak luar, tetapi ancaman berikutnya justru datang dari dalam: mata manusia yang sah membuka data. Tim support TokoKita perlu melihat tiket pelanggan, analyst perlu menghitung pola pembelian ulang, dan engineer perlu men-debug pipeline dengan data yang realistis — sementara email, nomor telepon, dan alamat rumah pelanggan tidak boleh tampil dalam bentuk utuh di semua tempat tersebut. Masking dan tokenization menyelesaikan masalah ini dengan dua pendekatan berbeda: masking menyembunyikan sebagian nilai untuk ditampilkan, tokenization mengganti nilai dengan pengganti yang bisa dipakai untuk analitik. Chapter ini membangun kedua teknik tersebut dan menunjukkan kapan masing-masing dipilih.

Tiga Teknik, Tiga Kebutuhan #

AspekMaskingTokenizationHashing
Nilai asliditampilkan sebagian (b***@example.com)diganti token (tok_4e90...)diganti sidik tetap
Dapat dibalik?tidak — tampilan sudah kehilangan bagian aslitergantung mode: deterministik tidak, reversibel ya dengan kuncitidak
Deterministik?ya, aturan yang sama untuk nilai samaya bila memakai kunci dan salt tetapya
Cocok untuklayar support, log, environment non-prodkolom analitik yang perlu join antar tabelchecksum integritas, sidik kata sandi

Kuncinya ada pada baris “deterministik”: analitik membutuhkan email yang sama selalu menjadi token yang sama, karena jika tidak, penghitungan pelanggan unik dan join tabel akan rusak. Hashing yang kita latih di Chapter Prinsip Keamanan Data sebenarnya adalah tokenisasi tanpa kunci rahasia — siapa pun yang tahu nilainya bisa menghitung ulang hash dan menebak daftar korrespondensinya. Tokenisasi yang memakai kunci rahasia menutup celah tersebut.

Simulasi: Masking untuk Layar, Token untuk Analitik #

python
"""Demo ch6: masking untuk tampilan, tokenisasi deterministik dan reversibel."""
import base64
import hashlib
import hmac

from cryptography.fernet import Fernet

# Kunci dan salt demo; di production keduanya disimpan di secrets manager.
KUNCI_TOKEN = b"demo-tokenization-key-GANTI-DI-PRODUCTION"
SALT = b"tokokita-token-salt-2026"


def mask_email(email: str) -> str:
    lokal, domain = email.split("@")
    return f"{lokal[0]}{'*' * (len(lokal) - 1)}@{domain}"


def mask_telepon(nomor: str) -> str:
    awal, tengah, akhir = nomor.split("-")
    return f"{awal}-{'*' * len(tengah)}-{akhir[-4:]}"


def token_deterministik(nilai: str) -> str:
    tanda = hmac.new(KUNCI_TOKEN, SALT + nilai.encode(), hashlib.sha256).hexdigest()
    return f"tok_{tanda[:16]}"


fernet = Fernet(base64.urlsafe_b64encode(
    hashlib.sha256(b"demo-token-vault-tokokita").digest()))


def token_reversibel(nilai: str) -> str:
    return fernet.encrypt(nilai.encode()).decode()


def balikkan_token(token: str) -> str:
    return fernet.decrypt(token.encode()).decode()


DATA_PELANGGAN = {
    "budi": ("[email protected]", "0812-3456-7890"),
    "siti": ("[email protected]", "0813-9876-5432"),
}

print("== Masking: untuk layar tim support ==")
for nama, (email, telepon) in DATA_PELANGGAN.items():
    print(f"{nama}: {email:18}-> {mask_email(email):18} | "
          f"{telepon} -> {mask_telepon(telepon)}")

print()
print("== Tokenisasi deterministik: untuk tabel analitik ==")
for nama, (email, _) in DATA_PELANGGAN.items():
    print(f"{nama}: {email:18}-> {token_deterministik(email)}")

print("email sama menghasilkan token sama :",
      token_deterministik("[email protected]") == token_deterministik("[email protected]"))
print("email beda menghasilkan token beda :",
      token_deterministik("[email protected]") != token_deterministik("[email protected]"))

print()
print("== Tokenisasi reversibel: untuk sistem pembayaran ==")
print("token dikembalikan ke email asli:",
      balikkan_token(token_reversibel("[email protected]")) == "[email protected]")

Output yang Dihasilkan:

text
== Masking: untuk layar tim support ==
budi: [email protected]  -> b***@example.com   | 0812-3456-7890 -> 0812-****-7890
siti: [email protected]  -> s***@example.com   | 0813-9876-5432 -> 0813-****-5432

== Tokenisasi deterministik: untuk tabel analitik ==
budi: [email protected]  -> tok_4e908cad20ae68d2
siti: [email protected]  -> tok_13933acfa18b612b
email sama menghasilkan token sama : True
email beda menghasilkan token beda : True

== Tokenisasi reversibel: untuk sistem pembayaran ==
token dikembalikan ke email asli: True

Mari kita telaah baris-baris kode di atas:

  1. Baris 13-15 (mask_email): satu karakter pertama dipertahankan agar tim support masih bisa mengonfirmasi identitas, sisanya diganti tanda bintang — panjang bintang mengikuti panjang asli sehingga panjang nilai tidak bocor lebih dari perlu.
  2. Baris 23-25 (token_deterministik): token dihitung dengan HMAC-SHA256 atas SALT + nilai; kunci rahasia membuat pihak luar tidak bisa menguji tebakan “apakah email ini termasuk data pelanggan” seperti pada hash polos.
  3. Baris 55-58 (dua pengujian): email sama menghasilkan token sama sehingga COUNT(DISTINCT token) tetap benar, sedangkan email berbeda menghasilkan token berbeda sehingga dua pelanggan tidak menyatu.
  4. Baris 32-33 (token_reversibel): token pembayaran memakai enkripsi Fernet, jadi hanya pemegang kunci yang dapat memetakan kembali token ke email asli saat pengembalian dana — kebutuhan yang tidak bisa dipenuhi token deterministik.

Pilihan mode mengikuti kebutuhan pemakai: tim support cukup menerima masked value di layar, analyst bekerja di tabel token deterministik, dan sistem pembayaran memakai token reversibel yang pemetaannya tersimpan terpisah. Detail fungsi hmac.new tersedia di dokumentasi Python .

Diterapkan ke warehouse TokoKita, pemetaannya menjadi konkret. Tabel pelanggan di layer curated menyimpan token deterministik untuk email dan telepon, sehingga join dengan tabel pesanan tetap benar tanpa menyimpan alamat asli. Layar aplikasi internal tim support menampilkan masked value karena pekerjaan sehari-hari hanya perlu mengonfirmasi dua karakter pertama. Sementara itu, nomor kartu pembayaran disimpan sebagai token reversibel milik layanan pembayaran — TokoKita sendiri tidak menyimpan nomor asli di warehouse mana pun, dan hanya layanan tersebut yang bisa memetakan balik saat pengembalian dana. Aturan sederhananya: semakin jarang nilai asli benar-benar dibutuhkan, semakin jauh nilai asli disimpan dari mata manusia.

Format-Preserving Tokenization #

Variasi lanjutan yang sering dipakai industri adalah format-preserving tokenization: token mengikuti format nilai asli — nomor kartu 16 digit tetap menjadi 16 digit, nomor telepon tetap valid secara format — sehingga aplikasi lama yang memvalidasi panjang kolom tetap berjalan tanpa perombakan skema. Implementasinya memakai algoritma enkripsi dengan domain terbatas dan biasanya disediakan layanan khusus, bukan ditulis sendiri. Format yang dipertahankan memudahkan integrasi, tetapi ingat bahwa kesamaan format tidak berarti kesamaan makna: token 16 digit tetap tidak bisa dipakai untuk transaksi.

Kini kita punya teknik menyembunyikan nilai untuk pemakaian yang berbeda-beda. Pertanyaan berikutnya menentukan teknik mana dipakai untuk kolom mana: seberapa sensitifkah setiap aset data TokoKita, dan siapa yang memutuskan? Pemetaan tersebut adalah pekerjaan Chapter Klasifikasi Data.