Bir denetçi denetim izinizi ilk istediğinde, muhtemelen çalıştırdığınız hangi log sistemi varsa oradan bir CSV export edersiniz ve gayet iyi görünür. Zaman damgaları, kullanıcı adları, eylemler, kaynak ID'leri, hepsi sırayla. Sonra biri önemli olan tek soruyu sorar: bu dosyanın gerçekte olanla eşleştiğini nereden biliyoruz? Ekibiniz dışında kimsenin bağımsız olarak kontrol edemediği değiştirilemez bir denetim kaydı kanıt değildir. Kontrol ettiğiniz sistemler tarafından, seçtiğiniz bir formatta üretilmiş, kendi davranışınız hakkında bir iddiadır. Denetçiler bu konuda kibar davranıyor. Regülatörler ise giderek daha az kibar davranıyor.

Çoğu altyapı yığınında "değiştirilemez" (immutable), kelimenin çağrıştırdığından daha zayıf bir şey ifade eder. Genellikle konvansiyon gereği yalnızca-ekleme anlamına gelir - uygulama sadece insert yapar ve herkes bir UPDATE çalıştırmamayı kabul eder. Bazen bir object store üzerinde bir saklama politikası, ya da silmeye karşı koruyan ama başta ne yazıldığı hakkında hiçbir şey söylemeyen bir WORM bucket anlamına gelir. Bunların hepsi gerçek kontrollerdir. Hiçbiri üçüncü bir tarafın sonradan bir değişikliği tespit etmesine izin vermez. Bu boşluk - "kimsenin bunu düzenlememesi gerekiyor" ile "kimsenin düzenlemediğini kanıtlayabilirsiniz" arasındaki boşluk - tüm konu budur.

Kurcalamanın fark edilebildiği bir denetim izi nasıl çalışır

Bir log kaydının önemli olan her alanını alın - eylem, kimin yaptığı, hangi organizasyon adına hareket ettiği, kaynak, değişen değerler, correlation ID, risk seviyesi, client adresi - bunları sabit, üzerinde anlaşılmış bir sırayla serialize edin, bir önceki kaydın hash'ini ekleyin ve sonuç üzerinde SHA-256 çalıştırın. Bu özeti satıra entry_hash olarak kaydedin ve bir öncekinin özetini prev_hash olarak kaydedin. İlk satırın bir öncülü yoktur, bu yüzden prev_hash'i null'dır. Ondan sonraki her şey, kendisinden önce gelene kaynaşmıştır.

Sonuç, işe yarayan kısımdır. Üç ay önceki bir kayıtta tek bir karakteri değiştirin, yeniden hesaplanan hash'i artık satırda saklanan hash'le eşleşmez. Bir satırı tamamen silin, bir sonraki satırın prev_hash'i orada olmayan bir öncüle işaret eder. Uydurma bir kayıt ekleyin, sekansta hiçbir geçerli yeri olmaz. Storage katmanına, operatöre veya vendor'a güvenmenize gerek yoktur. İhtiyacınız olan; kayıtlar, hashleme kuralları ve bir script'tir. Onu düzenli bir log yerine kurcalamanın fark edilebildiği bir denetim izi yapan şey budur.

Bunun size ne vermediği konusunda kesin olalım. Bir hash zinciri, kurcalamanın fark edilebildiği bir yapıdır, kurcalamaya karşı korumalı değildir. Veritabanına yazma erişimi olan ve hashleme kurallarını bilen bir saldırgan, bir kaydı yeniden yazabilir ve ardından ondan sonraki her hash'i yeniden hesaplayabilir, mükemmel şekilde doğrulanan bir zincir üretebilir. Bunu etkisiz kılan şey, zincirin başını saldırganın kontrol etmediği bir yerde yayınlamaktır: güncel entry_hash'i veritabanının dışında tutulan bir anahtarla imzalamak, export etmek, bir denetçiye göndermek, ayrı bir sisteme yazmak. Bunların herhangi biri, o ana kadarki tarihi dondurur.

Tek bir writer'ın düşündüğünüzden neden daha önemli olduğu

Bir hash zincirinin tam olarak bir başı vardır ve her yeni kayıt, ona bağlanabilmeden önce onu okumak zorundadır. Aynı tabloya karşı iki writer çalıştırın, yarışırlar - ikisi de aynı başı okur, ikisi de ona bağlanır ve bunlardan biri artık yanlıştır. Zincir kendini kırık olarak raporlar ve var olmayan bir saldırganı aramakla bir gün geçirirsiniz. Biz bunu bir tercih değil, bir invariant olarak ele alıyoruz: tek bir process denetim kuyruğunu tüketir ve tabloya yazar, ikinci bir writer'ı açmak kasıtlı bir cutover'dır, bir ölçeklendirme düğmesi değil.

Doğrulama hataları da okunaklı olmalı, çünkü operatörler okudukları ilk kelimeye tepki verir. Bizim verifier'ımız üç ayrı sebep raporlar. chain_broken, bağlantının yanlış olduğu, prev_hash'in öncülle eşleşmediği anlamına gelir. content_tampered, bağlantının sağlam olduğu ama saklanan alanlardan hash'i yeniden hesaplamanın farklı bir şey ürettiği anlamına gelir. entry_never_hashed, satırın hiç hash olmadan yazıldığı anlamına gelir. Yalnızca ikincisi kurcalamanın kanıtıdır ve üçünü tek bir mesajda birleştirmek, bir testteki bir bug yüzünden bir güvenlik olayı başlatmanın yoludur.

O üçüncü durum varsayımsal değil ve kendimiz hakkında anlatmaya değer. Kendi zincirimizdeki bir avuç satır, tabloya doğrudan raw SQL ile insert yapan, writer'ı atlayan ve her iki hash kolonunu da boş bırakan bir test tarafından yazılmıştı. Tabloyu yalnızca-ekleme yapan veritabanı tetikleyicileri hem update'i hem de delete'i reddeder, bu da o satırların kalıcı olarak onarılamaz olduğu anlamına gelir. Sonsuza kadar zincirde oturacaklar ve her doğrulama çalışması onlara ulaşacak. Çözüm, testlerin kullanması zorunlu bir helper'dı, artı birisi tekrar raw SQL'e uzandığı anda başarısız olan bir guard test.

Bir denetçinin gerçekte alması gereken şey

Teslim edilecek şey "zincir geçerli" diyen bir dashboard'un ekran görüntüsü değildir. Her iki hash kolonu dahil edilmiş, kayıtların kendisini içeren bir CSV'dir - id, eylem, actor, organizasyon, müşteri kapsamı, kaynak tipi ve ID'si, risk seviyesi, correlation ID, adres, user agent, prev_hash, entry_hash ve zaman damgası - artı tam olarak hangi alanların hangi sırayla özete girdiğine dair yazılı bir spesifikasyon. Bu iki şeyle bir denetçi yirmi satır Python yazar ve başka hiçbir şey sormadan işinizi kontrol eder. Kanıt budur: elden çıkarabileceğiniz ve sonra üzerindeki kontrolü kaybedebileceğiniz bir şey.

Gerçek sonuçları olan küçük bir detay: export edilen denetim alanları saldırgan-etkili string'lerdir ve spreadsheet'ler eşittir, artı, eksi veya at işaretiyle başlayan her şeyi çalıştırır. Denetçinin laptop'ında bir shell açan bir denetim export'u, bir denetimi kaybetmenin akılda kalıcı bir yoludur. Export'umuzdaki her alan escape edilir ve formül önekli değerler dosyaya ulaşmadan önce etkisiz hale getirilir. Bu, ilk kişi kanıt paketini Excel'de açana kadar titizlik gibi görünen türden bir kontroldür.

Bunların hepsinin altında, tablonun kendisi tehlikeli operasyonları reddetmek zorundadır. Uygulama kodunda uygulanan yalnızca-ekleme, kimsenin bir migrasyon, bir cleanup script'i veya sabahın ikisinde iyi niyetli bir düzeltme yazmadığı sürece hayatta kalan bir sözdür. Denetim tablosunda UPDATE ve DELETE'i reddeden veritabanı tetikleyicileri, o sözü bir kısıta dönüştürür. Bu aynı zamanda uygulama ve storage'ın yalnızca bir yönde uyuşmazlığa düşebileceği anlamına gelir: veritabanı, uygulamanın istediği bir yazmayı reddedebilir ama uygulama veritabanını asla sessizce yeniden yazamaz.

Değiştirilemez denetim kaydınızı bir zaman planına göre doğrulayın

Bir verify endpoint'i olan çoğu ekip onu sadece bir kez, demo sırasında çağırır. Bu yanlış bir ritimdir. Denetçi sorduğunda keşfedilen bir zincir kırılması, kaç ay geçmişse onu kapsayan bir adli bilişim problemidir; zamanlanmış bir çalışmayla keşfedilen aynı kırılma ise zaman damgalı bir bug raporudur. Büyük bir tablo üzerinde doğrulama, bunun için inşa edilmelidir. Bizimki, her şeyi belleğe yüklemek yerine kayıtları sıralı sayfalarda dolaşır, çünkü tablo platformdaki her mutasyonla büyür ve sadece küçük tablolarda çalışan bir verifier, çalışmayı bırakacak bir verifier'dır.

Diğer alışkanlık ise kapsamdır. Denetim loglamasını HTTP middleware'ine koymak, her API mutasyonunun izde belirdiğini izlemek ve işi bitmiş ilan etmek kolaydır. Sonra bir cron job bir müşterinin verisini arşivler, bir kuyruk consumer'ı bir ajanı iptal eder, bir arka plan worker'ı bir credential'ı rotate eder ve bunların hiçbiri izde değildir, çünkü hiçbiri bir HTTP request değildi. O yolların açıkça log tutması gerekir. Rahatsız edici gerçek şu ki, loglanma ihtimali en düşük eylemler, tam olarak bir soruşturmacının en çok görmek istediği eylemlerdir.

NIS2 ve DORA aynı yöne itiyor: iddia etmek yerine gösterebileceğiniz kontroller. Kimse size SHA-256 kullandığınız için bir sertifika vermeyecek ve biz de böyle bir iddiada bulunmuyoruz. Ama biri 3 Mart'ta firewall kuralını kimin değiştirdiğini sorduğunda, bir sorgu sonucu ile bütünlüğünü bir yabancının kontrol edebileceği bir sorgu sonucu arasında büyük bir fark vardır. Size değiştirilemez bir denetim kaydı satan herkese sormaya değer üç soru: hash'leri export edebilir miyim, bunları sizin yazılımınız olmadan yeniden hesaplayabilir miyim ve zincir kendini kırık olarak raporladığında ne olur?