Praktik membagikan satu kredensial skema database (shared account) ke banyak microservice, backend worker, dan teknisi DBA/developer menimbulkan celah keamanan kritis. Saat akun skema monolitik seperti APP_OWNER disusupi atau terjadi query destruktif, audit trail tidak dapat menentukan aktor sebenarnya karena semua entitas berbagi kredensial yang sama. Oracle Database menyediakan mekanisme Proxy Authentication melalui klausa CONNECT THROUGH untuk mengatasi masalah ini secara langsung di layer database.

Risiko Keamanan Akun Skema Monolitik

Pada arsitektur tradisional, backend terhubung langsung sebagai pemilik tabel (schema owner). Pola ini memiliki risiko signifikan:

  • Blast Radius Berlebihan: Akun pemilik skema biasanya memiliki hak DROP, TRUNCATE, atau modifikasi DDL lainnya. Akses aplikasi seharusnya dibatasi hanya pada DML tertentu.
  • Kehilangan Jejak Audit: Log standar database mencatat nama user yang sama untuk ratusan instance layanan yang berbeda, mempersulit investigasi pasca-insiden (forensik).
  • Rotasi Kredensial Sulit: Mengubah password skema utama berisiko mematikan seluruh ekosistem layanan secara simultan karena dependensi password bersama.

Step 1: Amankan Skema Data (Data Schema)

Langkah awal adalah mencegah koneksi langsung ke skema data menggunakan password. Akun data harus bertindak murni sebagai wadah objek (schema container).

Pada Oracle Database versi 21c ke atas, gunakan klausa NO AUTHENTICATION:

-- Oracle 21c+ syntax
CREATE USER app_data NO AUTHENTICATION;
GRANT CREATE TABLE, CREATE VIEW, CREATE SEQUENCE TO app_data;
ALTER USER app_data QUOTA UNLIMITED ON users;

Untuk Oracle Database 19c ke bawah yang belum mendukung NO AUTHENTICATION, kunci akun tersebut setelah pembuatan:

-- Oracle 19c dan versi sebelumnya
CREATE USER app_data IDENTIFIED BY "RandomStr0ngP@ssw0rd!Generated" ACCOUNT LOCK;
GRANT CREATE TABLE, CREATE VIEW, CREATE SEQUENCE TO app_data;
ALTER USER app_data QUOTA UNLIMITED ON users;
Status ACCOUNT LOCK memblokir autentikasi password langsung dari client, tetapi akun tetap dapat diakses melalui jalur proxy resmi.

Step 2: Konfigurasi Proxy User Tingkat Aplikasi

Buat akun perantara terpisah untuk setiap aplikasi atau service. Akun ini hanya membutuhkan hak dasar CREATE SESSION dan tidak memerlukan kuota tablespace atau kepemilikan tabel.

-- Buat proxy user spesifik untuk service pembayaran
CREATE USER svc_payment_app IDENTIFIED BY "PaymentSvcSecurePass#2026";
GRANT CREATE SESSION TO svc_payment_app;

-- Buat proxy user untuk background job reporting
CREATE USER svc_reporting_job IDENTIFIED BY "ReportWorkerSecretKey#2026";
GRANT CREATE SESSION TO svc_reporting_job;

Step 3: Autorisasi Hak CONNECT THROUGH

Beri wewenang kepada proxy user untuk bertindak atas nama skema data target menggunakan perintah ALTER USER ... GRANT CONNECT THROUGH.

-- Mengizinkan svc_payment_app bertindak atas nama app_data
ALTER USER app_data GRANT CONNECT THROUGH svc_payment_app;

-- Verifikasi delegasi hak proxy pada data dictionary
SELECT client, proxy, flags 
FROM user_proxies;

Katalog USER_PROXIES (atau DBA_PROXIES) akan menampilkan pemetaan hubungan antara akun target (client) dan akun perantara (proxy).

Step 4: Verifikasi Session dan Audit Trail

Pengujian koneksi via SQL*Plus atau Oracle Client CLI menggunakan sintaks proxy_user[schema_user]:

sqlplus svc_payment_app[app_data]/"PaymentSvcSecurePass#2026"@//localhost:1521/XEPDB1

Validasi pemisahan identitas dengan memeriksa variabel konteks bawaan database:

SELECT 
    SYS_CONTEXT('USERENV', 'SESSION_USER') AS current_schema_scope,
    SYS_CONTEXT('USERENV', 'PROXY_USER')   AS authenticated_proxy,
    SYS_CONTEXT('USERENV', 'OS_USER')      AS client_os_user,
    SYS_CONTEXT('USERENV', 'IP_ADDRESS')   AS client_ip
FROM dual;

Hasil eksekusi:

  • SESSION_USER menghasilkan APP_DATA. Seluruh query SQL resolver otomatis mengarah ke tabel di bawah skema APP_DATA tanpa perlu menambahkan prefix skema (misal: SELECT * FROM orders bukan SELECT * FROM app_data.orders).
  • PROXY_USER menghasilkan SVC_PAYMENT_APP. Catatan audit dan trigger audit menangkap identitas ini sebagai penanggung jawab koneksi.

Pemeriksaan pada dynamic performance view V$SESSION:

SELECT 
    sid, 
    serial#, 
    username, 
    osuser, 
    machine, 
    program,
    con_id
FROM v$session 
WHERE username = 'APP_DATA';

Step 5: Integrasi pada Backend Connection Pool

Pada framework modern seperti Spring Boot atau backend Node.js, integrasi proxy user dapat diterapkan langsung pada level URL koneksi JDBC atau programmatic API.

Contoh Format JDBC URL (HikariCP / Oracle Thin Driver)

spring.datasource.url=jdbc:oracle:thin:@//dbhost.internal:1521/ORCLPDB1
spring.datasource.username=svc_payment_app[app_data]
spring.datasource.password=PaymentSvcSecurePass#2026
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver

Contoh Programmatic API (Oracle Universal Connection Pool - UCP)

UCP mendukung pembukaan session proxy di atas koneksi fisik yang sudah ada, mengeliminasi biaya re-handshake TCP/TLS:

import oracle.ucp.jdbc.PoolDataSource;
import oracle.jdbc.OracleConnection;
import java.util.Properties;

// Mendapatkan physical connection dari pool
OracleConnection conn = (OracleConnection) pds.getConnection();

// Konfigurasi atribut proxy
Properties proxyProps = new Properties();
proxyProps.setProperty(OracleConnection.PROXY_USER_NAME, "app_data");

// Membuka proxy session
conn.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, proxyProps);

// Eksekusi transaksi...

// Tutup session proxy sebelum koneksi dikembalikan ke pool
conn.close(OracleConnection.PROXY_SESSION);

Konfigurasi Role Spesifik dan Trade-Off

Secara default, proxy user yang tersambung memiliki semua role default milik client/schema. Untuk membatasi prinsip least privilege, delegasi dapat dibatasi dengan klausa WITH ROLE.

-- 1. Buat role khusus read-only
CREATE ROLE role_reporting;
GRANT SELECT ON app_data.transactions TO role_reporting;

-- 2. Berikan izin proxy HANYA untuk role tertentu
ALTER USER app_data GRANT CONNECT THROUGH svc_reporting_job 
    WITH ROLE role_reporting;

Pertimbangan Implementasi:

  • Role Inactivity: Jika klausa WITH ROLE diterapkan, Oracle menonaktifkan seluruh default role milik target schema, kecuali role yang secara eksplisit dicantumkan. Pastikan dependensi role seperti RESOURCE diatur dengan teliti.
  • Stored Procedure Execution: Stored procedure yang menggunakan mode Definer's Rights (default) tetap dieksekusi dengan privilege pembuat procedure, terlepas dari pembatasan role pada proxy session. Gunakan Invoker's Rights (AUTHID CURRENT_USER) jika ingin pembatasan role proxy berlaku di dalam PL/SQL unit.
  • Connection Pool Recycling: Jika menggunakan programmatic proxy switching pada pool, pastikan koneksi membersihkan proxy state (close(OracleConnection.PROXY_SESSION)) untuk menghindari context-bleeding antar-request thread.