Ana içeriğe geç

Authorization

Authorization, kimliği doğrulanmış kullanıcıların hangi kaynaklara erişebileceğini belirler; yanlış yapılandırma yetkisiz erişime ve veri sızıntısına yol açar.


1. Role-Based Authorization’ı Hardcode Etmek

Yanlış Kullanım: Controller’da string role kontrolü yapmak.

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteOrder(int id)
{
    if (!User.IsInRole("Admin") && !User.IsInRole("SuperAdmin"))
        return Forbid();

    await _service.DeleteAsync(id);
    return NoContent();
}

İdeal Kullanım: Policy-based authorization ile merkezileştirin.

builder.Services.AddAuthorizationBuilder()
    .AddPolicy("CanDeleteOrders", policy =>
        policy.RequireRole("Admin", "SuperAdmin"))
    .AddPolicy("CanManageProducts", policy =>
        policy.RequireClaim("permission", "products.manage"));

[HttpDelete("{id}")]
[Authorize(Policy = "CanDeleteOrders")]
public async Task<IActionResult> DeleteOrder(int id)
{
    await _service.DeleteAsync(id);
    return NoContent();
}

2. Resource-Based Authorization Yapmamak

Yanlış Kullanım: Kullanıcının kendi kaynağına erişimini kontrol etmemek.

[Authorize]
[HttpGet("{id}")]
public async Task<IActionResult> GetOrder(int id)
{
    var order = await _service.GetAsync(id);
    return Ok(order); // Herhangi bir kullanıcı başkasının siparişini görebilir
}

İdeal Kullanım: Resource-based authorization ile kaynak sahipliğini doğrulayın.

public class OrderAuthorizationHandler : AuthorizationHandler<OwnerRequirement, Order>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context,
        OwnerRequirement requirement,
        Order resource)
    {
        var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;

        if (resource.CustomerId.ToString() == userId)
            context.Succeed(requirement);

        return Task.CompletedTask;
    }
}

[Authorize]
[HttpGet("{id}")]
public async Task<IActionResult> GetOrder(int id)
{
    var order = await _service.GetAsync(id);
    var result = await _authorizationService.AuthorizeAsync(User, order, new OwnerRequirement());

    if (!result.Succeeded) return Forbid();
    return Ok(order);
}

3. IDOR (Insecure Direct Object Reference)

Yanlış Kullanım: ID parametresini doğrulamadan kaynağa erişim vermek.

[HttpPut("api/users/{id}/profile")]
public async Task<IActionResult> UpdateProfile(int id, UpdateProfileDto dto)
{
    await _service.UpdateProfileAsync(id, dto); // Herkes başkasının profilini güncelleyebilir
    return Ok();
}

İdeal Kullanım: Kullanıcı kimliğini token’dan alarak doğrulayın.

[HttpPut("api/users/profile")]
public async Task<IActionResult> UpdateProfile(UpdateProfileDto dto)
{
    var userId = int.Parse(User.FindFirst(ClaimTypes.NameIdentifier)!.Value);
    await _service.UpdateProfileAsync(userId, dto);
    return Ok();
}

4. Claim Transformation Kullanmamak

Yanlış Kullanım: Her endpoint’te claim’leri manuel okumak.

[HttpGet("api/dashboard")]
public async Task<IActionResult> GetDashboard()
{
    var userId = User.FindFirst("sub")?.Value;
    var permissions = await _permissionService.GetPermissionsAsync(userId);

    if (!permissions.Contains("dashboard.view"))
        return Forbid();

    return Ok(await _dashboardService.GetAsync());
}

İdeal Kullanım: Claims transformation ile claim’leri otomatik zenginleştirin.

public class PermissionClaimsTransformation : IClaimsTransformation
{
    private readonly IPermissionService _permissionService;

    public PermissionClaimsTransformation(IPermissionService permissionService)
        => _permissionService = permissionService;

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var userId = principal.FindFirst("sub")?.Value;
        if (userId == null) return principal;

        var permissions = await _permissionService.GetPermissionsAsync(userId);
        var identity = (ClaimsIdentity)principal.Identity!;

        foreach (var permission in permissions)
        {
            identity.AddClaim(new Claim("permission", permission));
        }

        return principal;
    }
}

// Artık policy ile temiz kullanım
[Authorize(Policy = "CanViewDashboard")]
[HttpGet("api/dashboard")]
public async Task<IActionResult> GetDashboard()
{
    return Ok(await _dashboardService.GetAsync());
}

5. Global Authorization Filter Uygulamamak

Yanlış Kullanım: Her controller’a [Authorize] eklemeyi unutmak.

[ApiController]
public class OrdersController : ControllerBase { /* [Authorize] unutulmuş */ }

[Authorize]
[ApiController]
public class ProductsController : ControllerBase { /* Bu korunuyor */ }

İdeal Kullanım: Global olarak authorize edip, public endpoint’leri explicit açın.

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build());

// Tüm endpoint'ler varsayılan olarak korunur
// Sadece public endpoint'ler explicit olarak açılır
[AllowAnonymous]
[HttpPost("api/auth/login")]
public async Task<IActionResult> Login(LoginDto dto) { /* ... */ }

[AllowAnonymous]
[HttpGet("api/products")]
public async Task<IActionResult> GetProducts() { /* ... */ }