IDOR'u Test Etmeden Publish
Path'teki id, sahibin filtresi değil

Liste endpoint'i 'benim faturalarım' diye OwnerId kesiyordu. Detay {id} ile FirstOrDefaultAsync(x => x.Id == id) yaptı. Login olan herkes 14 numarayı çekti. 403 yok, 404 yok, 200 ve PDF. Bunu publish öncesi ikinci kullanıcıyla denememiştim.
Yetki sorguya iner
app.MapGet("/api/invoices/{id:guid}", async (
Guid id, ClaimsPrincipal user, AppDb db, CancellationToken ct) =>
{
var ownerId = user.FindFirstValue(ClaimTypes.NameIdentifier);
var invoice = await db.Invoices.AsNoTracking()
.Where(i => i.Id == id && i.OwnerId == ownerId)
.Select(i => new InvoiceDto(i.Id, i.Number, i.Total, i.IssuedAt))
.FirstOrDefaultAsync(ct);
return invoice is null ? Results.NotFound() : Results.Ok(invoice);
}).RequireAuthorization();
404, varlık sızdırmamak için 403 yerine. Saldırgan 'var ama senin değil' ile 'yok'u ayıramaz. Admin ayrı policy. Aynı id'yi admin'in görmesi OwnerId filtresini if ile gevşetmek değil, ayrı sorgu.
Test iki kimlik ister
Tek kullanıcıyla e2e yeşil kalır. İkinci kullanıcı A'nın id'sini ister, 404 beklerim. Bu test yoksa IDOR yok sayılır. Integration test'e iki seed kullanıcı koydum. Publish checklist'ine 'başkasının id'si' maddesi eklendi, 'Authorize attribute var' maddesinin yanına değil, yerine değil — altına.
[Fact]
public async Task Invoice_of_other_owner_is_not_found()
{
var alice = await AuthedClient("alice");
var bob = await AuthedClient("bob");
var created = await alice.PostAsJsonAsync("/api/invoices", new { total = 40m });
var id = await created.Content.ReadFromJsonAsync();
var peek = await bob.GetAsync($"/api/invoices/{id}");
Assert.Equal(HttpStatusCode.NotFound, peek.StatusCode);
}
Liste doğru, detay yanlış
Bu kalıp tekrar ediyor: collection filtreli, item filtresiz. Update ve delete aynı item yolunu kullanır. GET'i kapatıp PUT'u açık bırakmak PDF'den kötüdür. Üçünü de aynı Where ile yazıyorum. Servis metodu GetOwnedAsync(id, ownerId); controller id'yi tek başına DB'ye taşımıyor.
IDOR ileri seviye bir konu değil. Path'te guid olması gizlilik değildir. Guid tahmin zor olabilir, sızan guid yetmez. Yetki, tahmin zorluğuna emanet edilmez.
Yorumlar
Yorumlar (0)
Yorumlar üyelere açık. Üye ol · Giriş yap