API Güvenliği & Web Güvenliği 6 dk okuma 2 okunma

API'lerde CORS ve Güvenlik Başlıkları

CORS (Cross-Origin Resource Sharing) mekanizmasının nasıl çalıştığı, same-origin politikası, preflight istekleri, ASP.NET Core'da CORS yapılandırması, güvenlik başlıkları (CSP, HSTS, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy) ve bu başlıkların API güvenliğindeki rolü ele alınır.

API'lerde CORS ve Güvenlik Başlıkları

API'lerde CORS ve Güvenlik Başlıkları

Modern web uygulamalarında API güvenliği, yalnızca kimlik doğrulama ve yetkilendirme ile sınırlı değildir. Tarayıcı tabanlı istemcilerin API'nize güvenli bir şekilde erişebilmesi için CORS (Cross-Origin Resource Sharing) ve bir dizi güvenlik başlığı (security headers) doğru şekilde yapılandırılmalıdır. Yanlış yapılandırılmış CORS, API'nizi CSRF (Cross-Site Request Forgery) saldırılarına açık hale getirirken; eksik güvenlik başlıkları, XSS (Cross-Site Scripting) ve clickjacking gibi saldırılara zemin hazırlar. Bu yazıda, CORS mekanizmasını ve kritik güvenlik başlıklarını .NET/ASP.NET Core örnekleriyle detaylıca ele alacağız.


1. CORS Nedir ve Neden Gerekli?

Same-Origin Policy (Aynı Kaynak Politikası), tarayıcıların güvenlik modelinin temelidir. Bir web sayfası (https://app.example.com), yalnızca aynı origin'e (protokol + alan adı + port) sahip kaynaklara istek yapabilir. Farklı bir origin'e (https://api.example.com) istek yapıldığında, tarayıcı bu isteği engeller.

Origin Nedir? Protokol + Alan Adı + Port üçlüsüdür:

  • https://app.example.com ve https://api.example.com → Farklı origin (farklı alan adı)

  • http://app.example.com ve https://app.example.com → Farklı origin (farklı protokol)

  • https://app.example.com:443 ve https://app.example.com:8443 → Farklı origin (farklı port)

CORS (Cross-Origin Resource Sharing), sunucuların, tarayıcılara "bu origin'den gelen isteklere izin veriyorum" demesini sağlayan bir mekanizmadır. Sunucu, yanıta belirli başlıklar ekleyerek tarayıcıya izin verir.


2. CORS Çalışma Mekanizması

A. Basit İstekler (Simple Requests)
Aşağıdaki koşulları sağlayan istekler, tarayıcı tarafından doğrudan gönderilir (preflight olmadan):

  • Metot: GET, HEAD, POST

  • Başlıklar: Sadece Accept, Accept-Language, Content-Language, Content-Type (sadece application/x-www-form-urlencoded, multipart/form-data, text/plain)

B. Preflight İstekleri (Ön Uçuş)
Basit olmayan istekler (ör. PUT, DELETE, application/json içeren POST, özel başlıklar) için tarayıcı önce bir OPTIONS isteği gönderir. Buna preflight denir.

Preflight Akışı:

text

1. Tarayıcı → OPTIONS /api/orders
   Origin: https://app.example.com
   Access-Control-Request-Method: POST
   Access-Control-Request-Headers: Content-Type, Authorization

2. Sunucu → 204 No Content
   Access-Control-Allow-Origin: https://app.example.com
   Access-Control-Allow-Methods: GET, POST, PUT, DELETE
   Access-Control-Allow-Headers: Content-Type, Authorization
   Access-Control-Max-Age: 86400

3. Tarayıcı → POST /api/orders (gerçek istek)

Access-Control-Max-Age, preflight yanıtının tarayıcıda ne kadar süre önbelleğe alınacağını belirtir (saniye cinsinden).


3. CORS Başlıkları

Başlık Açıklama Örnek
Access-Control-Allow-Origin İzin verilen origin. * (tümü) veya belirli bir origin. https://app.example.com
Access-Control-Allow-Methods İzin verilen HTTP metotları. GET, POST, PUT, DELETE
Access-Control-Allow-Headers İzin verilen istek başlıkları. Content-Type, Authorization
Access-Control-Allow-Credentials Cookie veya HTTP kimlik doğrulama bilgilerinin gönderilip gönderilemeyeceği. true
Access-Control-Expose-Headers İstemcinin JavaScript ile erişebileceği yanıt başlıkları. X-Total-Count, X-Page-Number
Access-Control-Max-Age Preflight yanıtının önbellek süresi (saniye). 86400 (24 saat)

Kritik Kural: Access-Control-Allow-Credentials: true kullanıldığında, Access-Control-Allow-Origin asla * olamaz. Belirli bir origin belirtilmelidir.


4. ASP.NET Core'da CORS Yapılandırması

A. Global CORS Politikası

csharp

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowWebApp", policy =>
    {
        policy.WithOrigins("https://app.example.com", "https://admin.example.com")
              .AllowAnyMethod()
              .AllowAnyHeader()
              .AllowCredentials()
              .WithExposedHeaders("X-Total-Count", "X-Page-Number");
    });

    // Farklı istemciler için farklı politikalar
    options.AddPolicy("AllowMobileApp", policy =>
    {
        policy.WithOrigins("https://mobile.example.com")
              .WithMethods("GET", "POST")
              .WithHeaders("Content-Type", "Authorization");
    });
});

var app = builder.Build();

// Middleware sırası ÖNEMLİ: UseCors, UseRouting'den sonra, UseAuthorization'dan önce
app.UseRouting();
app.UseCors("AllowWebApp");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

B. Endpoint Bazlı CORS

csharp

app.MapGet("/api/public", () => "Herkese açık")
   .RequireCors("AllowWebApp");

app.MapGet("/api/private", () => "Kimlik doğrulamalı")
   .RequireCors("AllowMobileApp")
   .RequireAuthorization();

C. Minimal API'de CORS

csharp

var apiGroup = app.MapGroup("/api")
    .RequireCors("AllowWebApp");

apiGroup.MapGet("/products", () => { ... });

5. CORS En İyi Pratikleri ve Güvenlik Tuzakları

❌ Tehlikeli Yapılandırmalar:

csharp

// ASLA YAPMAYIN!
policy.AllowAnyOrigin()      // Tüm origin'lere izin verir
      .AllowAnyMethod()
      .AllowAnyHeader()
      .AllowCredentials();   // Bu kombinasyon çalışmaz ve güvensizdir!

Neden Tehlikeli? AllowAnyOrigin() + AllowCredentials() kombinasyonu, kötü niyetli bir sitenin kullanıcının kimlik bilgileriyle API'nize istek yapmasına olanak tanır (CSRF).

✅ Güvenli Yapılandırma:

csharp

policy.WithOrigins("https://app.example.com")  // Belirli origin'ler
      .WithMethods("GET", "POST", "PUT", "DELETE")
      .WithHeaders("Content-Type", "Authorization")
      .AllowCredentials();

Dinamik Origin Doğrulama:
Birden fazla alt alan adı (subdomain) varsa, dinamik kontrol yapılabilir:

csharp

policy.SetIsOriginAllowed(origin =>
{
    var host = new Uri(origin).Host;
    return host.EndsWith(".example.com") || host == "example.com";
});

⚠️ Önemli Uyarı: CORS, sunucu taraflı bir güvenlik mekanizması değildir. Sadece tarayıcılar tarafından uygulanır. curl, Postman veya sunucu taraflı istemciler CORS'u görmezden gelir. Bu nedenle, CORS'u bir güvenlik katmanı olarak değil, bir tarayıcı politikası olarak düşünün.


6. Güvenlik Başlıkları (Security Headers)

CORS'un yanı sıra, API'nizin yanıtlarına eklenmesi gereken bir dizi güvenlik başlığı vardır. Bu başlıklar, tarayıcı tabanlı saldırıları (XSS, clickjacking, MIME sniffing) önler.

Başlık Amaç Örnek Değer
Strict-Transport-Security (HSTS) Tarayıcıya, siteye yalnızca HTTPS üzerinden bağlanmasını söyler. max-age=31536000; includeSubDomains; preload
Content-Security-Policy (CSP) Hangi kaynakların (script, style, image) yüklenebileceğini kontrol eder. XSS saldırılarını önler. default-src 'self'; script-src 'self' https://trusted.cdn.com
X-Content-Type-Options Tarayıcının MIME türünü tahmin etmesini (sniffing) engeller. nosniff
X-Frame-Options Sayfanın iframe içinde gösterilmesini engeller (clickjacking koruması). DENY veya SAMEORIGIN
Referrer-Policy Hangi durumlarda referrer bilgisinin gönderileceğini kontrol eder. strict-origin-when-cross-origin
Permissions-Policy Kamera, mikrofon, konum gibi tarayıcı özelliklerini kısıtlar. camera=(), microphone=(), geolocation=()
X-XSS-Protection Eski tarayıcılar için XSS filtresi (artık modern tarayıcılarda CSP tercih edilir). 1; mode=block

7. ASP.NET Core'da Güvenlik Başlıkları Ekleme

A. Middleware ile Manuel Ekleme

csharp

app.Use(async (context, next) =>
{
    context.Response.Headers.Append("X-Content-Type-Options", "nosniff");
    context.Response.Headers.Append("X-Frame-Options", "DENY");
    context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
    context.Response.Headers.Append("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
    context.Response.Headers.Append("Content-Security-Policy", 
        "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
    
    await next();
});

B. HSTS Yapılandırması

csharp

builder.Services.AddHsts(options =>
{
    options.Preload = true;
    options.IncludeSubDomains = true;
    options.MaxAge = TimeSpan.FromDays(365);
});

// Production'da HSTS'yi etkinleştir
if (!app.Environment.IsDevelopment())
{
    app.UseHsts();
}
app.UseHttpsRedirection();

C. Özel Middleware Sınıfı (Daha Temiz Yaklaşım)

csharp

public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        context.Response.Headers.Append("X-Content-Type-Options", "nosniff");
        context.Response.Headers.Append("X-Frame-Options", "DENY");
        context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
        context.Response.Headers.Append("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
        context.Response.Headers.Append("Content-Security-Policy", 
            "default-src 'self'; frame-ancestors 'none'");

        await _next(context);
    }
}

// Program.cs
app.UseMiddleware<SecurityHeadersMiddleware>();

8. Ne Zaman Hangi Başlık Kullanılmalı?

Senaryo Önerilen Başlıklar
Tüm API'ler X-Content-Type-Options: nosniff, Referrer-Policy, Strict-Transport-Security
Tarayıcı tabanlı istemci Content-Security-Policy, X-Frame-Options: DENY
Hassas veri içeren API'ler Cache-Control: no-store, Pragma: no-cache
iframe içinde gösterilecek içerik X-Frame-Options: SAMEORIGIN
Kamera/mikrofon erişimi olan uygulamalar Permissions-Policy ile kısıtlayın

9. En İyi Pratikler

  1. CORS'u Daraltın: Sadece ihtiyaç duyulan origin'lere izin verin; AllowAnyOrigin() kullanmayın.

  2. Credentials ile * Kullanmayın: AllowCredentials() varken origin belirtin.

  3. HTTPS Zorunlu Kılın: UseHttpsRedirection() ve HSTS kullanın.

  4. Tüm Güvenlik Başlıklarını Ekleyin: Middleware ile merkezi olarak yönetin.

  5. CSP'yi Kademeli Uygulayın: Önce Content-Security-Policy-Report-Only ile test edin, sonra zorunlu kılın.

  6. Başlıkları Test Edin: securityheaders.com gibi araçlarla API'nizi test edin.

  7. Dokümantasyon: Hangi başlıkların neden eklendiğini belgeleyin.

  8. CORS'u Güvenlik Sanmayın: Sunucu taraflı yetkilendirme her zaman ayrıca yapılmalıdır.

Sonuç

CORS ve güvenlik başlıkları, modern API güvenliğinin olmazsa olmaz iki bileşenidir. CORS, tarayıcı tabanlı istemcilerin API'nize güvenli bir şekilde erişmesini sağlarken; güvenlik başlıkları, XSS, clickjacking ve MIME sniffing gibi tarayıcı tabanlı saldırılara karşı koruma sağlar. ASP.NET Core'da AddCors() ve özel middleware ile bu yapılandırmaları merkezi ve tutarlı bir şekilde yönetebilirsiniz. Unutmayın: CORS bir güvenlik mekanizması değil, bir tarayıcı politikasıdır; gerçek güvenlik, sunucu taraflı kimlik doğrulama, yetkilendirme ve input validasyonu ile sağlanır.

Tüm yazılar Soru ya da yorumun mu var? Yaz