DEV Community

Cover image for Cara Menguji Keamanan API dari Input Berbahaya Sebelum Diretas
Walse
Walse

Posted on • Originally published at apidog.com

Cara Menguji Keamanan API dari Input Berbahaya Sebelum Diretas

TL;DR: Input API Anda adalah permukaan serangan, jadi ujilah seperti itu. Tulis kasus negatif yang mengirimkan bidang berukuran besar, tipe yang salah, isi yang salah format, dan string injeksi, lalu pastikan endpoint menjawab dengan kode 4xx dan tidak pernah 5xx. Ubah validasi skema menjadi kontrol keamanan dengan additionalProperties: false, enum, dan batasan panjang. Jalankan seluruh suite di CI pada setiap perubahan. Agen AI membuat ini mendesak: mereka menghasilkan dan meneruskan payload dengan kecepatan mesin, sehingga "muat data ini" yang diam-diam menjadi "jalankan kode ini" kini skalanya meningkat.

Sebagian besar test suite membuktikan bahwa API Anda berfungsi ketika pemanggil berlaku sopan. Anda mengirimkan badan yang valid, Anda mendapatkan 200, penegasan berhasil. Hasil itu hampir tidak memberi tahu Anda apa pun tentang apa yang terjadi ketika badan tersebut bersifat hostile. Input yang tidak tepercaya adalah data apa pun yang tidak dihasilkan sendiri oleh endpoint Anda: badan permintaan, query string, header, unggahan berkas, payload webhook, dan JSON yang dikumpulkan agen AI dengan cepat. Semuanya pantas mendapatkan asumsi yang sama, yaitu bahwa seseorang pada akhirnya akan mengirimkan versi terburuknya.

Coba Apidog hari ini

Pada Juli 2026, Hugging Face menggambarkan insiden keamanan yang vektor masuknya adalah data, bukan kata sandi yang dicuri. Kami membahas pelajaran dari pelanggaran tersebut secara terpisah; panduan ini adalah bagian praktisnya.

Anda akan membangun tes yang mengirimkan jenis input yang dikirimkan penyerang, lalu menjalankannya secara otomatis pada setiap perubahan. Kategorinya selaras dengan OWASP API Security Top 10, yang patut tetap dibuka di sebuah tab. Apidog adalah salah satu cara untuk merancang kontrak dan menggerakkan tes ini, tetapi idenya berlaku di kerangka kerja apa pun yang sudah Anda gunakan.

Input adalah permukaan serangan, bukan bidang formulir

Validasi sering diperlakukan sebagai kesopanan pengalaman pengguna: menangkap email kosong, menampilkan batas merah, lalu lanjut. Pembingkaian itu adalah masalahnya.

Setiap bidang yang diterima API Anda adalah janji yang dapat dilanggar oleh pemanggil, dan setiap janji yang dilanggar adalah jalur ke dalam logika Anda.

  • Parameter limit yang Anda harapkan berupa bilangan bulat kecil menjadi 999999999.
  • filename yang Anda harapkan berupa satu kata menjadi ../../etc/passwd.
  • Objek config yang Anda harapkan menyimpan pengaturan menjadi serangkaian instruksi.

Pengujian keamanan bukanlah disiplin terpisah yang ditambahkan di akhir. Ini adalah pengujian negatif yang sama yang sudah Anda ketahui, ditujukan pada bidang yang paling mungkin merugikan Anda.

Biasakan bertanya: "Apa hal terburuk yang bisa masuk ke bidang ini?" Anda sudah setengah jalan menuju praktik dalam panduan praktik terbaik keamanan API. Sisa artikel ini mengubah pertanyaan tersebut menjadi tes konkret yang dapat Anda jalankan.

Bagaimana “muat data ini” menjadi “jalankan kode ini”

Insiden Hugging Face adalah contoh nyata mengapa input layak mendapatkan perhatian ini. Hugging Face mengatakan vektor masuknya adalah dataset yang berbahaya: dataset yang dibuat memicu pemuat dataset remote-code, dan injeksi template berada di dalam konfigurasi dataset. Anda dapat membaca laporan perusahaan sendiri di laporan insiden keamanannya.

Bentuk kegagalannya seperti ini:

  1. Sebuah endpoint menerima sesuatu yang digambarkan sebagai data.
  2. Memuat data tersebut menjalankan jalur kode.
  3. Jalur kode itu dapat mengeksekusi instruksi yang dikendalikan penyerang.

Dengan kata lain, "muat data ini" menjadi "jalankan kode ini."

Injeksi template adalah cerita yang sama dalam skala lebih kecil: nilai konfigurasi yang seharusnya berupa teks inert dievaluasi, sehingga teks berubah menjadi eksekusi.

Pelajarannya bukanlah "Hugging Face melakukan kesalahan langka." Pelajarannya adalah bahwa setiap endpoint yang menerima nama pemuat, format, template, objek terserialisasi, atau blob konfigurasi sebenarnya menerima instruksi—terlepas dari apakah Anda sengaja melakukannya atau tidak.

Jika Anda belum pernah mengirim konfigurasi berbahaya ke endpoint tersebut dalam tes, Anda belum memeriksa asumsi bahwa input tetap inert. Asumsi yang tidak teruji itulah kerentanannya.

Validasi skema sebagai kontrol keamanan

Kontrol termurah yang bisa Anda tambahkan adalah skema ketat di bagian tepi API. Skema bukan hanya dokumentasi. Ketika Anda menolak apa pun yang tidak sesuai, skema menjadi filter yang berjalan sebelum logika bisnis melihat permintaan.

JSON Schema menyediakan primitive untuk membuat filter tersebut ketat.

Berikut skema untuk konfigurasi dataset yang menolak sebagian besar input berbahaya sebelum mencapai kode aplikasi:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["loader", "name"],
  "properties": {
    "loader": { "enum": ["csv", "json", "parquet"] },
    "name": {
      "type": "string",
      "maxLength": 128,
      "pattern": "^[\\w .-]+$"
    },
    "rows": {
      "type": "integer",
      "minimum": 0,
      "maximum": 1000000
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Skema tersebut menerapkan empat pertahanan terpisah:

  1. additionalProperties: false

    Menolak bidang selundupan seperti template. Penyerang tidak dapat menambahkan properti yang tidak Anda dukkung.

  2. enum untuk loader

    Nilai seperti pickle:// atau pemuat kode jarak jauh bukan nilai yang valid.

  3. maxLength

    Menghentikan string multi-megabyte yang bertujuan menghabiskan memori.

  4. pattern untuk name

    Menolak karakter seperti {{ dan '; DROP TABLE sebelum mencapai lapisan berikutnya.

Tidak satu pun baris ini perlu mengetahui identitas penyerang. Skema hanya menerima kumpulan input sempit yang benar-benar Anda dukung. Kesempitan itulah properti keamanannya.

Validasi kontrak tidak akan menangkap setiap eksploitasi. Namun, validasi ini menutup kategori yang umum: bug "kita tidak pernah memeriksa apa yang diterima endpoint ini". Banyak pelanggaran dimulai dari kategori tersebut.

Pengujian negatif: buktikan bahwa endpoint menolak

Tes happy-path membuktikan input yang baik menghasilkan output yang baik. Tes negatif membuktikan input buruk menghasilkan penolakan yang terkontrol.

Penolakan adalah fitur:

  • Kode 400 atau 422 dengan kesalahan yang jelas berarti API mempertahankan batasnya.
  • Kode 500 berarti input Anda mencapai kode yang tidak siap menanganinya.

Untuk setiap bidang, tuliskan kondisi yang harus ditolak:

Kondisi Contoh
Tipe salah String saat API mengharapkan integer
Wajib tetapi hilang Properti name tidak dikirim
Terlarang tetapi ada Properti template ditambahkan
Terlalu panjang Nama berukuran beberapa megabyte
Di luar jangkauan rows: -1 atau nilai sangat besar
String injeksi SQL, template, perintah shell

Kemudian tegaskan dua hal pada respons:

  1. Status harus 4xx, biasanya 400, 413, atau 422.
  2. Status tidak boleh 5xx.

Kode 500 berarti payload berbahaya mencapai logika yang tidak siap untuknya—tepat jangkauan yang diinginkan penyerang.

Daftar periksa pengujian keamanan API kami dapat menjadi daftar awal per bidang yang dapat Anda sesuaikan.

Satu aturan penting: tegaskan perilaku, bukan teks kesalahan. Jangan mengunci tes pada pesan seperti "loader tidak valid", karena refactor yang aman dapat mengubah teks tersebut. Tegaskan kode status dan, jika memungkinkan, tegaskan bahwa tidak ada efek samping.

Kelas injeksi yang layak mendapatkan tes khusus

Beberapa keluarga injeksi cukup sering muncul sehingga layak memiliki kasus uji standar. Anda tidak perlu mencakup semuanya pada awalnya. Mulailah dengan satu kasus probing per kelas agar regresi gagal secara jelas.

Alat yang menjalankan deteksi kerentanan API otomatis dapat memperluas cakupan nanti, tetapi kasus manual berikut menangkap celah yang jelas lebih awal.

  • Injeksi SQL

    Kirim 1); DROP TABLE datasets;-- ke bidang yang mencapai query. Endpoint harus memperlakukannya sebagai nilai literal dan menjawab 400, atau mengembalikan hasil kosong. Jangan pernah membocorkan kesalahan basis data.

  • Injeksi template

    Kirim {{ 7*7 }} dan {{ config.__class__ }} ke bidang nama atau label. Jika respons berisi 49, template engine mengevaluasi input Anda. Itu berarti eksekusi kode jarak jauh mungkin terjadi.

  • Deserialisasi tidak aman dan pemuat kode jarak jauh

    Kirim loader bernilai pickle:// atau objek terserialisasi ketika API mengharapkan nilai biasa. Endpoint harus menolak pemuat yang tidak ada dalam allowlist, bukan mencoba memprosesnya.

  • Injeksi perintah

    Kirim ; id dan $(id) ke bidang yang mungkin menjadi argumen shell, seperti nama berkas atau opsi konversi. Kode 200 yang membocorkan ID pengguna adalah temuan kritis.

Ukuran berlebihan, salah format, dan kebingungan jenis konten

Tidak setiap input berbahaya adalah string yang cerdas. Sebagian hanya terlalu besar atau berbentuk salah. Kasus seperti ini sering merusak parser sebelum logika validasi aplikasi berjalan.

Uji setidaknya kasus berikut:

  • Satu bidang dengan lima megabyte karakter yang sama.
  • Larik JSON dengan satu juta elemen.
  • JSON terpotong.
  • JSON dengan koma di belakang.
  • JSON bersarang sangat dalam untuk menyelidiki kelelahan stack.

API yang sehat menerapkan batas ukuran badan dan mengembalikan 413 daripada mengalokasikan memori hingga habis. Untuk JSON salah format, respons yang diharapkan adalah 400 yang cepat, bukan worker yang macet.

Kebingungan jenis konten juga perlu diuji:

Header Content-Type Badan aktual Yang diuji
application/json XML Apakah server memercayai header tanpa memeriksa badan
application/xml XML dengan entitas eksternal Potensi XXE
text/plain JSON Apakah parser terlalu longgar menerima JSON

Setiap ketidakcocokan menguji apakah server memercayai header, memercayai badan, atau memeriksa bahwa keduanya konsisten. Server harus memastikan keduanya sesuai sebelum melakukan parsing.

Mengapa agen AI meningkatkan taruhan

Semua risiko di atas sudah ada sebelum agen AI. Agen mengubah volume dan kecepatan.

Penyerang manusia mengirim satu permintaan berbahaya pada satu waktu. Agen AI dapat menghasilkan dan meneruskan payload dengan kecepatan mesin, termasuk kombinasi input yang mungkin tidak pernah dicoba manusia.

Tiga karakteristik memperburuk risikonya:

  1. Agen mensintesis input

    Agen menghasilkan nilai bidang yang tidak ditulis manusia dan mungkin tidak diantisipasi oleh tes Anda.

  2. Agen mencoba ulang dan merangkai panggilan

    Satu dokumen hulu yang terkontaminasi dapat berubah menjadi ribuan permintaan berbahaya ke endpoint Anda dalam hitungan detik.

  3. Agen meneruskan data yang diperintahkan untuk dipercayai

    Payload yang tersembunyi dalam dataset atau webhook dapat berubah menjadi permintaan nyata ke API Anda.

Pola Hugging Face—"muat data ini" menjadi "jalankan kode ini"—adalah jenis instruksi yang dapat dibawa agen melintasi batas kepercayaan tanpa menyadarinya.

Catatan kami tentang injeksi prompt untuk tim API membahas hand-off tersebut lebih dalam. Pertahanannya tidak berubah, tetapi harus otomatis karena Anda tidak dapat meninjau lalu lintas agen secara manual.

Bangun suite negatif dan jalankan di CI pada setiap perubahan

Ubah kasus di atas menjadi suite yang berjalan pada setiap pull request. Berikut contoh ringkas dengan pytest yang memukul staging endpoint dan menegaskan penolakan terkontrol:

import httpx
import pytest

BASE = "https://staging.internal/v1"

HOSTILE_CONFIGS = [
    {"loader": "pickle://s3/models/payload.pkl", "format": "auto"},
    {"loader": "csv", "name": "{{ 7*7 }}"},
    {"loader": "csv", "name": "{{ config.__class__ }}"},
    {"loader": "csv", "filter": "1); DROP TABLE datasets;--"},
    {"loader": "csv", "name": "A" * 5_000_000},
]

@pytest.mark.parametrize("config", HOSTILE_CONFIGS)
def test_dataset_config_is_refused(config):
    response = httpx.post(
        f"{BASE}/datasets",
        json={"config": config},
        timeout=10,
    )

    assert response.status_code in (400, 413, 422), response.text
    assert response.status_code < 500, (
        "5xx berarti payload mencapai logika yang seharusnya tidak dijangkau"
    )
    assert "49" not in response.text, (
        "Template dirender: kemungkinan server-side template injection"
    )
Enter fullscreen mode Exit fullscreen mode

Hubungkan tes tersebut ke CI agar menjadi gerbang penggabungan. Job GitHub Actions minimal:

name: api-abuse-tests

on: [push, pull_request]

jobs:
  negative-input:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pytest tests/negative_input.py -q
Enter fullscreen mode Exit fullscreen mode

Di sinilah alat yang mengutamakan skema berguna. Di Apidog, Anda dapat merancang endpoint terhadap kontrak OpenAPI dan memeriksa setiap permintaan serta respons terhadap kontrak tersebut saat pengujian.

Simpan skenario negatif di samping skenario happy-path:

  • Bidang berukuran besar
  • Tipe salah
  • Properti tambahan yang tidak diizinkan
  • String injeksi SQL
  • String injeksi template
  • Nilai loader di luar allowlist

Untuk setiap skenario, tambahkan penegasan bahwa responsnya adalah 4xx. Kemudian jalankan skenario tersebut di CI melalui Apidog CLI agar perubahan yang diam-diam melonggarkan validasi membuat build gagal, bukan ter-deploy.

Jika ingin mencobanya, Unduh Apidog dan tambahkan satu skenario negatif ke endpoint yang sudah Anda miliki.

Batasannya perlu jelas: Apidog adalah alat desain, pengujian, mocking, dan dokumentasi. Ini tidak menjalankan web application firewall, memfilter lalu lintas langsung, atau menggantikan SIEM. Validasi kontrak saat pengujian juga tidak akan menangkap setiap eksploitasi.

Namun, alat ini membantu membuat kontrak eksplisit dan menjaga tim tetap jujur tentang apa yang diterima endpoint. Dengan begitu, kategori "kami tidak pernah memeriksa" berhenti menjadi kejutan di produksi.

Pertanyaan yang Sering Diajukan

Apa perbedaan antara pengujian negatif dan fuzzing?

Pengujian negatif mengirimkan serangkaian input buruk yang dipilih secara sengaja, satu per satu untuk kegagalan yang Anda pedulikan. Fuzzing mengirimkan volume besar input acak atau termutasi untuk menemukan kasus yang tidak terpikirkan.

Mulailah dengan tes negatif karena cepat, deterministik, dan mudah dijalankan di CI. Tambahkan fuzzing ketika Anda membutuhkan cakupan yang lebih luas daripada imajinasi tim.

Haruskah tes ini dijalankan terhadap produksi?

Tidak. Jalankan terhadap staging atau lingkungan terisolasi.

Beberapa kasus—seperti payload berukuran besar atau probe injeksi perintah—dirancang untuk menekan sistem. Jika ada bug, beberapa di antaranya dapat mengubah data. Lingkungan pengujian khusus memungkinkan tes tetap agresif tanpa risiko terhadap pengguna nyata.

Bukankah firewall atau WAF akan menangkap ini?

WAF adalah pertahanan berlapis yang berguna, tetapi bukan pengganti aplikasi yang menolak input buruk. Aturan dapat dilewati, dan WAF tidak mengetahui logika bisnis Anda.

Tujuan tes ini adalah membuktikan bahwa endpoint itu sendiri menolak input berbahaya sehingga Anda tidak bergantung sepenuhnya pada filter yang tidak Anda kendalikan.

Berapa banyak kasus negatif yang cukup per endpoint?

Targetkan satu kasus per bidang untuk setiap kelas kegagalan yang mungkin terjadi:

  • Tipe salah
  • Di luar jangkauan
  • Terlalu panjang
  • Bidang terlarang
  • String injeksi yang sesuai dengan formatnya

Biasanya ini berarti beberapa kasus per endpoint, bukan ratusan. Cakupan kelas kegagalan lebih penting daripada jumlah mentah.

Apakah validasi skema menghentikan injeksi sepenuhnya?

Tidak. Validasi skema tidak boleh menjadi satu-satunya lapisan pertahanan.

Skema ketat menghilangkan banyak input salah format dan berukuran besar, serta memblokir bidang tidak terduga. Namun, nilai dapat valid secara skema dan tetap menjadi injeksi SQL atau template.

Tetap gunakan:

  • Parameterized queries
  • Deserialisasi yang aman
  • Output encoding
  • Allowlist untuk nilai yang dapat dieksekusi atau dimuat

Gunakan skema untuk memperkecil permukaan yang harus dipertahankan oleh lapisan-lapisan tersebut.

Top comments (0)