API Güvenlik Testi: Yaygın Açıkları Tespit Etme ve Giderme Rehberi

Modern uygulamaların omurgasını oluşturan API’lar, aynı zamanda saldırganların en çok hedef aldığı noktalara dönüşmüş durumda. Bir REST endpoint’i yanlış yapılandırdığında ya da authentication mekanizmasını eksik kurduğunda, tüm sistemin kapısını ardına kadar açmış oluyorsun. Bu yazıda gerçek dünya senaryoları üzerinden API güvenlik testinin nasıl yapılacağını, yaygın açıkları nasıl tespit edip gidereceğini ele alacağız.

Neden API Güvenliği Bu Kadar Kritik?

Geçen yıl bir e-ticaret şirketinde danışmanlık yaptığımda, production ortamındaki bir API endpoint’inin herhangi bir authentication kontrolü olmaksızın tüm kullanıcı verilerini döndürdüğünü keşfettim. Endpoint dokümanlarda yoktu, “gizli” sayılıyordu ama basit bir dizin taramasıyla bulunabiliyordu. Security through obscurity’nin neden işe yaramadığının canlı örneğiydi bu.

OWASP’ın her yıl güncellediği API Security Top 10 listesi, bu sorunların ne kadar yaygın olduğunu gözler önüne seriyor. Broken Object Level Authorization, Broken Authentication, Excessive Data Exposure gibi açıklar tekrar tekrar karşımıza çıkıyor. Bunların büyük çoğunluğu ise geliştirme aşamasında basit testlerle tespit edilebilir.

Test Ortamını Hazırlamak

Üretim ortamında doğrudan test yapmak hem riskli hem de etik açıdan sorunlu. Önce izole bir test ortamı kurman gerekiyor.

Temel Araçları Kurmak

# OWASP ZAP kurulumu (Debian/Ubuntu)
sudo apt update && sudo apt install zaproxy -y

# Burp Suite Community Edition için Java gerekli
sudo apt install default-jre -y

# curl ve jq - temel API test araçları
sudo apt install curl jq -y

# httpie - daha okunabilir HTTP client
pip3 install httpie

# ffuf - fuzzing için
go install github.com/ffuf/ffuf/v2@latest

# nuclei - zafiyet tarama
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest

Docker ile Yerel Test Ortamı

Kendi test ortamını kurmak için savunmasız API uygulamalarını Docker üzerinde çalıştırabilirsin:

# DVAPI (Damn Vulnerable API) çalıştır
docker pull appsecco/dvapi
docker run -d -p 5000:5000 --name dvapi appsecco/dvapi

# OWASP crAPI (Completely Ridiculous API) - daha kapsamlı
git clone https://github.com/OWASP/crAPI.git
cd crAPI
docker-compose up -d

# Çalışıp çalışmadığını kontrol et
curl -s http://localhost:5000/health | jq .

OWASP API Security Top 10: Pratik Testler

1. Broken Object Level Authorization (BOLA/IDOR)

Bu en yaygın ve en tehlikeli API açığı. Kullanıcı kendi kaynağına erişirken, ID değerini değiştirerek başkasının kaynağına erişebiliyor.

# Kendi siparişine erişim
curl -H "Authorization: Bearer TOKEN_A" 
  https://api.example.com/v1/orders/1001

# Başka kullanıcının siparişine erişim denemesi
# Sadece ID'yi değiştirerek test et
for order_id in $(seq 1000 1010); do
  response=$(curl -s -o /dev/null -w "%{http_code}" 
    -H "Authorization: Bearer TOKEN_A" 
    https://api.example.com/v1/orders/$order_id)
  echo "Order $order_id: HTTP $response"
done

Giderme yöntemi: Her nesne erişiminde kullanıcı sahipliğini doğrula.

# Python/Flask örneği - Yanlış yaklaşım
@app.route('/orders/<int:order_id>')
def get_order(order_id):
    order = Order.query.get(order_id)  # Sadece ID kontrolü!
    return jsonify(order.to_dict())

# Doğru yaklaşım
@app.route('/orders/<int:order_id>')
@jwt_required()
def get_order(order_id):
    current_user = get_jwt_identity()
    order = Order.query.filter_by(
        id=order_id,
        user_id=current_user['id']  # Sahiplik kontrolü eklendi
    ).first_or_404()
    return jsonify(order.to_dict())

2. Broken Authentication Testleri

# Zayıf JWT token testi - algorithm confusion
# "none" algoritması ile token oluşturma denemesi
HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0)
PAYLOAD=$(echo -n '{"user_id":1,"role":"admin","exp":9999999999}' | base64 -w0)
TOKEN="${HEADER}.${PAYLOAD}."

curl -H "Authorization: Bearer $TOKEN" 
  https://api.example.com/v1/admin/users

# Brute force koruması testi
for i in $(seq 1 20); do
  curl -s -o /dev/null -w "Attempt $i: %{http_code}n" 
    -X POST https://api.example.com/auth/login 
    -H "Content-Type: application/json" 
    -d '{"username":"admin","password":"wrong_password"}'
  sleep 0.5
done

Rate limiting yoksa veya 20. denemede hala 200/401 dönüyorsa (429 yerine), brute force koruması eksik demektir.

Nginx ile rate limiting eklemek:

# /etc/nginx/nginx.conf
http {
    # Login endpoint için agresif rate limiting
    limit_req_zone $binary_remote_addr zone=api_login:10m rate=5r/m;
    
    # Genel API için daha geniş limit
    limit_req_zone $binary_remote_addr zone=api_general:10m rate=100r/m;
    
    server {
        location /api/auth/login {
            limit_req zone=api_login burst=3 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }
        
        location /api/ {
            limit_req zone=api_general burst=20 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }
    }
}

3. Excessive Data Exposure Testi

API’ların gereğinden fazla veri döndürüp döndürmediğini test etmek:

# Kullanıcı endpoint'inden dönen tüm alanları incele
curl -s -H "Authorization: Bearer $TOKEN" 
  https://api.example.com/v1/users/me | jq 'keys'

# Hassas alanları filtrele
curl -s -H "Authorization: Bearer $TOKEN" 
  https://api.example.com/v1/users/me | 
  jq '{
    hassas_alanlar: {
      password_hash: .password_hash,
      internal_id: .internal_id,
      admin_notes: .admin_notes,
      two_factor_secret: .two_factor_secret
    }
  }'

Eğer bu alanlar response’da görünüyorsa, client tarafında filtreleme yapıldığı için sunucu tarafında da görünür kalıyor demektir.

4. Injection Açıkları

SQL Injection ve NoSQL Injection testleri:

# SQL Injection - temel testler
# URL parametresi üzerinden
curl -s "https://api.example.com/v1/products?category=electronics'" 
  -H "Authorization: Bearer $TOKEN" | jq .

# JSON body üzerinden
curl -s -X POST "https://api.example.com/v1/search" 
  -H "Authorization: Bearer $TOKEN" 
  -H "Content-Type: application/json" 
  -d '{"query": "test" OR 1=1--"}' | jq .

# NoSQL Injection (MongoDB)
curl -s -X POST "https://api.example.com/v1/login" 
  -H "Content-Type: application/json" 
  -d '{"username": {"$ne": null}, "password": {"$ne": null}}' | jq .

# Otomatik SQL injection taraması
sqlmap -u "https://api.example.com/v1/products?id=1" 
  --headers="Authorization: Bearer $TOKEN" 
  --batch --level=3 --risk=2

5. Security Misconfiguration Testi

# HTTP metodlarını test et
for method in GET POST PUT DELETE PATCH OPTIONS TRACE HEAD; do
  response=$(curl -s -o /dev/null -w "%{http_code}" 
    -X $method https://api.example.com/v1/users 
    -H "Authorization: Bearer $TOKEN")
  echo "$method: $response"
done

# Hata mesajlarında bilgi sızıntısı kontrolü
curl -s "https://api.example.com/v1/users/999999999" 
  -H "Authorization: Bearer $TOKEN" | jq .

# Stack trace veya internal path bilgisi açığa çıkıyor mu?
# Debug endpoint'leri kontrolü
for endpoint in /debug /actuator /metrics /health/details /swagger-ui /api-docs; do
  code=$(curl -s -o /dev/null -w "%{http_code}" 
    https://api.example.com$endpoint)
  echo "$endpoint: $code"
done

Production’da kapatılması gereken endpoint’ler için Spring Boot örneği:

# application-production.yml
management:
  endpoints:
    web:
      exposure:
        include: health  # Sadece health endpoint'i aç
  endpoint:
    health:
      show-details: never  # Detayları gizle
  server:
    port: 8081  # Farklı port, iç ağa kapat

Fuzzing ile Bilinmeyen Endpoint’leri Keşfetmek

Dokümanlarda olmayan endpoint’leri bulmak için fuzzing oldukça etkili:

# ffuf ile API endpoint discovery
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/api/api-endpoints.txt 
  -u https://api.example.com/v1/FUZZ 
  -H "Authorization: Bearer $TOKEN" 
  -H "Content-Type: application/json" 
  -mc 200,201,204,301,302,403 
  -o results.json 
  -of json

# Parametre fuzzing
ffuf -w params_wordlist.txt 
  -u "https://api.example.com/v1/users?FUZZ=test" 
  -H "Authorization: Bearer $TOKEN" 
  -mc 200 
  -fs 0

# Version fuzzing - eski API versiyonları
ffuf -w versions.txt 
  -u https://api.example.com/FUZZ/users 
  -H "Authorization: Bearer $TOKEN" 
  -mc 200,201

Nuclei ile Otomatik Zafiyet Taraması

# Nuclei template'lerini güncelle
nuclei -update-templates

# API güvenlik testleri için özel template kategorileri
nuclei -target https://api.example.com 
  -tags api,token,jwt,auth 
  -H "Authorization: Bearer $TOKEN" 
  -severity medium,high,critical 
  -o nuclei_results.txt

# Sadece JWT açıkları için
nuclei -target https://api.example.com 
  -t ~/nuclei-templates/vulnerabilities/generic/jwt-none-algorithm.yaml 
  -t ~/nuclei-templates/exposures/tokens/ 
  -o jwt_test_results.txt

# OWASP API Top 10 template'leri
nuclei -target https://api.example.com 
  -t ~/nuclei-templates/misconfiguration/api/ 
  -H "Authorization: Bearer $TOKEN"

CI/CD Pipeline’a Güvenlik Testleri Entegre Etmek

Manuel testler yeterli değil. Her deployment’ta otomatik çalışacak güvenlik testleri kurman gerekiyor.

#!/bin/bash
# api-security-test.sh - CI/CD pipeline'da çalışacak script

API_URL="${1:-https://staging-api.example.com}"
TOKEN="${API_TOKEN}"
FAILED=0

echo "=== API Güvenlik Testi Başlıyor ==="
echo "Hedef: $API_URL"

# 1. Temel auth kontrolü
echo "[*] Authentication kontrolü yapılıyor..."
no_auth_response=$(curl -s -o /dev/null -w "%{http_code}" 
  "$API_URL/v1/users/me")
if [ "$no_auth_response" != "401" ]; then
  echo "[FAIL] /v1/users/me token olmadan $no_auth_response döndürüyor!"
  FAILED=1
else
  echo "[PASS] Authentication kontrolü başarılı"
fi

# 2. Security headers kontrolü
echo "[*] Security headers kontrol ediliyor..."
headers=$(curl -sI "$API_URL/v1/health")

for header in "X-Content-Type-Options" "X-Frame-Options" "Strict-Transport-Security"; do
  if echo "$headers" | grep -qi "$header"; then
    echo "[PASS] $header mevcut"
  else
    echo "[WARN] $header eksik"
  fi
done

# 3. Rate limiting kontrolü
echo "[*] Rate limiting test ediliyor..."
for i in $(seq 1 15); do
  code=$(curl -s -o /dev/null -w "%{http_code}" 
    -X POST "$API_URL/auth/login" 
    -H "Content-Type: application/json" 
    -d '{"username":"test","password":"wrong"}')
  if [ "$code" == "429" ]; then
    echo "[PASS] Rate limiting $i. denemede devreye girdi"
    break
  fi
  if [ $i -eq 15 ]; then
    echo "[FAIL] Rate limiting çalışmıyor!"
    FAILED=1
  fi
done

# 4. HTTPS zorlaması
echo "[*] HTTPS yönlendirmesi kontrol ediliyor..."
http_response=$(curl -s -o /dev/null -w "%{http_code}" 
  --max-redirs 0 
  "http://$(echo $API_URL | sed 's|https://||')/v1/health")
if [ "$http_response" == "301" ] || [ "$http_response" == "308" ]; then
  echo "[PASS] HTTP -> HTTPS yönlendirmesi mevcut"
else
  echo "[FAIL] HTTPS yönlendirmesi yok! HTTP kodu: $http_response"
  FAILED=1
fi

echo "=== Test Tamamlandı ==="
exit $FAILED
# .gitlab-ci.yml - GitLab CI entegrasyonu
api-security-test:
  stage: security
  image: ubuntu:22.04
  before_script:
    - apt-get update -qq && apt-get install -y curl jq
  script:
    - chmod +x ./scripts/api-security-test.sh
    - ./scripts/api-security-test.sh $STAGING_API_URL
  variables:
    API_TOKEN: $STAGING_API_TOKEN
  only:
    - main
    - develop
  allow_failure: false

Güvenli API Tasarımı İçin Checklist

Production’a geçmeden önce mutlaka kontrol etmen gereken maddeler:

Authentication ve Authorization:

  • Her endpoint için authentication zorunlu mu?
  • Object level authorization (BOLA) kontrolleri var mı?
  • Function level authorization (admin vs user) kontrolleri var mı?
  • JWT secret key’leri yeterince güçlü mü ve rotate ediliyor mu?

Input Validation:

  • Tüm input’lar whitelist ile validate ediliyor mu?
  • SQL, NoSQL, LDAP injection korumaları var mı?
  • File upload endpoint’lerinde tip ve boyut kontrolü yapılıyor mu?

Rate Limiting ve DoS Koruması:

  • Login endpoint’lerinde agresif rate limiting var mı?
  • API genelinde istek boyutu limiti var mı?
  • Endpoint bazında rate limiting uygulandı mı?

Data Exposure:

  • Response’larda sadece gerekli alanlar mı dönüyor?
  • Hata mesajları internal detay içeriyor mu?
  • Debug logları production’da kapalı mı?

Güvenli Yapılandırma:

  • Swagger/OpenAPI sadece geliştirme ortamında mı açık?
  • HTTP metodları gereksiz olanlar için engellenmiş mi?
  • CORS politikası wildcard (*) kullanmıyor mu?

Tespit Edilen Açıkları Önceliklendirmek

Her açık eşit önem taşımıyor. CVSS skorlama sistemini kullanarak önceliklendirme yapabilirsin. Gerçek dünya deneyimine göre şu sırayı öneririm:

Kritik (hemen düzelt): Authentication bypass, SQL injection, hassas veri sızıntısı, authorization eksikliği

Yüksek (bu sprint içinde): Brute force koruması eksikliği, IDOR, security misconfiguration

Orta (bir sonraki sprint): Excessive data exposure, eksik rate limiting, zayıf şifreleme

Düşük (backlog): Eksik security header’ları, verbose hata mesajları, eski TLS versiyonu

Sonuç

API güvenliği tek seferlik bir iş değil, sürekli bir süreç. Geliştirme aşamasında SAST araçlarıyla statik analiz, test aşamasında bu yazıda anlattığım dinamik testler, production’da ise sürekli izleme ve penetrasyon testleri döngüsü kurman gerekiyor.

En sık gördüğüm hatalar şunlar: Geliştiriciler frontend’in veriyi filtrelediğini düşünerek API’ı açık bırakıyor. “İç ağda çalışıyor zaten” mantığıyla internal API’lar korumasız kalıyor. Ya da token validation kodu yazılıyor ama her endpoint’e uygulanmıyor.

Bu yazıdaki test scriptlerini kendi API’larına adapte ederek CI/CD pipeline’ına eklemen, güvenlik açıklarını production’a taşımadan önce yakalamanı sağlayacak. Unutma, bir saldırgan API’ını bulduğunda test etmek için senin izninle beklemiyor. Sen daha önce test etmiş olmak zorundasın.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir