Data Masking — Full Current Functional Flow

Dokumen ini memetakan alur yang benar-benar berjalan pada source saat ini untuk fitur Data Masking, mulai dari pembuatan dan rotasi Data Access Key (token), konfigurasi dynamic field yang sensitif, penyisipan unmasking (dekripsi) untuk search filter dari request, hingga proses masking selektif (enkripsi) pada payload response. Dokumen ini adalah baseline perilaku current, bukan desain target.

Status Verifikasi

Area Status Batas Verifikasi
Service flow dan branching SOURCE-TRACED Ditelusuri dari TransactionMaskService dan dependensinya
Endpoint dan header SOURCE-TRACED Ditelusuri dari penggunaan anotasi header X-Data-Access-Key di controllers
Database behavior SOURCE-TRACED Berdasarkan token user dan config entity behavior
Runtime behavior NOT RUNTIME-VERIFIED Tidak menjalankan aplikasi atau integration test
Production behavior NOT PRODUCTION-VERIFIED Tidak memeriksa cron setting dan keys environment production

Peta Komponen Utama

Concern Komponen Current Tanggung Jawab
Masking orchestration TransactionMaskService Menangkap map payload, menguji token, meloop active sensitive config, dan mengganti nilai menjadi cipher atau fallback.
Access Token lifecycle DataAccessKeyService Menginisialisasi dummy key, memvalidasi input user vs database, menyimpan cache validasi, dan melakukan cron harian rotasi token.
Encryption engine EncryptionService Melakukan operasi kriptografi AES/GCM/NoPadding menggunakan active KeyService. Menelan error decrypt pada unmasking filter.
Sensitive fields registry SensitiveFieldConfigService Menyimpan field mana saja yang dianggap sensitif. Memvalidasi field baru terhadap domain class yang didukung.

Ringkasan End-to-End

[Diagram]

Flow 1 — Access Key Validation dan Lifecycle

Token (Data Access Key) setiap user disimpan dan dirotasi di dalam database secara otomatis. Mekanisme validasi memiliki fallback terhadap format key legacy.

1.1 Validasi Token

[Diagram]

[!DANGER] Cache Invalidation Delay

validationCache menggunakan ConcurrentHashMap dengan TTL 5 menit (CACHE_TTL_MS), namun current behavior tidak membersihkan cache spesifik user jika role atau token mereka dicabut (misal: deactivate user) di pertengahan jalan, kecuali ketika Global Scheduled Rotation berjalan. Token yang sudah ter-cache akan terus di-honor hingga 5 menit berlalu.

1.2 Inisialisasi dan Rotasi

Mekanisme generation token current membuat random token sepanjang 64 karakter dari gabungan 2 UUID yang di-strip -nya.

[Diagram]

Flow 2 — Konfigurasi Dynamic Sensitive Fields

SensitiveFieldConfigService mengatur field apa saja yang disembunyikan.

[Diagram]

[!DANGER] Tightly Coupled Static Validation

Validasi field asertif pada variabel statis VALID_FIELDS yang hanya me-load attributes dari ExistingCurrTrans.class.getDeclaredFields(). Jika current app memiliki entity lain yang digunakan dalam response (misalnya AlertCase atau AcquirerAlert) dan entity tersebut memiliki nama field unik yang butuh di-mask, current behavior menolak registrasinya. Hanya field dengan nama sama dengan milik ExistingCurrTrans atau field dalam objek addtData yang bisa ditambahkan.

Flow 3 — Unmasking Request Filters

Semua entry point pencarian (/search) melakukan pemanggilan ke unmaskSearchFilters untuk menterjemahkan kembali ciphertext dari client menjadi plaintext agar database criteria builder bisa berjalan (misalnya query exact match pada No Rekening).

[Diagram]

[!DANGER] Silent Fallback pada Dekripsi Filter

decryptIfEncrypted menangkap Exception e (General Exception) dan me-return original value secara pasif. Ini artinya sistem tidak bisa membedakan mana "client dengan sengaja mengirim plaintext" versus "client mengirim random base64 yang gagal decrypt". Keduanya akan lolos ke business logic dan diproses sebagai kriteria filter.

Flow 4 — Masking Data (Response Payload)

Jika token invalid atau absent, proses mutasi map data berjalan (replace original value).

[Diagram]

[!DANGER] Type Mismatch di JSON Payload

Jika field yang dikonfigurasi sebagai sensitif aslinya berjenis Number atau Boolean (contoh: amount, isFraud), current behavior memaksakan field tersebut menjadi String berbunyi "[PROTECTED]". Ini akan langsung mengubah skema response API (dari integer ke string) dan berpotensi memunculkan error unmarshal/deserialization pada sistem UI / Client.

Matriks Skenario Operasional

Skenario Masking Payload Search Filter (Unmask) Assignment/State Lain Next Step
Request tanpa X-Data-Access-Key Masking berjalan aktif Dekripsi di filter tetap diupayakan Data disamarkan UI menampilkan Cipher
Token valid tapi cache miss Masking di-skip (Plaintext) Filter di-decrypt / lewat Cache terisi timestamp baru UI menampilkan Plaintext
Token valid dan cache hit Masking di-skip (Plaintext) Filter di-decrypt / lewat DB tidak disentuh untuk user key UI menampilkan Plaintext
Token kadaluwarsa/diubah via Cron Masking berjalan (ditolak) Filter tetap bisa unmask (jika ciphertext valid) Data disamarkan Client harus request key baru (SSE)
Client mengirim Plaintext di filter Masking bergantung Token Fallback raw value di controller Query DB memakai plaintext tersebut Lolos logika pencarian normal
Enkripsi AES gagal (misal invalid Key) Response diset [PROTECTED] Filter menelan error Nilai riil dihapus dari payload UI menampilkan [PROTECTED]
Field berjenis Integer dikonfigurasi sensitif Response menjadi String [PROTECTED] N/A Type JSON terubah Kemungkinan error di Frontend parsers

State Ownership Current

State Authoritative Current Projection/Consumer
Dynamic fields target SensitiveFieldConfigRepository (T_SENSITIVE_FIELD_CONFIG) Seluruh controller yang memanggil MaskService
Access Key User T_USER.key DataAccessKeyService dan token evaluator
Temporary Valid Key Memory: validationCache (Map) Cepatnya pengecekan sebelum DB hit
Cryptographic Secret Key KeyService (Alias: aes-key-01) EncryptionService

Known Current Gaps yang Relevan untuk Rework

Gap Current Dampak
Validasi static field sangat tight ke ExistingCurrTrans Tidak bisa mem-mask field khusus dari entity Alert/Case yang tidak di-share dengan Transaksi (kecuali diselipkan di addtData).
Data Access Key Cache per user tidak terhapus saat session diterminasi (hanya clear saat cron) TTL 5 menit menyebabkan zombie validity window bagi token yang direvoke.
Penggunaan literal string "[PROTECTED]" pada field non-String Mutasi skema JSON mendadak dan berisiko merusak type-safety client frontend.
decryptIfEncrypted menangkap root Exception tanpa jejak audit Sangat sulit mendeteksi apakah filter input dari luar memang disengaja salah format atau ada insiden salah enkripsi.
Masking iteratif menggunakan ObjectMapper.convertValue dari Object ke Map pada pagination besar Potensi overhead serialization/deserialization ganda tinggi pada /search yang melist ratusan object.

Endpoint Surface Utama

Surface Endpoint Family Capability
Sensitive Fields Management /sensitive-fields Menambahkan (/add), menghapus (/delete/{fieldName}), melihat field aktif (/), dan melihat field ExistingCurrTrans yang available diregistrasi (/available).
Consumer (Transaction) /existing-transaction/* Memakai header X-Data-Access-Key untuk unmask filter search dan unmask response.
Consumer (Alert Acquirer) /alert-acquirer/* Memakai header mask di endpoint search dan findById.
Consumer (Alert Issuer) /alert-issuer/* Memakai header mask di endpoint search dan findById.
Consumer (Case) /case/* Memakai header mask di endpoint search.

Source Trace

Flow / Area Primary Source
Orchestration & Nested AddtData SecurityConfiguration/Security/Masking/TransactionMaskService.java
Token Generator & Rotation Cron SecurityConfiguration/Security/Key/DataAccessKeyService.java
Field Restriction Logic SecurityConfiguration/Security/Masking/SensitiveFieldConfigService.java
Fallback & Encryption Logic SecurityConfiguration/Security/Encryption/EncryptionService.java
Sensitive Field Controller SecurityConfiguration/Security/Masking/SensitiveFieldConfigController.java
Controller Injection & Unmask Invoke AlertManagement/Case/CaseServiceImpl.java, GeneralComponent/Logic/ExistingCurrTrans/ExistingCurrTransController.java, dll.

Catatan Tambahan (Behavior Khusus)

Saat memparsing endpoint pagination seperti /case/search, applyMaskingToGroupedPagination akan membongkar property bernama alerts di dalam masing-masing baris (apabila tipenya adalah List) dan mem-mask setiap item list tersebut secara terpisah mengandalkan iterasi map manual. Behavior ini spesifik disisipkan di MaskService saat ini agar nested object array tidak terlewat proses screening field aktif.