API Security¶
API güvenliği, uygulamanın dış tehditlere karşı korunmasını sağlar; eksik güvenlik önlemleri veri sızıntısına ve servis kesintisine yol açar.
1. CORS’u Herkese Açmak¶
❌ Yanlış Kullanım: Tüm origin’lere izin vermek.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.AllowAnyOrigin() // Herkes erişebilir
.AllowAnyHeader()
.AllowAnyMethod();
});
});
✅ İdeal Kullanım: Sadece bilinen origin’lere izin verin.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
{
policy.WithOrigins(
"https://myapp.com",
"https://admin.myapp.com")
.AllowCredentials()
.WithHeaders("Authorization", "Content-Type")
.WithMethods("GET", "POST", "PUT", "DELETE");
});
});
2. Rate Limiting Yapmamak¶
❌ Yanlış Kullanım: API endpoint’lerini sınırsız istek almaya açık bırakmak.
app.MapControllers(); // Rate limit yok, brute-force ve DDoS'a açık
✅ İdeal Kullanım: Rate limiting ile endpoint’leri koruyun.
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("general", limiter =>
{
limiter.PermitLimit = 100;
limiter.Window = TimeSpan.FromMinutes(1);
});
options.AddFixedWindowLimiter("auth", limiter =>
{
limiter.PermitLimit = 5;
limiter.Window = TimeSpan.FromMinutes(1);
});
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
});
app.UseRateLimiter();
app.MapPost("/api/auth/login", Login).RequireRateLimiting("auth");
app.MapControllers().RequireRateLimiting("general");
3. Input Validation Yapmamak¶
❌ Yanlış Kullanım: Kullanıcı girdisini doğrulamadan işlemek.
[HttpGet("api/users")]
public async Task<IActionResult> Search([FromQuery] string query)
{
var users = await _context.Users
.FromSqlRaw($"SELECT * FROM Users WHERE Name LIKE '%{query}%'") // SQL Injection!
.ToListAsync();
return Ok(users);
}
✅ İdeal Kullanım: Parametreli sorgular ve input validation kullanın.
[HttpGet("api/users")]
public async Task<IActionResult> Search([FromQuery] string query)
{
if (string.IsNullOrWhiteSpace(query) || query.Length > 100)
return BadRequest("Geçersiz arama terimi.");
var users = await _context.Users
.Where(u => EF.Functions.Like(u.Name, $"%{query}%"))
.Take(50)
.ToListAsync();
return Ok(users);
}
4. Security Headers Eklememek¶
❌ Yanlış Kullanım: Varsayılan HTTP header’ları ile çalışmak.
app.MapControllers();
// X-Content-Type-Options, X-Frame-Options, CSP header'ları eksik
✅ İdeal Kullanım: Güvenlik header’larını middleware ile ekleyin.
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("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");
context.Response.Headers.Append("Content-Security-Policy", "default-src 'self'");
context.Response.Headers.Remove("Server");
context.Response.Headers.Remove("X-Powered-By");
await next();
});
app.UseHsts();
app.UseHttpsRedirection();
5. Sensitive Data Exposure¶
❌ Yanlış Kullanım: Hata detaylarını ve iç yapıyı istemciye açmak.
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
try
{
var user = await _context.Users
.Include(u => u.Password) // Şifre hash'i döner
.Include(u => u.SecurityStamp) // İç güvenlik bilgisi
.FirstOrDefaultAsync(u => u.Id == id);
return Ok(user);
}
catch (Exception ex)
{
return StatusCode(500, new { error = ex.ToString() }); // Stack trace sızar
}
}
✅ İdeal Kullanım: DTO ile sadece gerekli veriyi dönün, hataları maskelleyin.
public record UserDto(int Id, string Name, string Email);
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _service.GetByIdAsync(id);
if (user == null) return NotFound();
return Ok(new UserDto(user.Id, user.Name, user.Email));
}
// Global exception handler hata detaylarını gizler
public class GlobalExceptionMiddleware
{
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "Beklenmeyen hata");
context.Response.StatusCode = 500;
await context.Response.WriteAsJsonAsync(new
{
message = "Bir hata oluştu. Lütfen daha sonra tekrar deneyin."
});
}
}
}