REST API Güvenliği: OWASP Top 10 API Riskleri ve Çözümleri
Modern uygulamaların omurgası haline gelen REST API’ler, her geçen gün daha fazla kritik veriyi taşıyor. Bir yanda mobil uygulamalar, öte yanda mikroservis mimarileri, IoT cihazları ve üçüncü taraf entegrasyonlar… Tüm bu trafiğin merkezinde API’ler var. Ve tabii ki saldırganlar da bunu çok iyi biliyor. OWASP, 2023 yılında API güvenliğine özel bir Top 10 listesi yayınladı. Bu yazıda o listeyi sysadmin gözüyle inceleyeceğiz, gerçek dünya senaryolarıyla ele alacağız ve her risk için pratik önlemler göstereceğiz.
OWASP API Security Top 10 Nedir?
OWASP (Open Web Application Security Project), web ve API güvenliğinin referans noktası. API Security Top 10 listesi, dünya genelindeki gerçek ihlallerin analizinden çıkmış. Yani teorik değil, sahada yaşanmış riskleri kapsıyor. Sysadmin olarak bu listeyi bilmek, hem mevcut API’leri güvence altına almak hem de yeni kurulumları doğru yapılandırmak açısından kritik.
Hemen konuya girelim.
API1: Broken Object Level Authorization (BOLA)
Bu liste içindeki en yaygın ve en yıkıcı açık. Bir kullanıcının başka bir kullanıcının verisine erişebildiği durumdur. Senaryoyu somutlaştıralım: Bir e-ticaret API’sinde /api/orders/12345 endpoint’ine istek atıyorsunuz ve kendi siparişinizi görüyorsunuz. Peki ya /api/orders/12344 yazarsanız? Eğer yetki kontrolü yoksa başkasının siparişini de görürsünüz.
Nasıl Tespit Edilir?
# Burp Suite veya curl ile basit bir BOLA testi
# Önce kendi token'ınızla istek atın
curl -H "Authorization: Bearer eyJuser1token..."
https://api.example.com/api/v1/users/1001/profile
# Sonra başka bir kullanıcının ID'siyle deneyin
curl -H "Authorization: Bearer eyJuser1token..."
https://api.example.com/api/v1/users/1002/profile
# Eğer 200 döndürüyorsa BOLA açığı var
Önlem: Nginx ile Rate Limiting ve Log Analizi
# /etc/nginx/conf.d/api-security.conf
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $http_authorization zone=api_token:10m rate=30r/m;
server {
location /api/v1/ {
limit_req zone=api burst=20 nodelay;
limit_req zone=api_token burst=10 nodelay;
# Object ID'leri loglayın
log_format api_access '$remote_addr - $http_authorization '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
access_log /var/log/nginx/api_access.log api_access;
}
}
Uygulama tarafında her nesne erişiminde kullanıcı sahipliği kontrol edilmeli. ID’ler sıralı integer yerine UUID olmalı.
API2: Broken Authentication
Token yönetimi hataları, zayıf şifre politikaları ve eksik çok faktörlü doğrulama bu kategoriye giriyor. JWT token’larının yanlış yapılandırılması özellikle yaygın.
JWT Güvenlik Kontrolü
# JWT token'ının algorithm kontrolü
# "alg: none" saldırısını simüle etmek için
# Önce token'ı decode edin (header kısmı)
echo "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0" | base64 -d
# Çıktı: {"alg":"none","typ":"JWT"}
# Bu token backend tarafından kabul ediliyorsa kritik açık var!
# Güvenli JWT doğrulama script'i
#!/bin/bash
TOKEN=$1
HEADER=$(echo $TOKEN | cut -d'.' -f1 | base64 -d 2>/dev/null)
ALG=$(echo $HEADER | python3 -c "import sys,json; print(json.load(sys.stdin).get('alg','unknown'))")
if [ "$ALG" = "none" ] || [ "$ALG" = "None" ]; then
echo "KRITIK: 'alg:none' token tespit edildi!"
exit 1
fi
echo "Algorithm: $ALG - OK"
Fail2ban ile Brute Force Koruması
# /etc/fail2ban/filter.d/api-auth.conf
[Definition]
failregex = ^<HOST> .* "POST /api/v1/auth/login HTTP.*" 401
^<HOST> .* "POST /api/v1/auth/token HTTP.*" 403
ignoreregex =
# /etc/fail2ban/jail.local
[api-auth]
enabled = true
port = http,https
filter = api-auth
logpath = /var/log/nginx/api_access.log
maxretry = 5
findtime = 300
bantime = 3600
API3: Broken Object Property Level Authorization (BOPLA)
BOLA’nın kardeşi ama daha ince. Bir kullanıcı bir nesneye erişebiliyor ama o nesnenin tüm alanlarını görmemeli. Örneğin bir kullanıcı profili dönerken admin: true, internal_credit_score: 850, ssn: "123-45-6789" gibi alanlar gönderiliyorsa bu ciddi bir veri sızıntısı.
Hassas Alan Tespiti için Otomatik Test
#!/bin/bash
# API yanıtındaki hassas alanları tara
RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN"
https://api.example.com/api/v1/users/me)
# Hassas kelime listesi
SENSITIVE_FIELDS=("password" "ssn" "credit_card" "secret" "internal" "admin" "is_admin" "role" "salary")
echo "Yanıt analiz ediliyor..."
for field in "${SENSITIVE_FIELDS[@]}"; do
if echo "$RESPONSE" | grep -qi ""$field""; then
echo "UYARI: '$field' alanı API yanıtında mevcut!"
fi
done
# Tüm alanları listele
echo -e "nMevcut alanlar:"
echo "$RESPONSE" | python3 -c "
import sys, json
data = json.load(sys.stdin)
for key in data.keys():
print(f' - {key}')
"
Çözüm, response şemalarını katı biçimde tanımlamak ve her endpoint için sadece gerekli alanları döndürmek. Bu “data minimization” prensibi GDPR açısından da zorunlu.
API4: Unrestricted Resource Consumption
API’yi çözen en klasik sorunlardan biri: kaynak tükenmesi. Dosya yükleme boyut limiti yok, pagination yok, rate limit yok. Birisi /api/users?limit=999999 dese ne olur? Veritabanı çöker.
Kapsamlı Rate Limiting ve Resource Control
# /etc/nginx/nginx.conf - Genel limitler
http {
# Bağlantı limitleri
limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_req_zone $binary_remote_addr zone=global:10m rate=100r/s;
# Upload boyut limiti
client_max_body_size 10m;
client_body_timeout 30s;
client_header_timeout 15s;
# Buffer limitleri - slow loris saldırılarına karşı
client_body_buffer_size 128k;
large_client_header_buffers 4 32k;
}
server {
# Endpoint bazlı limitler
location /api/v1/upload {
limit_req zone=global burst=5 nodelay;
limit_conn addr 3;
client_max_body_size 5m;
}
location /api/v1/search {
limit_req zone=global burst=10 nodelay;
# Search endpoint'i daha kısıtlı
proxy_read_timeout 10s;
}
}
Pagination Zorunluluğu Kontrolü
# API'nin pagination olmadan büyük veri döndürüp döndürmediğini test et
curl -s -o /dev/null -w "%{size_download}"
-H "Authorization: Bearer $TOKEN"
"https://api.example.com/api/v1/products" |
awk '{if ($1 > 1048576) print "UYARI: 1MB üzeri yanıt! Pagination eksik olabilir."}'
API5: Broken Function Level Authorization
Admin endpoint’leri kullanıcılara erişilebilir mi? /api/admin/users/delete endpoint’i normal bir kullanıcı token’ıyla çağrılabiliyor mu? Bu açık çoğunlukla tahmin yürütme ve brute force ile keşfedilir.
Admin Endpoint Tarama ve Koruma
# Yaygın admin path'lerini test eden script
#!/bin/bash
BASE_URL="https://api.example.com"
USER_TOKEN="eyJhbGc..."
ADMIN_PATHS=(
"/api/admin"
"/api/v1/admin"
"/api/management"
"/api/internal"
"/api/debug"
"/api/config"
"/actuator"
"/actuator/env"
"/actuator/health"
"/.well-known/security.txt"
)
echo "Admin endpoint taraması başlatılıyor..."
for path in "${ADMIN_PATHS[@]}"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}"
-H "Authorization: Bearer $USER_TOKEN"
"$BASE_URL$path")
if [ "$STATUS" = "200" ] || [ "$STATUS" = "201" ]; then
echo "KRITIK: $path - HTTP $STATUS (normal token ile erişilebilir!)"
elif [ "$STATUS" = "403" ]; then
echo "OK: $path - HTTP $STATUS (erişim engellendi)"
elif [ "$STATUS" = "404" ]; then
echo "INFO: $path - HTTP $STATUS (bulunamadı)"
fi
done
Nginx seviyesinde admin endpoint’lerini IP kısıtlamasıyla koruyun:
# /etc/nginx/conf.d/api-admin.conf
location /api/admin {
# Sadece iç ağdan erişim
allow 10.0.0.0/8;
allow 192.168.1.0/24;
deny all;
# Ek olarak mTLS zorunluluğu
ssl_verify_client on;
ssl_client_certificate /etc/nginx/client-certs/ca.crt;
proxy_pass http://admin-backend;
}
API6: Unrestricted Access to Sensitive Business Flows
Bu biraz daha iş mantığına özgü. Örneğin bir bilet satış sistemi düşünün: Biriisi botlarla saniyede 1000 bilet satın alma isteği gönderiyor. Rate limit yok, captcha yok, davranış analizi yok. Tüm biletler dakikalar içinde tükeniyor.
Davranış Tabanlı Anomali Tespiti
#!/bin/bash
# Son 1 dakikadaki şüpheli istek örüntülerini tespit et
LOG_FILE="/var/log/nginx/api_access.log"
echo "=== Son 60 Saniyedeki Şüpheli Aktiviteler ==="
# Aynı IP'den 60 saniyede 100'den fazla istek
echo -e "n[Yüksek Frekanslı IP'ler]"
awk -v date="$(date -d '1 minute ago' '+%d/%b/%Y:%H:%M')"
'$0 ~ date {print $1}' $LOG_FILE |
sort | uniq -c | sort -rn |
awk '$1 > 100 {print "UYARI: IP " $2 " -> " $1 " istek/dakika"}'
# Aynı endpoint'e tekrarlayan başarısız istekler
echo -e "n[Başarısız İstek Örüntüleri]"
grep " 4[0-9][0-9] " $LOG_FILE |
awk '{print $1, $7}' |
sort | uniq -c | sort -rn | head -10
# Kullanıcı başına satın alma frekansı (business flow)
echo -e "n[Şüpheli Purchase Aktivitesi]"
grep "POST /api/v1/purchase" $LOG_FILE |
grep " 200 " |
awk '{print $6}' |
sort | uniq -c | sort -rn |
awk '$1 > 10 {print "UYARI: Token " $2 " -> " $1 " başarılı purchase"}'
API7: Server Side Request Forgery (SSRF)
API’ye dışarıdan URL parametresi verebiliyorsanız ve bu URL API sunucusu tarafından ziyaret ediliyorsa SSRF var demektir. Saldırgan url=http://169.254.169.254/latest/meta-data/ gibi bir istek göndererek AWS metadata servisine erişebilir.
SSRF Testi ve Önlem
# SSRF açığı testi - metadata endpoint denemeleri
# (Sadece kendi sistemlerinizde test edin)
SSRF_PAYLOADS=(
"http://169.254.169.254/latest/meta-data/"
"http://metadata.google.internal/"
"http://localhost:8080/admin"
"http://127.0.0.1:6379"
"file:///etc/passwd"
)
for payload in "${SSRF_PAYLOADS[@]}"; do
echo "Test: $payload"
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}"
-X POST
-H "Content-Type: application/json"
-d "{"url": "$payload"}"
"https://api.example.com/api/v1/fetch-url")
echo "HTTP Status: $RESPONSE"
done
Önlem olarak outbound trafiği iptables ile kısıtlayın:
# API sunucusundan çıkan trafiği kısıtla
# Metadata endpoint'lerine erişimi engelle
iptables -A OUTPUT -d 169.254.169.254 -j DROP
iptables -A OUTPUT -d 169.254.0.0/16 -j DROP
# Sadece belirli dış adreslere izin ver
iptables -A OUTPUT -p tcp --dport 443 -d trusted-service.com -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j DROP
# Kuralları kaydet
iptables-save > /etc/iptables/rules.v4
API8: Security Misconfiguration
Yanlış yapılandırma her yerde karşımıza çıkıyor: CORS’un * ile açık bırakılması, debug modunun production’da aktif olması, stack trace’lerin kullanıcıya dönmesi, HTTP header’larının eksikliği.
Güvenlik Başlıklarını Kontrol Eden Script
#!/bin/bash
# API güvenlik header kontrolü
API_URL="https://api.example.com"
echo "=== Güvenlik Header Analizi: $API_URL ==="
HEADERS=$(curl -sI "$API_URL/api/v1/health")
check_header() {
local header=$1
local description=$2
if echo "$HEADERS" | grep -qi "^$header:"; then
echo "OK: $header mevcut"
else
echo "EKSIK: $header - $description"
fi
}
check_header "Strict-Transport-Security" "HTTPS zorunluluğu (HSTS)"
check_header "X-Content-Type-Options" "MIME sniffing koruması"
check_header "X-Frame-Options" "Clickjacking koruması"
check_header "Content-Security-Policy" "XSS koruması"
check_header "X-XSS-Protection" "Eski tarayıcı XSS koruması"
check_header "Referrer-Policy" "Referrer bilgisi kontrolü"
# CORS kontrolü
CORS=$(echo "$HEADERS" | grep -i "Access-Control-Allow-Origin")
if echo "$CORS" | grep -q "*"; then
echo "KRITIK: CORS wildcard (*) kullanımı tespit edildi!"
else
echo "OK: CORS kısıtlı: $CORS"
fi
# Sunucu bilgisi sızıntısı
SERVER=$(echo "$HEADERS" | grep -i "^Server:")
if echo "$SERVER" | grep -qiE "(apache|nginx|iis|php|express)/[0-9]"; then
echo "UYARI: Sunucu versiyon bilgisi sızıyor: $SERVER"
fi
# X-Powered-By kontrolü
POWERED=$(echo "$HEADERS" | grep -i "X-Powered-By")
if [ -n "$POWERED" ]; then
echo "UYARI: Teknoloji stack'i açık: $POWERED"
fi
API9: Improper Inventory Management
“Shadow API” problemi de denir. Eski API versiyonları (/api/v1/) production’da hala canlıyken yeni versiyona geçilmiş. Eski versiyon güncelleme almıyor, patch uygulanmıyor ama hala erişilebilir. Ya da belgelenmemiş internal endpoint’ler.
API Inventory Tarama
#!/bin/bash
# Aktif API endpoint'lerini keşfet ve belgele
BASE_URL="https://api.example.com"
# Yaygın API versiyonlarını tara
echo "=== API Versiyon Taraması ==="
for version in v1 v2 v3 v4 v5 v6 v7 v8 v9 v10; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}"
"$BASE_URL/api/$version/health" 2>/dev/null)
if [ "$STATUS" != "404" ]; then
echo "AKTIF: /api/$version/ - HTTP $STATUS"
fi
done
# Swagger/OpenAPI dokümantasyon endpoint'lerini kontrol et
echo -e "n=== Dokümantasyon Endpoint'leri ==="
DOC_PATHS=("/swagger-ui.html" "/api-docs" "/swagger.json"
"/openapi.json" "/api/swagger" "/docs" "/redoc")
for path in "${DOC_PATHS[@]}"; do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$BASE_URL$path")
if [ "$STATUS" = "200" ]; then
echo "BULUNDU: $path (kamuya açık mı kontrol edin!)"
fi
done
API10: Unsafe Consumption of APIs
Son madde biraz farklı: Kendi API’nizin tükettiği üçüncü taraf API’lere güvenmek. Bir ödeme gateway’inden gelen yanıtı doğrulamadan işliyorsanız, dış bir servisin döndürdüğü veriyi sanitize etmeden veritabanına yazıyorsanız risk var.
Dış API Yanıtlarını Valide Eden Script
#!/bin/bash
# Üçüncü taraf API yanıtını güvenli şekilde işle
EXTERNAL_API="https://payment-provider.com/api/verify"
PAYMENT_ID=$1
# SSL sertifikasını doğrula (pinning olmasa da en azından geçerli olmalı)
RESPONSE=$(curl -s
--cacert /etc/ssl/certs/trusted-ca-bundle.crt
--max-time 10
--max-filesize 102400
-H "Authorization: Bearer $PAYMENT_API_KEY"
"$EXTERNAL_API/transaction/$PAYMENT_ID")
# HTTP status kontrolü
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}"
--cacert /etc/ssl/certs/trusted-ca-bundle.crt
"$EXTERNAL_API/transaction/$PAYMENT_ID")
if [ "$HTTP_STATUS" != "200" ]; then
echo "HATA: Dış API beklenen yanıtı vermedi: HTTP $HTTP_STATUS"
exit 1
fi
# Yanıt boyutu kontrolü
RESPONSE_SIZE=$(echo "$RESPONSE" | wc -c)
if [ "$RESPONSE_SIZE" -gt 102400 ]; then
echo "UYARI: Anormal büyük yanıt: $RESPONSE_SIZE byte"
exit 1
fi
# Beklenen alanları doğrula
AMOUNT=$(echo "$RESPONSE" | python3 -c "
import sys, json
try:
data = json.load(sys.stdin)
if 'amount' not in data or 'status' not in data:
print('INVALID_SCHEMA')
sys.exit(1)
# Amount negatif olamaz
if float(data['amount']) < 0:
print('NEGATIVE_AMOUNT')
sys.exit(1)
print(data['amount'])
except:
print('PARSE_ERROR')
sys.exit(1)
")
echo "Doğrulanmış tutar: $AMOUNT"
Genel API Güvenlik Hardening Checklist
Tüm bu maddeleri kapsayan bir hardening script’i işinizi kolaylaştırır:
#!/bin/bash
# API Security Baseline Audit Script
echo "======================================"
echo " API Güvenlik Temel Kontrol Raporu "
echo "======================================"
echo "Tarih: $(date)"
echo ""
SCORE=0
TOTAL=0
ISSUES=()
check() {
local description=$1
local command=$2
TOTAL=$((TOTAL + 1))
if eval "$command" > /dev/null 2>&1; then
echo "PASS: $description"
SCORE=$((SCORE + 1))
else
echo "FAIL: $description"
ISSUES+=("$description")
fi
}
# TLS kontrolü
check "TLS 1.2+ zorunlu"
"nginx -T 2>/dev/null | grep -q 'ssl_protocols.*TLSv1.[23]'"
# HTTP/2 desteği
check "HTTP/2 aktif"
"nginx -T 2>/dev/null | grep -q 'listen.*http2'"
# Rate limiting aktif mi
check "Rate limiting tanımlı"
"nginx -T 2>/dev/null | grep -q 'limit_req_zone'"
# Fail2ban çalışıyor mu
check "Fail2ban servisi aktif"
"systemctl is-active fail2ban"
# Güvenlik duvarı aktif mi
check "UFW/iptables aktif"
"ufw status | grep -q 'Status: active' || iptables -L | grep -q 'Chain'"
# Log rotation tanımlı mı
check "API log rotation tanımlı"
"ls /etc/logrotate.d/ | grep -qiE 'nginx|apache'"
echo ""
echo "Sonuç: $SCORE/$TOTAL kontrol geçti"
if [ ${#ISSUES[@]} -gt 0 ]; then
echo ""
echo "Düzeltilmesi Gereken Konular:"
for issue in "${ISSUES[@]}"; do
echo " - $issue"
done
fi
Sonuç
OWASP API Security Top 10, bir kontrol listesinden öte bir bakış açısı sunuyor. Her maddeye baktığınızda şunu görüyorsunuz: Çoğu açık teknik bir sihirbazlık gerektirmiyor, temel güvenlik prensiplerinin uygulanmamasından kaynaklanıyor.
Sysadmin perspektifinden bakarsak:
- Altyapı seviyesinde rate limiting, güvenlik header’ları ve ağ segmentasyonu büyük farklar yaratıyor.
- Log analizi sadece sorun olduğunda değil, düzenli olarak yapılmalı. Anomalileri önceden yakalamak mümkün.
- Otomasyon şart. Güvenlik kontrolleri manuel yapılırsa kaçınılmaz olarak atlanıyor.
- API envanteri tutmak, hangi endpoint’lerin canlı olduğunu bilmek temel bir gereklilik.
Bu yazıdaki script’leri olduğu gibi alıp çalıştırmayın, önce test ortamında deneyin ve kendi altyapınıza göre uyarlayın. Her ortam farklı, her API farklı. Ama temel prensipler evrensel: en az yetki, girdi doğrulama, çıktı filtreleme, izleme ve kayıt tutma.
API güvenliği bir kez yapılıp bırakılan bir şey değil, sürekli gözden geçirilmesi gereken bir süreç. OWASP listesi de bu yüzden düzenli güncelleniyor. Takipte kalın.
