Data pelanggan TokoKita kini tersebar di banyak tempat sekaligus: database transaksional menyimpan alamat dan nomor telepon, data warehouse menyimpan riwayat pesanan bertahun-tahun, dan data lake menampung log event mentah. Semakin banyak titik penyimpanan, semakin luas permukaan yang harus dijaga — satu celah pada lapisan mana pun dapat membocorkan data yang sama. Keamanan data karena itu bukan satu tool yang dipasang sekali, melainkan serangkaian prinsip yang berlaku sama pada sistem besar maupun kecil. Chapter ini meletakkan fondasi yang dipakai seluruh chapter lain di section ini: triad CIA, principle of least privilege, defense in depth, dan kebiasaan paling dasar seorang data engineer, yaitu tidak pernah menyimpan kata sandi sebagai plaintext.

Triad CIA: Kerahasiaan, Integritas, Ketersediaan #

Hampir semua keputusan keamanan dapat ditimbang dengan tiga pertanyaan dari triad CIA — Confidentiality, Integrity, Availability. Confidentiality menjawab siapa saja yang boleh melihat data, Integrity menjawab apakah data dapat berubah tanpa terdeteksi, dan Availability menjawab apakah data tetap dapat diakses saat dibutuhkan. Tabel berikut memetakan ketiga pilar ke skenario konkret TokoKita:

PilarPertanyaan kunciSkenario TokoKita
ConfidentialitySiapa saja yang boleh melihat data ini?Alamat dan telepon pelanggan hanya boleh dibaca tim fulfillment dan pipeline pengiriman
IntegrityBisakah data berubah tanpa terdeteksi?total_bayar pada tabel pesanan tidak boleh berubah diam-diam saat pipeline berjalan
AvailabilityApakah data tetap ada saat dibutuhkan?Dashboard omzet harian tetap hidup meski satu node warehouse bermasalah

Ketiga pilar tersebut sering tarik-menarik. Mencadangkan warehouse dengan enkripsi berlapis memperkuat confidentiality, tetapi pemulihan menjadi lebih lambat dan menurunkan availability saat insiden. Kerja seorang data engineer adalah memilih titik seimbang berdasarkan nilai dan sensitivitas data; kerangka seperti NIST Cybersecurity Framework menyediakan daftar periksa yang lazim dipakai industri.

Principle of Least Privilege dan Need to Know #

Principle of least privilege menyatakan setiap akun — manusia maupun service account — hanya boleh memegang izin minimum yang dibutuhkan untuk tugasnya. Pipeline ETL yang hanya membaca tabel sumber cukup diberi SELECT, bukan ALL PRIVILEGES; akun pipeline tersebut tidak perlu mampu menghapus tabel. Prinsip ini memperkecil dampak kebocoran kredensial: pihak yang tidak berhak yang mendapat akun baca-saja tidak bisa mengubah data.

Need to know mempersempit lagi: meskipun seseorang berhak secara umum, akses hanya diberikan bila pekerjaan memang menuntut data tersebut. Analyst yang menyelidiki pola pembelian cukup menerima tabel agregat per wilayah, bukan baris mentah berisi nama dan alamat pelanggan. Gabungan kedua prinsip menjadi ukuran apakah sebuah pemberian akses layak atau justru berlebihan.

Defense in Depth #

Defense in depth berarti melindungi data dengan banyak lapisan yang saling menutupi, karena setiap lapisan dapat gagal sendiri-sendiri. Diagram berikut memperlihatkan lapisan khas yang dilewati sebuah permintaan sebelum menyentuh data TokoKita:

Perhatikan bahwa audit logging berdiri sebagai pengawas yang memantau hampir semua lapisan, bukan sebagai lapisan terakhir. Bila satu lapisan ditembus — misalnya kredensial seseorang berhasil dicuri — lapisan RBAC, enkripsi, dan masking masih membatasi seberapa jauh penyalahgunaan dapat berjalan. Setiap lapisan pada diagram tersebut akan kita bedah satu per satu di chapter-chapter selanjutnya.

Mengapa Menyimpan Hash, Bukan Plaintext #

Skenario paling awal yang dijumpai hampir semua engineer: tabel pengguna dengan kolom kata sandi. Menyimpan kata sandi apa adanya berarti satu berkas users.csv yang bocor langsung membuka semua akun. Mari kita buktikan bedanya memakai hashlib:

python
"""Demo ch1: plaintext vs hash — mengapa tabel pengguna menyimpan hash."""
import hashlib

SANDI_PENGGUNA = {
    "budi": "sandi-rahasia-budi",
    "siti": "sandi-rahasia-siti",
}

print("== Tabel pengguna bila kata sandi disimpan plaintext ==")
for pengguna, sandi in SANDI_PENGGUNA.items():
    print(f"{pengguna:6}-> {sandi}")

print()
print("== Tabel pengguna bila kata sandi disimpan sebagai hash SHA-256 ==")
for pengguna, sandi in SANDI_PENGGUNA.items():
    sidik = hashlib.sha256(sandi.encode()).hexdigest()
    print(f"{pengguna:6}-> {sidik}")

print()
print("== Dua pengguna berkata sandi sama, salt berbeda (PBKDF2) ==")
for pengguna, salt in [("budi", "salt-budi-2026"), ("siti", "salt-siti-2026")]:
    sidik = hashlib.pbkdf2_hmac("sha256", b"sandi-sama-2026", salt.encode(), 600_000)
    print(f"{pengguna:6}-> {sidik.hex()[:32]}...")

print()
print("== Verifikasi login Siti tanpa membaca kata sandi asli ==")
masukan = "sandi-rahasia-siti"
sidik_masukan = hashlib.sha256(masukan.encode()).hexdigest()
sidik_tersimpan = hashlib.sha256(SANDI_PENGGUNA["siti"].encode()).hexdigest()
print("hash masukan   :", sidik_masukan)
print("hash tersimpan :", sidik_tersimpan)
print("login diterima :", sidik_masukan == sidik_tersimpan)

Output yang Dihasilkan:

text
== Tabel pengguna bila kata sandi disimpan plaintext ==
budi  -> sandi-rahasia-budi
siti  -> sandi-rahasia-siti

== Tabel pengguna bila kata sandi disimpan sebagai hash SHA-256 ==
budi  -> c5485e3be86620d8e321980e680bf3835eeae5d6988f7288378e18098ceae545
siti  -> 22c3a8ee00c8684992c11812200704a52873d0cdb2c2e744c72d702891bcb798

== Dua pengguna berkata sandi sama, salt berbeda (PBKDF2) ==
budi  -> 7bc00ab11103660bb0f81cb68446b737...
siti  -> 0c0c682688cc1fc2151300acfe610512...

== Verifikasi login Siti tanpa membaca kata sandi asli ==
hash masukan   : 22c3a8ee00c8684992c11812200704a52873d0cdb2c2e744c72d702891bcb798
hash tersimpan : 22c3a8ee00c8684992c11812200704a52873d0cdb2c2e744c72d702891bcb798
login diterima : True

Mari kita telaah baris-baris kode di atas:

  1. Baris 17 (sidik = hashlib.sha256(...)): fungsi hashlib.sha256 menghasilkan sidik 64 karakter heksadesimal; kata sandi aslinya tidak pernah disimpan di tabel.
  2. Baris 22-23 (blok PBKDF2): hashlib.pbkdf2_hmac mengulang proses hashing 600.000 kali dengan salt berbeda per pengguna, sehingga dua orang yang kebetulan memakai kata sandi sama tetap menghasilkan hash berbeda.
  3. Baris 29-30 (verifikasi): proses login menghitung hash dari masukan pengguna, lalu membandingkannya dengan hash tersimpan — perbandingan dua string, bukan membuka kembali hash.
  4. Baris 33: keputusan menerima atau menolak login diambil semata-mata dari kesamaan kedua hash.

Bagian verifikasi menunjukkan inti kerjanya: hash adalah fungsi satu arah, jadi sistem dapat memeriksa kata sandi tanpa pernah menyimpan kata sandi tersebut. Salt memastikan dua pengguna dengan kata sandi identik tidak menghasilkan hash sama, dan iterasi PBKDF2 membuat pencobaan menebak secara massal menjadi mahal. Rincian seluruh fungsi hashing tersedia di dokumentasi hashlib .

Triad CIA memberi kerangka, least privilege memberi aturan main, dan hash memberi contoh konkret pertama. Prinsip-prinsip tersebut belum menjawab bagaimana sistem mengenali siapa yang sedang meminta akses dan memutuskan permintaan mana yang boleh dijalankan — dua pertanyaan itu adalah wilayah Chapter Authentication dan Authorization.