Hardening API key dan session untuk AI workbench TypeScript berarti membatasi siapa yang bisa memanggil model, tool, dan file eksperimen; memastikan secret tidak bocor; serta mencegah agent menjadi jalur privilege escalation. Untuk aplikasi riset internal, ancamannya bukan hanya penyerang eksternal, tetapi juga token yang tersebar di log, prompt yang memicu tool berbahaya, dan service account yang diberi akses terlalu luas.
Artikel ini membahas pola praktis untuk AI workbench berbasis TypeScript/Bun: pemisahan auth antara user dan service account, penyimpanan secret di environment variable atau secret manager, rotasi key, session cookie yang aman, validasi prompt dan parameter tool, pembatasan upload file, rate limit per user dan per token, audit log, serta isolasi akses tool. Contoh dan checklist di bawah sengaja diarahkan ke sistem internal riset yang mirip pola workbench agentik: UI internal, backend API, koneksi ke LLM, eksekusi tool, dan akses ke artefak eksperimen.
Model ancaman yang relevan untuk AI workbench internal
Sebelum memilih middleware atau header cookie, tetapkan dulu apa yang ingin dicegah. Pada AI workbench internal, beberapa risiko paling umum adalah:
- API key bocor melalui log, error message, file konfigurasi, atau commit repository.
- Session dicuri karena cookie tidak dikonfigurasi aman, masa hidup terlalu panjang, atau tidak ada regenerasi session setelah login.
- Service account disalahgunakan karena satu token dipakai bersama banyak komponen dan memiliki akses terlalu luas.
- Prompt atau parameter tool tidak tervalidasi sehingga agent dapat memanggil tool dengan argumen yang tidak seharusnya.
- Upload file berbahaya yang memicu parsing berisiko, konsumsi storage berlebihan, atau penyelundupan format.
- Abuse ke LLM dan tool berupa spam request, percobaan scraping, token exhaustion, atau loop agent yang mahal.
- Tool agent menjadi jalur eskalasi misalnya model bisa membaca file eksperimen di luar ruang kerja user, atau memanggil shell/database dengan kredensial backend penuh.
Tujuan hardening bukan membuat sistem tidak bisa dipakai, tetapi memperkecil blast radius. Jika satu session, satu token, atau satu agent disalahgunakan, dampaknya harus tetap terbatas pada ruang lingkup yang kecil dan mudah diaudit.
Desain auth: bedakan user session, API key, dan service account
Jangan samakan identitas manusia dengan identitas sistem
Kesalahan umum pada workbench internal adalah memakai satu mekanisme auth untuk semua hal. Praktiknya lebih aman jika Anda membedakan tiga identitas:
- User session untuk interaksi manusia dari browser atau client internal.
- API key pribadi atau token mesin ringan untuk automasi terbatas, misalnya script analisis milik peneliti.
- Service account untuk komunikasi antar-layanan, worker, scheduler, atau executor tool.
Pemisahan ini penting karena kebutuhan kontrolnya berbeda. User session perlu proteksi cookie, CSRF sesuai pola aplikasi, dan revokasi cepat per user. Service account lebih cocok memakai token non-interaktif dengan scope sempit, masa hidup pendek, dan identitas layanan yang jelas di audit log.
Prinsip desain yang disarankan
- Setiap request harus punya principal jelas: user ID, service account ID, atau keduanya jika ada delegation.
- Authorization berbasis aksi dan resource, bukan hanya “sudah login”. Contoh: run:agent, read:experiment-file, upload:artifact, invoke:tool:python-sandbox.
- Service account tidak mewarisi hak admin user kecuali benar-benar dibutuhkan dan terdokumentasi.
- Gunakan kredensial berbeda per komponen. Worker tool, API utama, dan pipeline ingest file sebaiknya tidak berbagi token yang sama.
- Dukung rotasi dan revokasi sejak awal. Token yang tidak bisa diputar tanpa downtime akan menjadi beban operasional.
Contoh model principal di TypeScript
type Principal =
| {
kind: 'user';
userId: string;
sessionId: string;
roles: string[];
scopes: string[];
}
| {
kind: 'service';
serviceAccountId: string;
tokenId: string;
scopes: string[];
};
function can(principal: Principal, action: string, resource: string): boolean {
const needed = `${action}:${resource}`;
return principal.scopes.includes(needed) || principal.scopes.includes(`${action}:*`);
}Contoh di atas sederhana, tetapi menunjukkan satu hal penting: backend jangan menebak-nebak identitas pemanggil. Semua keputusan akses harus berbasis principal yang eksplisit.
Penyimpanan secret dan rotasi API key
Environment variable cukup untuk awal, tetapi bukan untuk semua konteks
Menyimpan secret di environment variable masih lazim dan bisa diterima untuk deployment sederhana, selama:
- secret tidak dikomit ke repository,
- nilai produksi tidak disalin ke file .env lokal sembarangan,
- akses ke environment deployment dibatasi,
- log startup tidak mencetak variabel sensitif.
Namun untuk sistem yang punya beberapa service account, worker, dan kebutuhan rotasi berkala, secret manager lebih aman dan lebih operasional. Secret manager membantu versioning, audit akses secret, dan rotasi tanpa menyebar file baru ke banyak host.
Catatan: Jika Anda masih memakai .env, pisahkan file lokal pengembangan dari rahasia produksi. Jangan gunakan satu file yang berpindah-pindah antara laptop, CI, dan server.
Pola penyimpanan yang disarankan
- Secret inbound: token untuk mengakses API Anda. Simpan hanya bentuk yang sudah di-hash jika token perlu diverifikasi server-side.
- Secret outbound: kredensial untuk memanggil LLM provider, object storage, database, atau sistem eksperimen lain. Simpan di env/secret manager, jangan pernah kirim ke browser atau tool agent tanpa alasan kuat.
- Secret per service account: satu service, satu identitas, satu token atau key pair, satu set scope.
Hash API key, jangan simpan plaintext jika tidak perlu
Untuk API key yang dipakai client memanggil backend Anda, praktik aman adalah menampilkan plaintext hanya sekali saat pembuatan, lalu simpan di database dalam bentuk hash. Saat request masuk, server meng-hash token yang dikirim dan membandingkan hasilnya. Dengan pola ini, kebocoran database tidak otomatis mengungkap token aktif.
type StoredApiKey = {
id: string;
keyPrefix: string;
keyHash: string;
ownerType: 'user' | 'service';
ownerId: string;
scopes: string[];
revokedAt?: string;
expiresAt?: string;
};
async function verifyApiKey(rawKey: string): Promise<StoredApiKey | null> {
const prefix = rawKey.slice(0, 8);
const candidates = await db.apiKeys.findByPrefix(prefix);
for (const key of candidates) {
if (timingSafeEqual(hash(rawKey), key.keyHash) && !key.revokedAt) {
return key;
}
}
return null;
}Mengapa memakai prefix? Karena Anda tidak bisa mencari berdasarkan hash tanpa menghitung ke semua baris. Prefix non-rahasia memudahkan lookup awal, sedangkan verifikasi akhir tetap memakai hash dan perbandingan aman terhadap timing attack.
Rotasi key yang realistis
Rotasi key sering gagal bukan karena teknis hash, tetapi karena aplikasi diasumsikan hanya punya satu key aktif. Untuk menghindari downtime:
- Izinkan lebih dari satu key aktif per service account dalam masa transisi.
- Tambahkan metadata createdAt, lastUsedAt, dan expiresAt.
- Buat prosedur rotasi: create new key → deploy/update consumer → monitor usage → revoke old key.
- Log identitas key, bukan plaintext key.
Untuk secret outbound ke provider LLM, idealnya rotasi dilakukan di secret manager lalu worker memuat ulang konfigurasi secara aman. Hindari mewajibkan restart manual banyak proses jika bisa.
Session cookie yang aman untuk user
Gunakan cookie, bukan menyimpan token session sembarangan di localStorage
Untuk UI web internal, session berbasis cookie biasanya lebih aman dan lebih mudah dikendalikan daripada menyimpan bearer token jangka panjang di localStorage. Cookie memungkinkan atribut transport dan origin yang lebih ketat.
Setidaknya, cookie session sebaiknya memiliki atribut:
- HttpOnly agar tidak bisa dibaca JavaScript di browser.
- Secure agar hanya dikirim lewat HTTPS.
- SameSite yang sesuai kebutuhan aplikasi, biasanya Lax untuk UI internal umum, atau Strict bila alur aplikasi memungkinkan.
- Path yang dibatasi bila relevan.
- Masa hidup terbatas dan didukung server-side revocation.
Jika aplikasi memakai session state di server atau database, simpan hanya ID session acak di cookie. Data sensitif seperti role, scope, dan status MFA sebaiknya divalidasi ulang dari backend atau cache tepercaya, bukan dipercaya penuh dari client.
Regenerasi session dan pengikatan konteks
Regenerasi ID session setelah login atau perubahan privilege membantu mencegah session fixation. Anda juga dapat menyimpan metadata seperti user agent hash, IP kasar, atau device identifier untuk mendeteksi anomali, tetapi jangan terlalu agresif sampai membuat pengguna sah sering terlogout karena perubahan jaringan internal.
type SessionRecord = {
id: string;
userId: string;
createdAt: string;
lastSeenAt: string;
expiresAt: string;
userAgentHash?: string;
revokedAt?: string;
};
async function createSession(userId: string, userAgent?: string) {
const sessionId = crypto.randomUUID();
await db.sessions.insert({
id: sessionId,
userId,
createdAt: new Date().toISOString(),
lastSeenAt: new Date().toISOString(),
expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 8).toISOString(),
userAgentHash: userAgent ? hash(userAgent) : undefined
});
return sessionId;
}Kesalahan yang sering terjadi pada session
- Menyimpan payload otorisasi lengkap di client lalu tidak memeriksa status user lagi di server.
- Tidak ada tombol dan endpoint logout all sessions.
- Cookie valid terlalu lama tanpa idle timeout.
- Session admin dan session peneliti biasa diperlakukan sama.
- Session tidak direvokasi saat password diubah atau hak akses dicabut.
Validasi input prompt dan parameter tool
Prompt bukan SQL, tetapi tetap input tidak tepercaya
Prompt user, instruction agent, dan parameter tool harus diperlakukan sebagai input tidak tepercaya. Bahayanya bukan hanya prompt injection ke model, tetapi juga request yang membuat backend menjalankan tool dengan parameter di luar kebijakan.
Pola aman:
- Pisahkan prompt ke model dari parameter tool terstruktur. Jangan biarkan model menyusun command bebas.
- Validasi schema untuk semua argumen tool: tipe, panjang, enum, batas numerik, daftar path yang diizinkan.
- Terapkan allowlist untuk nama tool yang bisa dipanggil per role atau per workflow.
- Normalisasi input sebelum validasi, misalnya trimming, canonical path, dan pengecekan Unicode anomali bila relevan.
Contoh validasi parameter tool
type RunNotebookToolInput = {
experimentId: string;
notebookName: string;
maxRuntimeSec: number;
};
function validateRunNotebookInput(input: RunNotebookToolInput) {
if (!/^[a-zA-Z0-9_-]{1,64}$/.test(input.experimentId)) {
throw new Error('experimentId tidak valid');
}
if (!/^[a-zA-Z0-9_.-]{1,128}$/.test(input.notebookName)) {
throw new Error('notebookName tidak valid');
}
if (input.maxRuntimeSec < 1 || input.maxRuntimeSec > 600) {
throw new Error('maxRuntimeSec di luar batas');
}
}Validasi seperti ini bekerja karena backend tidak memberi ruang bagi model untuk mengirim argumen arbitrer. Jika butuh path file, validasi harus lebih ketat lagi: gunakan ID artefak atau path virtual, bukan path absolut host.
Filter prompt dan kebijakan konten internal
Tidak semua validasi harus berupa pemblokiran keras. Untuk prompt, Anda bisa menerapkan:
- batas panjang input,
- deteksi upaya menyisipkan secret atau kredensial,
- pemotongan konteks file yang terlalu besar,
- peringatan saat user mencoba meminta agent menampilkan environment variable atau isi file konfigurasi.
Jangan mengandalkan filter prompt sebagai kontrol utama. Kontrol utama tetap ada di layer otorisasi tool dan sandbox eksekusi.
Pembatasan upload file dan penanganan artefak eksperimen
Upload file adalah jalur serangan yang sering diremehkan
AI workbench riset sering menerima notebook, CSV, PDF, gambar, atau arsip hasil eksperimen. Jika semua file diterima tanpa pembatasan, Anda membuka risiko konsumsi storage, parser crash, file berbahaya, dan kebocoran data antar ruang kerja.
Minimal, terapkan:
- batas ukuran file per request dan per user,
- allowlist tipe file berdasarkan kebutuhan nyata, bukan menerima apa pun,
- validasi MIME dan ekstensi, serta bila perlu inspeksi signature file,
- penyimpanan terpisah antara metadata database dan blob file,
- nama file acak di storage backend, bukan nama asli sebagai path utama,
- scan atau quarantine untuk format berisiko tinggi jika organisasi Anda mensyaratkan.
Batasi akses file berdasarkan workspace atau experiment
File eksperimen sebaiknya dipetakan ke resource yang jelas: workspace, project, atau experiment. Agent tidak boleh bisa membaca file hanya karena backend punya kredensial storage penuh. Setiap pembacaan file oleh tool harus memeriksa apakah principal punya hak terhadap resource tersebut.
async function fetchExperimentFile(principal: Principal, experimentId: string, fileId: string) {
if (!can(principal, 'read', `experiment:${experimentId}`)) {
throw new Error('forbidden');
}
const file = await db.files.findById(fileId);
if (!file || file.experimentId !== experimentId) {
throw new Error('not found');
}
return storage.getObject(file.storageKey);
}Poin pentingnya: cek otorisasi sebelum akses storage. Jangan langsung percaya bahwa file ID yang valid berarti boleh dibaca.
Rate limit dan abuse prevention untuk LLM, tool, dan upload
Rate limit harus ada di beberapa dimensi
Untuk AI workbench, satu rate limit global hampir selalu tidak cukup. Yang lebih berguna adalah kombinasi beberapa batas:
- per user: mencegah satu akun menghabiskan kapasitas bersama,
- per API key atau session: membatasi kebocoran satu token,
- per IP atau network segment: berguna sebagai sinyal tambahan, terutama untuk endpoint publik atau semi-publik,
- per jenis aksi: chat LLM, upload file, tool invocation, dan download artefak punya karakteristik berbeda,
- concurrency limit: membatasi jumlah job agent aktif per principal.
Pada endpoint LLM, lebih berguna jika Anda juga membatasi estimasi biaya atau token, bukan hanya jumlah request. Satu request bisa jauh lebih mahal daripada sepuluh request kecil.
Pola implementasi
Simpan counter di store terpusat ber-latensi rendah, lalu gunakan kunci seperti:
rl:user:{userId}:chat:{window}rl:key:{tokenId}:tool:{window}concurrency:user:{userId}:agent
Untuk tool agent, limit concurrency sering lebih penting daripada request per menit karena job bisa berlangsung lama dan mengikat resource CPU, memory, atau quota provider eksternal.
Respons yang aman saat limit terlampaui
Saat limit terlampaui:
- kembalikan status yang sesuai,
- jangan membocorkan detail internal quota layanan lain,
- catat principal, endpoint, dan kategori limit,
- jika perlu, naikkan level observabilitas untuk token atau user yang sama.
Kesalahan umum adalah hanya menolak request tanpa audit. Padahal lonjakan limit sering menjadi sinyal awal penyalahgunaan atau bug loop agent.
Audit log yang berguna untuk forensik, bukan sekadar log akses
Apa yang perlu dicatat
Audit log untuk AI workbench sebaiknya menjawab pertanyaan: siapa menjalankan apa, terhadap resource mana, memakai kredensial apa, dan hasilnya apa. Minimum event yang berguna:
- login, logout, dan revokasi session,
- pembuatan, penggunaan, rotasi, dan revokasi API key,
- pemanggilan endpoint sensitif,
- tool invocation beserta nama tool, principal, experiment/workspace, dan status,
- upload, download, dan penghapusan file,
- perubahan role, scope, atau kebijakan akses.
Hindari mencatat secret, cookie, plaintext API key, atau seluruh prompt sensitif tanpa kontrol. Jika prompt perlu diaudit, pertimbangkan redaksi parsial, hashing, atau penyimpanan terpisah dengan akses lebih ketat.
Struktur audit event
type AuditEvent = {
ts: string;
actorType: 'user' | 'service';
actorId: string;
sessionId?: string;
tokenId?: string;
action: string;
resourceType: string;
resourceId: string;
outcome: 'allowed' | 'denied' | 'error';
requestId: string;
metadata?: Record<string, string | number | boolean>;
};Dengan struktur seperti ini, Anda bisa menghubungkan satu request dari gateway, API, worker, hingga executor tool menggunakan requestId atau traceId.
Isolasi tool: cegah agent menjadi jalur privilege escalation
Masalah inti: model tidak boleh mewarisi privilege backend penuh
Ini titik paling kritis pada AI workbench. Backend Anda mungkin memiliki akses ke secret manager, storage eksperimen, database, atau executor komputasi. Jika agent dapat memanggil tool melalui backend tanpa pembatasan tegas, model praktis mewarisi seluruh hak backend.
Pola yang lebih aman:
- tool registry dengan allowlist eksplisit,
- scope per tool dan per principal,
- argumen tool tervalidasi schema,
- eksekusi tool di sandbox atau worker terisolasi,
- kredensial terpisah per worker/tool, bukan satu token superuser,
- hasil tool disanitasi sebelum dikembalikan ke model atau UI.
Jangan berikan shell umum jika sebenarnya butuh operasi spesifik
Anti-pattern yang sering terjadi adalah memberi agent akses ke shell atau interpreter umum, padahal kebutuhan bisnis hanya “jalankan notebook yang sudah disetujui”, “ambil metrik eksperimen”, atau “baca file artefak tertentu”. Semakin sempit permukaan tool, semakin mudah diamankan dan diaudit.
Daripada:
- tool runCommand(command: string)
Lebih aman memakai:
- tool runNotebook(experimentId, notebookName, maxRuntimeSec)
- tool readArtifact(experimentId, artifactId)
- tool searchExperimentNotes(workspaceId, query, limit)
Delegasi yang aman
Jika worker perlu bertindak atas nama user, gunakan prinsip delegation with restriction: worker menerima identitas user, tetapi hanya untuk scope tertentu dan untuk durasi terbatas. Jangan teruskan session cookie user ke executor. Buat token internal jangka pendek yang memuat claim minimal, misalnya resource dan aksi yang diizinkan.
Contoh alur request yang lebih aman
- User login ke UI internal dan menerima session cookie dengan HttpOnly, Secure, dan SameSite yang sesuai.
- UI mengirim request ke endpoint /agent/run dengan prompt, ID eksperimen, dan opsi yang diperbolehkan.
- API memuat session, membentuk principal user, mengecek apakah user boleh menjalankan agent pada eksperimen tersebut.
- API memvalidasi input: panjang prompt, daftar tool yang boleh dipakai, batas file context, dan parameter numerik.
- API menerapkan rate limit per user dan per session, lalu membuat requestId untuk observabilitas.
- Agent planner hanya menerima daftar tool yang sudah di-allowlist untuk principal itu.
- Saat model meminta tool, backend memvalidasi ulang nama tool dan argumennya terhadap schema.
- Tool dieksekusi di worker terisolasi dengan service account khusus dan scope sempit, misalnya hanya bisa membaca artefak dari eksperimen tertentu.
- Semua event penting diaudit: siapa menjalankan agent, tool apa yang dipakai, file mana yang dibaca, apakah ada penolakan akses, dan berapa estimasi penggunaan token.
- Hasil dikembalikan ke user setelah disanitasi seperlunya dan tanpa membocorkan secret internal atau path host.
Perhatikan bahwa otorisasi terjadi lebih dari sekali: di awal request, saat akses resource, dan saat tool invocation. Ini bukan duplikasi yang sia-sia; ini pertahanan berlapis.
Checklist implementasi hardening API key dan session
- Bedakan principal user dan service account.
- Terapkan scope dan otorisasi berbasis aksi-resource.
- Simpan API key inbound dalam bentuk hash, bukan plaintext.
- Gunakan lebih dari satu key aktif saat rotasi.
- Simpan secret outbound di env yang terkendali atau secret manager.
- Pastikan session cookie memakai HttpOnly, Secure, dan SameSite yang sesuai.
- Regenerasi session setelah login dan perubahan privilege.
- Terapkan idle timeout dan mekanisme revokasi session.
- Validasi semua parameter tool dengan schema ketat.
- Jangan berikan tool umum seperti shell jika operasi bisa dibuat spesifik.
- Batasi upload file berdasarkan ukuran, tipe, dan resource owner.
- Terapkan rate limit per user, per token, dan concurrency untuk job agent.
- Catat audit log untuk login, key usage, tool invocation, file access, dan perubahan role.
- Gunakan requestId/traceId untuk menghubungkan log API dan worker.
- Sanitasi output tool dan jangan log secret atau prompt sensitif mentah tanpa kontrol.
Anti-pattern yang sering terjadi
- Satu API key untuk semua service sehingga tidak ada isolasi dan sulit rotasi.
- Bearer token disimpan di localStorage untuk session web internal tanpa alasan kuat.
- Backend meneruskan secret provider ke browser agar client memanggil LLM langsung tanpa kontrol.
- Tool agent membaca file berdasarkan path mentah dari model atau user.
- Worker tool berjalan dengan kredensial database atau storage superuser.
- Tidak ada rate limit untuk endpoint agent karena diasumsikan hanya dipakai internal.
- Audit log terlalu miskin konteks sehingga tidak bisa menjawab siapa melakukan apa.
- Prompt dianggap cukup untuk membatasi perilaku agent tanpa enforcement di backend.
Debugging dan verifikasi keamanan
Apa yang perlu diuji
- Coba gunakan API key yang sudah direvokasi: apakah benar ditolak di semua endpoint?
- Coba akses file eksperimen lain dengan file ID valid: apakah otorisasi tetap menolak?
- Coba minta model memanggil tool yang tidak di-allowlist: apakah backend menolak?
- Coba upload file terlalu besar atau tipe terlarang: apakah pipeline berhenti lebih awal?
- Coba spam endpoint agent dengan satu session dan banyak concurrency: apakah limit bekerja dan tercatat di audit?
Indikator observabilitas yang berguna
- jumlah penolakan auth dan authorization per endpoint,
- penggunaan API key berdasarkan token ID,
- rasio tool invocation yang gagal validasi schema,
- job agent aktif per user/service account,
- anomali akses file lintas workspace atau eksperimen.
Hardening yang baik bukan hanya soal menolak request, tetapi juga memudahkan Anda menjelaskan mengapa request ditolak dan apa dampaknya jika ada penyalahgunaan.
Penutup
Pada AI workbench TypeScript/Bun, keamanan tidak berhenti di login. Hardening API key dan session harus terhubung langsung ke desain otorisasi, isolasi tool, kontrol upload file, rate limit, dan audit log. Jika agent dapat menyentuh LLM, file eksperimen, dan tool komputasi, maka kontrol paling penting adalah mempersempit hak akses setiap komponen dan memverifikasi ulang setiap transisi dari prompt ke aksi nyata.
Mulailah dari hal yang dampaknya paling besar: pisahkan user dan service account, hash API key, kencangkan session cookie, validasi parameter tool dengan schema ketat, dan hilangkan tool generik yang tidak perlu. Setelah itu, tambahkan rotasi secret, audit log yang benar-benar bisa dipakai, serta rate limit berbasis user dan token agar sistem riset internal tetap aman tanpa menghambat kerja tim.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!