Cover image for API'nizi Güvenilmeyen Girişlere Karşı Nasıl Test Edersiniz: Saldırganlar Keşfetmeden Önce

Tobias Hoffmann

TL;DR: API'nizin girdisi bir saldırı yüzeyidir; bu nedenle onu düşmanca isteklerle test edin. Büyük alanlar, yanlış türler, hatalı gövdeler ve enjeksiyon dizeleri gönderin. Uç noktanın 4xx döndürdüğünü ve hiçbir zaman 5xx üretmediğini doğrulayın. Şema doğrulamasını additionalProperties: false, enum'lar ve uzunluk sınırlarıyla bir güvenlik kontrolüne dönüştürün. Bu paketi her değişiklikte CI'da çalıştırın. Yapay zeka ajanları yükleri makine hızında ürettiği için, “bu veriyi yükle” isteğinin sessizce “bu kodu çalıştır” davranışına dönüşme riski artık daha kolay ölçeklenir.

Apidog'u bugün deneyin

Çoğu test paketi yalnızca nazik bir istemci geçerli veri gönderdiğinde API'nin çalıştığını kanıtlar. Geçerli bir gövde gönderir, 200 alır ve testi geçersiniz. Ancak bu, gövde düşmanca olduğunda ne olacağını söylemez. İstek gövdeleri, sorgu parametreleri, başlıklar, dosya yüklemeleri, webhook yükleri ve yapay zeka ajanlarının oluşturduğu JSON dahil olmak üzere güvenilmeyen tüm girdileri aynı varsayımla ele alın: bir gün birisi bunun mümkün olan en kötü sürümünü gönderecek.

Temmuz 2026'da Hugging Face, giriş vektörünün çalınmış parola değil veri olduğu bir güvenlik olayını açıkladı. Bu makalede uygulama tarafına odaklanacağız: saldırganın gönderebileceği girdileri testlere dönüştürecek ve bunları her değişiklikte otomatik çalıştıracağız. Kategoriler, açık tutulmaya değer olan OWASP API Güvenlik En İyi 10 ile uyumludur. Apidog, sözleşme tasarlamak ve testleri çalıştırmak için kullanılabilecek araçlardan biridir; ancak yaklaşım kullandığınız çerçeveden bağımsızdır.

Girdi bir form alanı değil, saldırı yüzeyidir

Doğrulama çoğu zaman bir kullanıcı deneyimi ayrıntısı olarak görülür: boş e-postayı yakala, hata mesajı göster, devam et. API güvenliği açısından doğrulama bir sınır kontrolüdür.

API'nizin kabul ettiği her alan bir sözleşmedir ve bu sözleşme bozulabilir:

  • limit için küçük bir tamsayı beklersiniz, istemci 999999999 gönderir.
  • filename için basit bir ad beklersiniz, istemci ../../etc/passwd gönderir.
  • config için ayar nesnesi beklersiniz, istemci yürütülebilir talimatlara dönüşebilecek değerler gönderir.

Güvenlik testi, projenin sonuna eklenen ayrı bir iş değildir. Zaten yaptığınız negatif testlerin, en fazla zarar verebilecek alanlara uygulanmış hâlidir. Her alan için şu soruyu sorun:

Bu alana sığabilecek en kötü girdi nedir?

Bu yaklaşım, API güvenlik en iyi uygulamaları içindeki kontrollerin çoğunu pratik olarak uygulamanıza yardımcı olur.

“Bu veriyi yükle” nasıl “bu kodu çalıştır” oldu?

Hugging Face olayı, veri kabul eden uç noktaların neden dikkatle ele alınması gerektiğini gösterir. Şirketin açıklamasına göre giriş vektörü kötü niyetli veri kümeleriydi: özel hazırlanmış bir veri kümesi uzaktan kod yükleyicisini tetikledi ve veri kümesi yapılandırmasına şablon enjeksiyonu yerleştirildi. Ayrıntılar için güvenlik olayı raporunu inceleyebilirsiniz.

Bu hata modelini genelleştirin:

  1. Uç nokta veri olarak tanımlanan bir değer kabul eder.
  2. Bu verinin yüklenmesi veya işlenmesi bir kod yolunu tetikler.
  3. Kod yolu, saldırgan kontrollü komutları değerlendirebilir.
  4. Sonuçta “veri yükleme”, “kod çalıştırma” etkisine dönüşür.

Aynı risk; yükleyici adı, dosya biçimi, şablon, serileştirilmiş nesne veya yapılandırma blobu kabul eden her uç noktada bulunabilir. Düşmanca bir yapılandırmanın eylemsiz kaldığını test etmiyorsanız, bu varsayımı henüz doğrulamamışsınızdır.

Şema doğrulamasını güvenlik kontrolü olarak kullanın

En düşük maliyetli savunmalardan biri, uç noktada katı bir şema kullanmaktır. Şema yalnızca dokümantasyon değildir. İş mantığınız isteği görmeden önce eşleşmeyen girdileri filtreleyen bir sınırdır.

JSON Schema ile veri kümesi yapılandırmasını şu şekilde sınırlayabilirsiniz:

{
  "$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

Bu şemadaki her kural ayrı bir savunma katmanıdır:

Kural Engellediği risk
additionalProperties: false Beklenmeyen template, command veya benzeri alanların gizlice eklenmesi
loader enum'u pickle:// veya bilinmeyen uzaktan yükleyiciler
maxLength Bellek tüketmeyi hedefleyen çok büyük dizeler
pattern {{, ;, yol geçişi ve benzeri beklenmeyen karakter dizileri
Sayısal minimum / maximum Aralık dışı değerler ve kaynak tüketimi

Şema doğrulama tüm açıkları kapatmaz. Örneğin şema açısından geçerli bir dize yine de SQL veya şablon enjeksiyonu taşıyabilir. Ancak kritik bir hata sınıfını kapatır: uç noktanın neyi kabul ettiğinin hiç sınırlandırılmamış olması.

Negatif test: Uç noktanın “hayır” dediğini kanıtlayın

Başarılı yol testleri, iyi girdinin beklenen çıktıyı ürettiğini doğrular. Negatif testler ise kötü girdinin kontrollü bir ret ürettiğini doğrular.

İdeal sonuç genellikle şudur:

  • 400 Bad Request
  • 413 Payload Too Large
  • 422 Unprocessable Entity

Kabul edilemez sonuç ise şudur:

  • 500 Internal Server Error
  • Herhangi bir başka 5xx yanıtı

500, düşmanca girdinin uygulamanızda beklenmeyen bir kod yoluna ulaştığını gösterir. Bu durum hem hata ayrıntılarının sızmasına hem de kullanılabilirlik sorunlarına yol açabilir.

Her alan için aşağıdaki negatif durumları yazın:

  • Yanlış tür
  • Eksik zorunlu alan
  • Yasak veya beklenmeyen alan
  • Aşırı uzun değer
  • Aralık dışı sayı
  • Hatalı biçim
  • Alan bağlamına uygun enjeksiyon dizisi

Testlerde hata metnine değil davranışa odaklanın. Örneğin yalnızca "geçersiz yükleyici" metnini doğrulamak yerine durum kodunu ve yan etkileri doğrulayın. Hata mesajı değişebilir; güvenlik sınırı değişmemelidir.

Başlangıç senaryoları için API güvenlik test kontrol listesini uyarlayabilirsiniz.

Sürekli test edilmesi gereken enjeksiyon sınıfları

Her enjeksiyon türü için kapsamlı bir payload koleksiyonu ile başlamanız gerekmez. Her sınıf için en az bir regresyon senaryosu oluşturun. Amaç, savunma zayıfladığında CI'ın yüksek sesle başarısız olmasıdır.

  • SQL enjeksiyonu: Sorguya ulaşabilecek alanlara 1); DROP TABLE datasets;-- gönderin. Uç nokta bunu değişmez değer olarak ele almalı, kontrollü biçimde reddetmeli veya boş sonuç döndürmelidir. Veritabanı hatası sızdırmamalıdır.
  • Şablon enjeksiyonu: Ad veya etiket alanlarına {{ 7*7 }} ve {{ config.__class__ }} gönderin. Yanıtta 49 görünmesi, girdinin şablon motorunda değerlendirildiğine işaret eder.
  • Güvenli olmayan serileştirme ve uzaktan yükleyiciler: Düz metin beklenen alanlara pickle:// türü yükleyici değerleri veya serileştirilmiş nesneler gönderin. Bilinmeyen yükleyiciler beyaz liste yaklaşımıyla reddedilmelidir.
  • Komut enjeksiyonu: Dosya adı, dönüştürme seçeneği veya shell argümanına dönüşebilecek alanlara ; id ve $(id) gönderin. Kullanıcı veya sistem bilgisi döndüren bir 200 yanıtı kritik bulgudur.

Kapsamı otomatik genişleten API güvenlik açığı tespiti araçları daha sonra eklenebilir. Önce küçük ve anlaşılır bir negatif test paketi oluşturun.

Büyük boyutlu, hatalı biçimlendirilmiş ve içerik türü uyuşmazlığı olan gövdeler

Düşmanca girdi her zaman akıllı bir enjeksiyon dizesi değildir. Bazen yalnızca çok büyüktür veya yanlış biçimlendirilmiştir. Bu tür istekler, doğrulama kodunuz çalışmadan önce ayrıştırıcıları ve kaynakları zorlayabilir.

Aşağıdaki durumları test edin:

  1. Aşırı büyük alanlar

    • Tek alanda 5 MB karakter dizisi gönderin.
    • Bir milyon öğeli JSON dizisi gönderin.
    • Beklenen sonuç: uygulama bellek tüketmeden 413 veya kontrollü bir 4xx döndürmeli.
  2. Hatalı JSON

    • Kesilmiş JSON
    • Sondaki virgül
    • Hatalı tırnak kullanımı
    • Beklenen sonuç: hızlı bir 400; takılan worker veya 500 değil.
  3. Aşırı derin JSON

    • Binlerce seviye iç içe nesne veya dizi gönderin.
    • Beklenen sonuç: ayrıştırma sınırları nedeniyle kontrollü ret.
  4. İçerik türü uyuşmazlığı

    • Content-Type: application/json ile XML gönderin.
    • Content-Type: application/xml ile JSON gönderin.
    • JSON'u text/plain olarak gönderin.
    • XML işleniyorsa XXE araştırması için harici varlık içeren yükleri izole ortamda deneyin.

Sunucu, başlık ve gövdenin uyumlu olmasını herhangi bir içeriği ayrıştırmadan önce kontrol etmelidir.

Yapay zeka ajanları neden riski artırıyor?

Bu risklerin tamamı yapay zeka ajanlarından önce de vardı. Ajanların değiştirdiği şey hacim ve hızdır.

İnsan saldırgan tek tek istek yazar. Yapay zeka ajanı ise:

  • İnsanların düşünmeyeceği alan değerleri üretebilir.
  • Başarısız istekleri otomatik olarak yeniden deneyebilir.
  • Çağrıları zincirleyebilir.
  • Güvenilir kabul edilen belgelerde veya webhook'larda gizlenmiş verileri API isteğine dönüştürebilir.

Tek bir zehirli yukarı akış belgesi, saniyeler içinde binlerce düşmanca isteğe dönüşebilir. Bu nedenle savunma yaklaşımı değişmez; ancak manuel inceleme yerine otomatik test ve sınır kontrolleri gerekir.

Bu aktarım riskini daha ayrıntılı incelemek için API ekipleri için istem enjeksiyonu notuna bakabilirsiniz.

Negatif test paketini oluşturun ve CI'da çalıştırın

Negatif senaryoları her çekme isteğinde çalışan bir test paketine dönüştürün. Aşağıdaki pytest örneği, hazırlık ortamındaki bir uç noktaya düşmanca yapılandırmalar gönderir:

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, yükün ulaşmaması gereken iş mantığına ulaştığını gösterir"
    )
    assert "49" not in response.text, (
        "Şablon işlendi: sunucu tarafı şablon enjeksiyonu riski"
    )

Enter fullscreen mode Exit fullscreen mode

Bu testi CI'da çalıştırarak güvenlik kontrollerinin sessizce gevşetilmesini engelleyebilirsiniz:

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

Apidog ile uç noktayı OpenAPI sözleşmesine göre tanımlayabilir, pozitif ve negatif senaryoları aynı koleksiyonda tutabilir ve bunları CLI üzerinden CI'da çalıştırabilirsiniz. Her negatif senaryoda en az bir durum kodu doğrulaması ekleyin:

Beklenen durum kodu: 400, 413 veya 422
Beklenmeyen durum kodu: herhangi bir 5xx

Enter fullscreen mode Exit fullscreen mode

Başlamak için Apidog'u indirin ve mevcut bir uç noktaya tek bir negatif senaryo ekleyin.

Sınırı net tutun: Apidog bir tasarım, test, mock ve dokümantasyon aracıdır. Web uygulama güvenlik duvarı çalıştırmaz, canlı trafiği filtrelemez ve SIEM'in yerine geçmez. Sözleşme doğrulaması da her açığı yakalayamaz. Ancak uç noktanın neyi kabul ettiğini görünür ve test edilebilir hâle getirir.

Sıkça sorulan sorular

Negatif test ile fuzzing arasındaki fark nedir?

Negatif test, bilerek seçtiğiniz belirli kötü girdileri gönderir. Fuzzing ise düşünmediğiniz durumları bulmak için rastgele veya mutasyona uğratılmış çok sayıda girdi üretir.

Önce negatif testlerle başlayın: hızlıdır, deterministiktir ve CI'da çalıştırması kolaydır. Daha geniş keşif gerektiğinde fuzzing ekleyin.

Bu testler üretimde çalıştırılmalı mı?

Hayır. Testleri hazırlık veya izole bir ortamda çalıştırın. Büyük gövdeler, komut enjeksiyonu denemeleri ve bazı serileştirme testleri sistemi stres altına almak veya hata varsa veri değiştirmek için tasarlanmıştır.

WAF bu istekleri zaten engellemez mi?

WAF, savunmada derinlik için yararlıdır ancak uygulama doğrulamasının yerine geçmez. Kurallar atlatılabilir ve WAF iş mantığınızı bilmez. Bu testlerin amacı, uç noktanın kendisinin kontrollü şekilde ret verdiğini kanıtlamaktır.

Uç nokta başına kaç negatif senaryo yeterlidir?

Her alan için maruz kaldığı hata sınıflarını kapsayın:

  • Yanlış tür
  • Aralık dışı değer
  • Aşırı uzun değer
  • Yasak alan
  • Bağlama uygun enjeksiyon dizesi

Bu genellikle uç nokta başına yüzlerce değil, birkaç iyi seçilmiş senaryo demektir. Ham sayı yerine sınıf kapsamına odaklanın.

Şema doğrulama enjeksiyonu tamamen engeller mi?

Hayır. Katı şema; beklenmeyen alanları, hatalı biçimleri ve birçok büyük yükü engeller. Ancak şema açısından geçerli bir değer yine de SQL veya şablon enjeksiyonu içerebilir.

Şemayı aşağıdaki katmanlarla birlikte kullanın:

  • Parametreli sorgular
  • Güvenli serileştirme
  • Çıktı kodlama
  • İzinli yükleyici listeleri
  • Gövde ve ayrıştırma sınırları
  • CI'da çalışan negatif testler