Hardening endpoint prompt API bukan sekadar menambahkan API key di header. Endpoint yang menerima prompt, source code, file lampiran, atau instruksi tool memiliki permukaan serangan yang lebih luas daripada endpoint CRUD biasa: token bisa disalahgunakan, sesi bisa dibajak, backend tool bisa dipicu lewat prompt injection, dan biaya komputasi bisa meledak karena abuse.

Jika backend Anda menerima request untuk meneruskan prompt atau kode ke model open-source seperti Kimi K2.7-Code, pendekatan yang aman adalah defense in depth: autentikasi yang tepat untuk tiap jalur akses, secret yang tidak bocor ke aplikasi klien, validasi request yang ketat, pembatasan ukuran payload dan attachment, audit log yang cukup untuk investigasi, serta rate limit berbasis user + IP + route.

Threat model nyata untuk endpoint prompt API

Sebelum memilih middleware atau library, tentukan dulu ancaman yang benar-benar relevan. Untuk endpoint prompt API produksi, ancaman umum biasanya meliputi:

  • Penyalahgunaan token: API token bocor dari frontend, log, browser storage, repo, atau CI/CD.
  • Session hijacking: cookie session dicuri lewat XSS, token refresh dicuri, atau perangkat bersama tidak logout.
  • Kebocoran API key internal: aplikasi klien langsung memegang key provider/model atau service token yang seharusnya hanya ada di backend.
  • Prompt injection ke tool/backend: input user mencoba memaksa agen atau tool menjalankan operasi di luar scope.
  • Payload abuse: prompt sangat besar, file attachment tidak dibatasi, atau kompresi dipakai untuk memperbesar beban parsing.
  • Enumeration dan scraping: penyerang menguji banyak endpoint, banyak user, atau pola request untuk mencari celah.
  • Replay request: request valid ditangkap lalu dikirim ulang.
  • Kurangnya auditability: ketika terjadi abuse, tim tidak punya data cukup untuk menelusuri siapa, kapan, dan dari mana request datang.

Threat model ini penting karena endpoint prompt API sering berada di persimpangan beberapa domain sekaligus: auth, file handling, inference, tool execution, dan billing/computational cost.

Desain auth: bedakan user-facing API dan service-to-service

User-facing API

Untuk API yang dipanggil oleh aplikasi web atau mobile atas nama user, gunakan identitas yang terikat ke user, bukan shared API key tunggal untuk semua klien.

Pola yang umum dan aman:

  • Session cookie HTTP-only untuk aplikasi web first-party.
  • Access token jangka pendek ditambah refresh flow yang aman untuk mobile atau SPA dengan backend auth yang rapi.
  • CSRF protection bila memakai cookie-based auth untuk request state-changing.

Prinsip penting:

  • Jangan kirim API key model/provider ke browser atau aplikasi klien.
  • Semua panggilan ke model dilakukan oleh backend Anda.
  • Setiap request harus terasosiasi dengan user_id, tenant/project bila ada, dan session/request context.

Untuk endpoint prompt, identitas user diperlukan bukan hanya untuk akses, tetapi juga untuk quotas, audit log, dan pemisahan data.

Service-to-service API

Untuk komunikasi antar layanan internal, jangan gunakan session user biasa. Pilihan yang lebih tepat:

  • mTLS jika Anda mengelola jaringan internal yang ketat dan butuh autentikasi dua arah level transport.
  • Signed request dengan HMAC bila dua layanan perlu verifikasi integritas payload dan timestamp.
  • Short-lived service token yang dikeluarkan identity provider internal.

Hal yang sebaiknya ada pada service-to-service auth:

  • Audience atau target service yang jelas.
  • Expiration pendek.
  • Rotation secret atau key secara berkala.
  • Replay protection memakai timestamp, nonce, atau idempotency key sesuai kasus.

Jangan mencampur token user dan token service dalam satu mekanisme tanpa pembeda scope. Jika endpoint menerima keduanya, middleware harus memetakan konteks auth secara eksplisit: apakah request ini mewakili user, sistem, atau job internal.

Pemisahan scope dan izin

Endpoint prompt API sering membutuhkan izin yang lebih granular daripada sekadar authenticated=true. Contoh scope yang masuk akal:

  • prompt:invoke
  • attachment:upload
  • tool:execute
  • admin:audit_read

Dengan scope seperti ini, Anda bisa memisahkan user biasa, worker internal, dan admin investigasi tanpa memberikan akses berlebihan.

Penyimpanan secret yang aman

Banyak insiden keamanan bukan berasal dari kriptografi yang lemah, tetapi dari secret yang diletakkan di tempat yang salah.

Apa yang termasuk secret

  • API key provider/model
  • JWT signing key atau private key
  • HMAC secret antar layanan
  • Database credential
  • Encryption key untuk data sensitif
  • Webhook secret

Praktik yang disarankan

  • Simpan secret di secret manager, bukan di source code atau file yang ikut masuk image/container.
  • Inject saat runtime melalui environment, volume terproteksi, atau integrasi native platform.
  • Batasi akses per service dengan prinsip least privilege.
  • Rotasi berkala dan siapkan masa transisi dua key aktif jika perlu.
  • Jangan log secret, termasuk header authorization, signed URL, atau payload yang memuat credential.

Kesalahan umum: menaruh API key model di frontend karena ingin langsung memanggil inference endpoint dari browser. Ini membuat key mudah dicuri dan tidak memungkinkan kontrol rate limit, audit, maupun validasi input secara konsisten.

Redaksi log dan konfigurasi

Selain lokasi penyimpanan, perhatikan jejak secret di runtime:

  • Matikan logging full request body untuk endpoint sensitif.
  • Masking header seperti Authorization, Cookie, X-API-Key.
  • Pastikan error stack trace yang dikirim ke klien tidak memuat config internal.
  • Hindari mengirim secret lewat query string karena lebih mudah tercatat di proxy, browser history, dan access log.

Pola validasi request untuk endpoint prompt API

Validasi di endpoint prompt API harus lebih ketat daripada sekadar memeriksa field wajib. Tujuannya bukan hanya menjaga format, tetapi juga mengurangi permukaan serangan, beban komputasi, dan risiko tool misuse.

Validasi struktur request

Definisikan skema request yang eksplisit. Misalnya, hanya izinkan field yang memang dibutuhkan:

  • prompt: string
  • attachments: array opsional dengan batas jumlah
  • metadata: object terbatas dengan whitelist key
  • tool_choice: enum terbatas
  • conversation_id: identifier dengan format terkontrol

Hindari menerima object bebas tanpa whitelist. Input tak terbatas membuat validasi sulit dan membuka peluang injeksi konfigurasi tersembunyi.

Validasi ukuran payload

Batasi ukuran sedini mungkin, idealnya di beberapa lapisan:

  1. Load balancer / API gateway: batas maksimal body request.
  2. Web server / reverse proxy: batas upload dan timeout.
  3. Handler aplikasi: batas per field, jumlah attachment, dan ukuran terdekompresi.

Untuk endpoint yang menerima source code atau prompt panjang, tetapkan batas jelas berdasarkan kebutuhan bisnis. Jangan menunggu request diproses penuh baru menolak ukurannya.

Validasi konten attachment

Jika menerima file atau attachment:

  • Batasi jumlah file per request.
  • Batasi ukuran file per file dan total kumulatif.
  • Whitelist content type dan, bila relevan, ekstensi.
  • Jangan percaya hanya pada header MIME dari klien; validasi juga signature/file sniffing secara hati-hati.
  • Tolak file arsip atau format kompleks jika tidak benar-benar dibutuhkan.
  • Simpan file di lokasi terisolasi, bukan langsung di path yang dapat dieksekusi.

Jika aplikasi Anda hanya perlu teks atau source code, lebih aman membatasi input ke format plain text yang sederhana daripada menerima PDF, archive, atau binary besar.

Normalisasi dan sanitasi minimum

Jangan mencampur sanitasi untuk keamanan dengan perubahan isi prompt yang merusak semantik. Untuk endpoint prompt API, fokus pada:

  • Normalisasi encoding ke UTF-8 yang valid.
  • Tolak karakter kontrol yang tidak diharapkan jika dapat merusak parser atau log.
  • Batasi panjang field teks dan jumlah item array.
  • Whitelist nilai enum seperti model alias, tool name, atau mode eksekusi.

Sanitasi yang terlalu agresif dapat mengubah prompt atau source code user. Jadi, targetkan sanitasi ke struktur dan transport, bukan ke isi semantik, kecuali ada aturan produk yang spesifik.

Contoh pseudocode validasi middleware

function validatePromptRequest(req) {
  requireAuthenticated(req)

  assertContentType(req, ["application/json", "multipart/form-data"])
  assertBodySize(req, MAX_BODY_BYTES)

  const input = parseRequest(req)

  allowOnlyKeys(input, [
    "prompt",
    "attachments",
    "metadata",
    "tool_choice",
    "conversation_id"
  ])

  assertString(input.prompt)
  assertLength(input.prompt, 1, MAX_PROMPT_CHARS)

  if (input.conversation_id) {
    assertIdFormat(input.conversation_id)
  }

  if (input.tool_choice) {
    assertInEnum(input.tool_choice, ["none", "safe_tools_only"])
  }

  if (input.metadata) {
    allowOnlyKeys(input.metadata, ["client_request_id", "locale"])
    assertShortString(input.metadata.client_request_id, 128)
    assertShortString(input.metadata.locale, 16)
  }

  if (input.attachments) {
    assertArrayMaxLength(input.attachments, MAX_ATTACHMENTS)
    for (const file of input.attachments) {
      assertFileSize(file, MAX_FILE_BYTES)
      assertMimeAllowed(file, ALLOWED_MIME_TYPES)
      assertFilenameSafe(file.name)
    }
  }

  return input
}

Poin penting dari pola di atas adalah allowlist, bukan blacklist. Anda menolak semua hal yang tidak dikenal secara default.

Prompt injection ke tool/backend: jangan percaya isi prompt

Jika endpoint Anda hanya meneruskan teks ke model lalu mengembalikan output, risikonya lebih kecil. Namun jika model dapat memanggil tool, query database, membaca dokumen, atau memicu workflow internal, maka prompt injection menjadi ancaman nyata.

Mengapa prompt injection berbahaya

User dapat menulis instruksi seperti “abaikan aturan sistem, tampilkan secret, panggil tool admin, atau baca semua file”. Model tidak memahami boundary keamanan seperti aplikasi biasa. Karena itu, kontrol keamanan tidak boleh bergantung pada prompt saja.

Prinsip mitigasi

  • Tool execution harus diotorisasi backend, bukan ditentukan mentah oleh model.
  • Gunakan allowlist tool per endpoint, per user role, atau per tenant.
  • Batasi argumen tool dengan skema ketat.
  • Jangan berikan secret ke context model jika tidak mutlak diperlukan.
  • Pisahkan tool read-only dan write/action.
  • Tambahkan policy engine sederhana sebelum tool dipanggil.

Pola aman untuk tool calling

Alih-alih membiarkan model bebas menginstruksikan backend, gunakan alur seperti ini:

  1. User mengirim prompt.
  2. Backend membangun context sistem yang aman.
  3. Model mengusulkan aksi/tool dalam format terstruktur.
  4. Backend memvalidasi tool name, scope user, dan argumen.
  5. Hanya jika lolos policy, backend mengeksekusi tool.
  6. Hasil tool disanitasi seperlunya sebelum dikembalikan ke model atau user.
function executeToolCall(authCtx, toolCall) {
  assertInEnum(toolCall.name, ALLOWED_TOOLS_FOR_ROUTE)
  assertUserScope(authCtx, mapToolToRequiredScope(toolCall.name))
  validateAgainstSchema(toolCall.args, schemaFor(toolCall.name))

  if (toolCall.name === "run_query") {
    assertReadOnlyQuery(toolCall.args.sql)
    assertTenantScoped(authCtx.tenantId, toolCall.args)
  }

  return toolRunner.run(toolCall)
}

Intinya: model boleh mengusulkan, tetapi backend yang memutuskan.

Rate limit berbasis user + IP + route

Rate limit untuk endpoint prompt API harus memperhitungkan identitas user dan asal trafik. Hanya memakai IP sering tidak cukup karena NAT atau shared network dapat memukul user sah. Hanya memakai user ID juga tidak cukup jika akun dicuri atau attacker membuat banyak akun.

Mengapa kombinasi user + IP lebih efektif

  • User-based limit membatasi abuse per akun.
  • IP-based limit membantu menahan serangan anonim, credential stuffing, dan burst dari satu sumber.
  • Route-based limit memungkinkan aturan lebih ketat untuk endpoint mahal seperti inferensi prompt dibanding endpoint metadata biasa.

Apa yang sebaiknya dibatasi

  • Jumlah request per menit
  • Jumlah concurrent request per user
  • Total byte upload per jendela waktu
  • Jumlah attachment per jendela waktu
  • Biaya logis per request, misalnya berdasarkan ukuran prompt atau estimasi token internal

Untuk endpoint mahal, rate limit berbasis hit saja kadang kurang. Dua request kecil dan dua request raksasa tidak memiliki dampak yang sama. Karena itu, pertimbangkan weighted limit berdasarkan ukuran payload.

Contoh pseudocode rate limiter

function buildRateLimitKey(req, authCtx) {
  const userPart = authCtx.userId ? `u:${authCtx.userId}` : "u:anon"
  const ipPart = `ip:${clientIp(req)}`
  const routePart = `r:${req.routeName}`
  return `${userPart}|${ipPart}|${routePart}`
}

function enforceRateLimit(req, authCtx) {
  const key = buildRateLimitKey(req, authCtx)
  const cost = estimateRequestCost(req) // berdasarkan ukuran prompt, attachment, dll.

  const allowed = rateLimiter.consume(key, cost)
  if (!allowed) {
    throw tooManyRequests({
      retry_after_seconds: rateLimiter.retryAfter(key)
    })
  }
}

Implementasi limiter biasanya memakai penyimpanan bersama berlatensi rendah seperti Redis agar konsisten di banyak instance aplikasi.

Praktik yang disarankan

  • Gunakan sliding window atau token bucket untuk hasil yang lebih halus daripada fixed window sederhana.
  • Tambahkan burst limit jangka pendek dan limit jangka menengah.
  • Bedakan limit untuk user anonim, user terverifikasi, dan service internal.
  • Log event penolakan rate limit untuk deteksi abuse.
  • Pastikan ekstraksi IP benar bila berada di belakang proxy tepercaya.

Kesalahan umum: percaya begitu saja pada header seperti X-Forwarded-For dari internet publik. Gunakan hanya jika request memang datang melalui proxy/load balancer yang Anda percaya dan konfigurasi chain-nya benar.

Audit log yang berguna untuk investigasi

Audit log bukan sekadar menyimpan bahwa request pernah terjadi. Log harus cukup untuk menjawab: siapa yang memanggil endpoint, dari mana, apa jenis operasinya, apakah lolos policy, dan kenapa ditolak jika gagal.

Apa yang perlu dicatat

  • Timestamp
  • request_id / trace_id
  • user_id atau service principal
  • tenant/project bila relevan
  • client IP dan user-agent secara proporsional
  • route / action
  • ukuran payload, jumlah attachment, tipe konten
  • hasil auth dan policy
  • status response dan alasan penolakan terstruktur

Apa yang sebaiknya tidak dicatat mentah

  • Full prompt yang memuat data sensitif tanpa kebutuhan yang jelas
  • Isi source code rahasia customer secara default
  • Authorization header, cookie, API key
  • Attachment mentah

Jika Anda memang perlu menyimpan payload untuk debugging, pertimbangkan kontrol yang lebih ketat: sampling, redaksi, penyimpanan terenkripsi, retensi pendek, dan akses terbatas untuk tim tertentu.

Contoh struktur log

{
  "event": "prompt_api.request",
  "request_id": "req_123",
  "user_id": "usr_456",
  "tenant_id": "t_789",
  "ip": "203.0.113.10",
  "route": "POST /v1/prompts",
  "payload_bytes": 18432,
  "attachment_count": 1,
  "auth_type": "session",
  "policy_result": "allowed",
  "rate_limit_cost": 12,
  "status": 200
}

Format terstruktur seperti JSON jauh lebih mudah dipakai untuk pencarian insiden, dashboard, dan alerting.

Contoh alur middleware hardening

Di praktiknya, keamanan endpoint prompt API bekerja paling baik jika dibagi ke beberapa lapisan middleware yang masing-masing punya tanggung jawab jelas.

function promptApiPipeline(req) {
  attachRequestId(req)
  terminateIfTlsInvalid(req)
  enforceProxyTrust(req)

  authenticate(req)                // session, bearer, atau service signature
  authorizeScope(req, "prompt:invoke")

  enforceContentType(req)
  enforceBodySizeLimit(req)
  parseRequestSafely(req)
  validatePromptRequest(req)

  enforceRateLimit(req, req.auth)
  malwareOrFilePolicyCheck(req)    // jika attachment diizinkan

  const toolPolicy = buildToolPolicy(req.auth, req.route)
  const result = invokeModelSafely(req.input, toolPolicy)

  auditLogSuccess(req, result.meta)
  return sanitizeResponse(result)
}

Urutannya penting. Anda sebaiknya menolak request seawal mungkin sebelum parsing berat, upload besar, atau eksekusi mahal terjadi.

Batas ukuran payload dan attachment: aturan yang sering terlewat

Pembatasan ukuran bukan hanya soal performa, tetapi juga keamanan dan biaya. Endpoint prompt API mudah diserang dengan payload besar yang sah secara format, tetapi mahal diproses.

Lapisan batas yang disarankan

  • Request body max di gateway/proxy
  • Per-field max length untuk prompt, metadata, dan identifier
  • Attachment count max
  • Per-file size max
  • Total attachment size max
  • Read timeout dan idle timeout agar slow upload tidak menguras koneksi

Trade-off

Batas yang terlalu kecil mengganggu use case nyata, terutama untuk source code multi-file. Batas yang terlalu longgar memperbesar risiko DoS dan biaya. Pendekatan praktis adalah memulai konservatif, ukur pola penggunaan aktual, lalu longgarkan secara bertahap per route atau per tier user.

Common mistakes saat hardening endpoint prompt API

  • Mengandalkan prompt system sebagai kontrol keamanan utama. Ini tidak cukup untuk membatasi tool atau data access.
  • Mengirim provider key ke frontend. Ini membuat abuse sulit dicegah dan diaudit.
  • Validasi hanya di frontend. Semua validasi keamanan harus tetap ada di backend.
  • Rate limit hanya per IP. Ini sering memblokir user sah atau tidak efektif untuk akun yang dicuri.
  • Logging terlalu banyak. Prompt, kode, atau credential bisa bocor lewat log.
  • Menerima file terlalu bebas. Attachment adalah jalur masuk beban dan parsing yang berisiko.
  • Tidak memisahkan auth user dan auth service. Akibatnya scope dan audit menjadi kabur.

Debugging dan verifikasi implementasi

Setelah middleware terpasang, lakukan verifikasi terarah. Beberapa skenario uji yang layak dicoba:

  • Kirim request tanpa auth, dengan auth invalid, dan dengan scope kurang.
  • Kirim payload di atas batas body dan di atas batas field.
  • Uji attachment dengan MIME salah, ekstensi ganda, dan ukuran total melebihi batas.
  • Simulasikan burst request dari user yang sama dan IP yang sama.
  • Uji request dari user sama tetapi IP berbeda, dan sebaliknya.
  • Pastikan log menulis request_id, user_id, alasan penolakan, tetapi tidak membocorkan secret.
  • Jika ada tool execution, uji prompt injection yang mencoba memanggil tool terlarang atau argumen di luar skema.

Jika memakai reverse proxy atau CDN, pastikan juga bahwa client IP, batas body, dan timeout yang Anda lihat di aplikasi benar-benar konsisten dengan konfigurasi jaringan di depan aplikasi.

Penutup

Hardening endpoint prompt API untuk backend produksi perlu memadukan beberapa lapisan kontrol: auth yang sesuai konteks, secret yang tersimpan aman, validasi request berbasis allowlist, pembatasan payload dan attachment, mitigasi prompt injection ke tool/backend, audit log yang cukup, dan rate limit berbasis user+IP.

Tujuan utamanya bukan membuat endpoint “sempurna”, melainkan membuat penyalahgunaan menjadi lebih sulit, lebih mahal, lebih terdeteksi, dan lebih mudah direspons. Untuk endpoint yang menerima prompt atau kode ke model open-source seperti Kimi K2.7-Code, kontrol-kontrol ini jauh lebih penting daripada optimasi kecil di sisi inferensi, karena insiden paling mahal sering datang dari API layer yang terlalu permisif.