CORS Yanlış Yapılandırmaları

CORS (Cross-Origin Resource Sharing) , bir web sayfasının, kendi kaynağının bulunduğu domain dışındaki domainlere API istekleri yapabilmesini sağlayan bir mekanizmadır. Tarayıcılar, güvenlik nedeniyle varsayılan olarak cross-origin isteklerini kısıtlar. CORS, bu kısıtlamaları güvenli bir şekilde yönetmek için kullanılan bir protokoldür.

CORS Nasıl Çalışır?
CORS, HTTP header'ları aracılığıyla çalışır. Tarayıcı, cross-origin istek yaparken sunucuya Origin header'ını gönderir. Sunucu, bu origin'e izin verip vermediğini Access-Control-Allow-Origin header'ı ile belirtir.

Basit İstek:

http
GET /api/users HTTP/1.1
Host: api.hedef.com
Origin: https://hedef.com
Sunucu Yanıtı:

http
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://hedef.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: X-Total-Count
Preflight İsteği (OPTIONS):
Tarayıcı, özel header'lar veya farklı HTTP metodları kullanılmadan önce OPTIONS isteği gönderir.

http
OPTIONS /api/users HTTP/1.1
Host: api.hedef.com
Origin: https://hedef.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: X-Custom-Header
Preflight Yanıtı:

http
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://hedef.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 3600
CORS Güvenlik Riskleri:
1. Access-Control-Allow-Origin: * Kullanımı
Risk: Herhangi bir domainin API'ye erişebilmesi.

Örnek:

http
Access-Control-Allow-Origin: *
Bu yapılandırma, internetteki herhangi bir sitenin API'ye istek gönderebilmesine olanak tanır. Sadece public API'ler veya statik dosyalar için kullanılmalıdır.

Çözüm:

Sadece güvenilir domain'lere izin verin.

Dinamik olarak domain'i kontrol edin ve yanıtlayın.

2. Access-Control-Allow-Credentials: true ile * Birlikte Kullanımı
Risk: Çerez, token gibi hassas bilgilerin herhangi bir domaine gönderilmesi.

Örnek:

http
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Bu yapılandırma, credential'ların (çerez, Authorization header, TLS client certificates) herhangi bir domain'e gönderilmesine izin verir.

NOT: Tarayıcılar, Access-Control-Allow-Origin: * ve Access-Control-Allow-Credentials: true kombinasyonuna izin vermez. Ancak saldırganlar, Access-Control-Allow-Origin: https://saldirgan.com şeklinde spesifik bir domain kullanarak credential'ları ele geçirebilir.

Çözüm:

Credential'lar (çerez, token) taşıyan isteklerde asla * kullanmayın.

Sadece güvenilir domain'lere credential gönderin.

Access-Control-Allow-Credentials sadece gerektiğinde true yapın.

3. Origin Validasyonu Eksikliği veya Zayıf Validasyon
Risk: Saldırganın Origin header'ını manipüle ederek API'ye erişmesi.

Örnek Zayıf Validasyon:

python
origin = request.headers.get('Origin')
if 'hedef.com' in origin:
response.headers['Access-Control-Allow-Origin'] = origin
Bu validasyon şu durumlarda atlatılabilir:




Çözüm:

Tam eşleştirme (exact match) kullanın.

Regex ile domain'in sonunu kontrol etmeyin.

Beyaz liste kullanın.

4. Wildcard Subdomain Kullanımı
Risk: Tüm alt domain'lere izin verilmesi.

Örnek:

http
Access-Control-Allow-Origin: *.hedef.com
Eğer alt domain'lerden biri ele geçirilirse, tüm sistem risk altına girer.

Çözüm:

İzin verilen domain'leri tek tek listeleyin.

Wildcard kullanmaktan kaçının.

5. Access-Control-Allow-Headers veya Access-Control-Expose-Headers ile Bilgi Sızdırma
Risk: Hassas header'ların client tarafına açılması.

Örnek:

http
Access-Control-Expose-Headers: X-Auth-Token
Çözüm:

Sadece gerekli header'ları expose edin.

Hassas bilgi içeren header'ları expose etmeyin.

6. Preflight Önbellekleme (Max-Age)
Risk: Uzun süreli önbellekleme ile güvenlik politikalarının etrafından dolaşılması.

Örnek:

http
Access-Control-Max-Age: 86400 # 24 saat
Uzun süreli önbellekleme, güncellenen güvenlik politikalarının uygulanmasını geciktirebilir.

Çözüm:

Makul bir max-age (örn: 3600 - 1 saat) kullanın.

Güvenlik politikası değiştiğinde önbelleğin temizlenmesini sağlayın.

7. Null Origin
Risk: Origin: null değerinin kabul edilmesi.

http
Origin: null
Bu değer, iframe içinde veya data: URL'lerinden gelen isteklerde görülür.

Çözüm:

Origin: null değerini reddedin.

Sadece geçerli HTTP/HTTPS origin'lerini kabul edin.

CORS Güvenli Uygulama Teknikleri:
1. Dinamik Origin Validasyonu
python
from urllib.parse import urlparse

ALLOWED_ORIGINS = [
'https://hedef.com',
'https://www.hedef.com',
'https://api.hedef.com'
]

def get_cors_origin(request):
origin = request.headers.get('Origin')

if not origin:
return None

# Sadece HTTP/HTTPS protokollerine izin ver
parsed = urlparse(origin)
if parsed.scheme not in ['http', 'https']:
return None

# Tam eşleştirme kontrolü
if origin in ALLOWED_ORIGINS:
return origin

# Subdomain kontrolü (isteğe bağlı)
# Sadece güvenilir subdomain'lere izin ver
if origin.startswith('https://') and origin.endswith('.hedef.com'):
# Belirli alt domain'leri kontrol et
allowed_subdomains = ['app.hedef.com', 'dashboard.hedef.com']
if origin in [f'https://{sub}' for sub in allowed_subdomains]:
return origin

return None

# Flask örneği
@app.after_request
def add_cors_headers(response):
origin = request.headers.get('Origin')
allowed_origin = get_cors_origin(request)

if allowed_origin:
response.headers['Access-Control-Allow-Origin'] = allowed_origin

# Credential'ları sadece gerektiğinde gönder
if request.method == 'GET' and request.headers.get('Authorization'):
response.headers['Access-Control-Allow-Credentials'] = 'true'

# Preflight yanıtları
if request.method == 'OPTIONS':
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type, X-Requested-With'
response.headers['Access-Control-Max-Age'] = '3600' # 1 saat
response.status_code = 204

return response
2. Django CORS Yapılandırması
python
# settings.py
CORS_ALLOWED_ORIGINS = [
'https://hedef.com',
'https://www.hedef.com',
'https://api.hedef.com',
]

CORS_ALLOWED_ORIGIN_REGEXES = [
r'^https://(app|dashboard)\.hedef\.com$',
]

CORS_ALLOW_CREDENTIALS = True # Sadece gerekirse

CORS_ALLOW_METHODS = [
'GET',
'POST',
'PUT',
'DELETE',
'OPTIONS',
]

CORS_ALLOW_HEADERS = [
'Authorization',
'Content-Type',
'X-Requested-With',
]
3. Nginx CORS Yapılandırması
nginx
location /api/ {
# CORS header'ları
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://hedef.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, X-Requested-With';
add_header 'Access-Control-Max-Age' 3600;
return 204;
}

# Dinamik origin kontrolü
set $cors_origin '';
if ($http_origin ~ '^https://(www\.|api\.)?hedef\.com$') {
set $cors_origin $http_origin;
}

add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Credentials' 'true' always;

proxy_pass http://backend;
}
4. CORS Test Araçları
Tarayıcı Konsolu ile Test:

javascript
// Basit GET testi
fetch('https://api.hedef.com/users', {
method: 'GET',
credentials: 'include'
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('CORS error:', error));

// Preflight testi (DELETE)
fetch('https://api.hedef.com/users/123', {
method: 'DELETE',
headers: {
'Authorization': 'Bearer token',
'X-Custom-Header': 'value'
},
credentials: 'include'
})
.then(response => console.log('Success'))
.catch(error => console.error('CORS error:', error));
Chrome CORS Testi:

DevTools → Network sekmesi

Cross-origin istekleri inceleyin

Access-Control-Allow-Origin header'ını kontrol edin

Otomatik Araçlar:

Burp Suite: CORS scanner

Nuclei: CORS template'leri

CORS-Misconfiguration: Özel test aracı

CORS Güvenlik Kontrol Listesi:
A. Origin Validasyonu:
Access-Control-Allow-Origin: * kullanılmıyor mu? (credential varsa)

Origin header'ı doğrulanıyor mu?

Tam eşleştirme (exact match) yapılıyor mu?

Beyaz liste kullanılıyor mu?

Origin: null reddediliyor mu?

Sadece HTTP/HTTPS protokolleri kabul ediliyor mu?

B. Credential Güvenliği:
Access-Control-Allow-Credentials: true sadece gerektiğinde mi kullanılıyor?

Credential içeren isteklerde * kullanılmıyor mu?

Authorization header'ı ile CORS kontrolü yapılıyor mu?

C. Preflight (OPTIONS) Yapılandırması:
Access-Control-Allow-Methods doğru listelenmiş mi?

Access-Control-Allow-Headers sadece gerekli header'ları içeriyor mu?

Access-Control-Max-Age makul bir sürede mi (3600-7200)?

D. Expose Header'ları:
Access-Control-Expose-Headers hassas bilgi içermiyor mu?

Sadece gerekli header'lar expose ediliyor mu?

E. Test ve İzleme:
CORS testleri yapıldı mı?

Farklı origin'lerden (allow/deny) test edildi mi?

Preflight (OPTIONS) testleri yapıldı mı?

Anormal CORS istekleri loglanıyor mu?

Özel Senaryolar:
1. Public API'ler
Public API'lerde Access-Control-Allow-Origin: * kullanılabilir (credential olmadan).

http
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: false
2. API Gateway ile CORS
API Gateway (AWS, Kong, Tyk) kullanıyorsanız, CORS'u gateway seviyesinde yönetin.

AWS API Gateway Örneği:

yaml
# AWS SAM template
Cors:
AllowOrigins:
- 'https://hedef.com'
- 'https://www.hedef.com'
AllowMethods:
- GET
- POST
- PUT
- DELETE
AllowHeaders:
- Authorization
- Content-Type
MaxAge: 3600
3. Wildcard Subdomain Kullanımı (Riskli)
Eğer wildcard subdomain kullanmak zorundaysanız:

python
import re

def is_allowed_subdomain(origin):
# Sadece belirli subdomain pattern'lerine izin ver
pattern = r'^https://(app|dashboard|api)-\d+\.hedef\.com$'
return bool(re.match(pattern, origin))
4. CORS ve CSP Birlikte Kullanımı
CORS ile birlikte CSP (Content Security Policy) kullanarak ekstra güvenlik katmanı oluşturun.

http
Content-Security-Policy: default-src 'self'; connect-src https://api.hedef.com

🔒 Bu içeriği görmek için giriş yapın

 
Yanıt yazmak için giriş yapmalısınız
Forum özelliklerini kullanmak ve Level 2 üyelik satın almak için hesabınıza giriş yapın.
133,663Konular
3,288,256Mesajlar
324,335Kullanıcılar
hbi14Son Üye
Üst Alt