İşletim Sistemleri · Ders Notu

Bölüm 13: Güvenlik

İşletim sistemi bir bilgisayardaki bütün kaynakların bekçisidir. Hangi sürecin hangi dosyayı okuyacağına, hangi kullanıcının sisteme gireceğine, hangi kodun çekirdek kipinde çalışacağına o karar verir. Bu kararlar yanlış verilirse en iyi çizelgeleyici ya da en hızlı dosya sistemi de bir işe yaramaz: veriler sızar, değiştirilir ya da kullanılamaz hâle gelir. Not, önce güvenliğin hedeflerini ve tehditlerini tanımlar. Ardından işletim sisteminin kullandığı kriptografi araçlarını anlatır: şifreleme, özet, imza, sertifika ve TLS. Koruma kısmı erişim matrisini, erişim denetim listelerini, yetenekleri ve en az ayrıcalık ilkesini ele alır. Biçimsel modeller ve gizli kanallar bunu izler. Son kesimler kimlik doğrulamayı, bellek güvenliği açıklarını, kötü amaçlı yazılımları ve bugünkü savunmaları işler: korumalı alan, konteyner, zorunlu erişim denetimi, güvenli önyükleme.

Öğrenme çıktıları

Hedefler ve tehditler
Gizlilik, bütünlük ve erişilebilirlik hedeflerini; saldırı türlerini ve saldırgan profillerini ayırt etmek.
Kriptografi
Simetrik ve asimetrik şifrelemeyi, özet fonksiyonlarını, dijital imzayı, sertifikaları ve TLS el sıkışmasını açıklamak; Diffie-Hellman değişimini adım adım hesaplamak.
Koruma
Erişim matrisini ACL ve yetenek biçiminde okumak; en az ayrıcalığı, setuid'i ve Linux yeteneklerini uygulamak.
Biçimsel modeller
Bell-LaPadula ve Biba kurallarını uygulamak; gizli kanalların neden kapatılamadığını açıklamak.
Kimlik doğrulama
Tuzlu yavaş parola özetlerini, MFA'yı, TOTP'yi ve FIDO2 geçiş anahtarlarını karşılaştırmak.
Saldırılar ve savunmalar
Bellek güvenliği hatalarını, TOCTOU'yu ve kötü amaçlı yazılımları; kanarya, NX, ASLR, CFI, korumalı alan ve güvenli önyüklemeyi tanımak.

13.1Güvenlik hedefleri ve tehditler

Bir sistemi korumaya başlamadan önce neyin, kime karşı ve hangi amaçla korunduğunu söylemek gerekir. Bu kesim güvenliğin üç temel hedefini, bu hedefleri çiğneyen olay türlerini ve saldırganları tanıtır. Sonunda da savunmanın genel mimarisi gelir: katmanlı savunma ve güvenilir bilgi işleme tabanı.

13.1.1Güvenlik ve koruma

İşletim sistemleri kitaplarında iki yakın kavram ayrı ayrı anılır. Koruma (protection), sistemin içindeki mekanizmalardır: hangi sürecin hangi nesneye hangi hakla erişebileceğini belirleyen ve bunu denetleyen kurallar. Dosya izin bitleri, sayfa tablosundaki salt okunur bit, çekirdek ve kullanıcı kipi ayrımı birer koruma mekanizmasıdır. Güvenlik (security) ise daha geniş bir sorudur. Sistem, içerden ve dışarıdan gelen kasıtlı saldırılara ve kazalara karşı ne kadar dayanıklıdır? Koruma mekanizmaları kusursuz çalışsa bile parola çalınırsa, yönetici kandırılırsa ya da yedek alınmamışsa sistem güvenli değildir.

Bu ayrımın pratik bir sonucu vardır. Koruma, işletim sisteminin doğrudan gerçeklediği ve doğruluğu kanıtlanabilen bir alt sistemdir. Güvenlik ise insanları, ağı, donanımı ve yazılımın bütün hatalarını kapsar; hiçbir zaman tam olarak sağlanamaz, yalnız saldırının maliyeti yükseltilebilir. Bu not ikisini birlikte ele alır. Önce hedefler ve tehditler, sonra koruma mekanizmaları gelir. En sonda bu mekanizmaları aşmaya çalışan saldırılar ve onlara karşı geliştirilen savunmalar anlatılır.

13.1.2CIA üçlüsü

Güvenlik hedefleri genellikle üç sözcükle özetlenir. İngilizce baş harflerinden ötürü bu üçlüye CIA üçlüsü denir (Şekil 13.1).

Tanım 13.1

Gizlilik (confidentiality), verinin yalnız yetkili kişilerce okunabilmesidir. Bütünlük (integrity), verinin yalnız yetkili kişilerce ve yetkili yollarla değiştirilebilmesidir. Erişilebilirlik (availability), meşru kullanıcıların veriye ve hizmete ihtiyaç duydukları anda ulaşabilmesidir.

GizlilikconfidentialityBütünlükintegrityErişilebilirlikavailabilityVarlıkveri · hizmet · donanımyetkisiz okuma yokhizmet ayaktayetkisiz değişiklik yokİhlal:ifşa (casusluk, sızıntı)İhlal:hizmet reddi (DoS)İhlal: tahrifat, sahte kayıt, fidye ile şifreleme
Şekil 13.1: CIA üçlüsü. Korunan varlık veri, hizmet ya da donanım olabilir; her hedefin ihlali ayrı bir zarar türüdür.

Her hedefin karşısında bir ihlal türü durur. Gizliliğin ihlali ifşadır: bir şirketin müşteri veritabanının sızdırılması, bir casus yazılımın e-postaları kopyalaması. Bütünlüğün ihlali tahrifattır: bir öğrencinin not kaydını değiştirmesi, bir saldırganın sistem programının yerine kendi sürümünü koyması. Erişilebilirliğin ihlali hizmet reddidir: bir web sunucusunun sahte isteklerle boğulması ya da bir fidye yazılımının diski şifreleyip kullanılamaz hâle getirmesi.

Üç hedef birbirinden bağımsız değildir ve kimi zaman çatışır. Verinin üç ayrı ülkede kopyasını tutmak erişilebilirliği artırır, ama sızıntı riski olan yerlerin sayısını da üçe çıkarır. Bir disk şifrelendiğinde gizlilik artar; anahtar kaybolursa veri sonsuza dek erişilemez olur. Güvenlik tasarımı bu yüzden hedefleri dengeleme işidir.

Üçlüye sık eklenen iki hedef daha vardır. Özgünlük (authenticity), bir iletinin ya da kullanıcının gerçekten iddia ettiği kaynaktan geldiğinin doğrulanabilmesidir. Hesap verebilirlik (accountability) ise bir işlemin kimin yaptığının sonradan kanıtlanabilmesidir. Hesap verebilirliğin iki aracı vardır: denetim kayıtları ve inkâr edilemezlik. İnkâr edilemezlikte (non-repudiation) bir kişi imzaladığı bir belgeyi sonradan “ben imzalamadım” diyerek reddedemez. Dijital imzanın asıl kazancı budur.

Örnek 13.1

Bir hastanenin dosya sunucusundaki kayıtlarla ilgili dört olayı ele alalım. Her biri hangi hedefi çiğner?

  1. Bir çalışan, merak ettiği bir ünlünün tahlil sonuçlarını açıp okuyor. Veri değişmedi, hizmet aksamadı; ama yetkisiz biri okudu. Gizlilik ihlalidir.
  2. Bir saldırgan bir hastanın kan grubunu değiştiriyor. Kimse fark etmeden okunan veri artık yanlıştır. Bütünlük ihlalidir ve gizlilik ihlalinden de tehlikeli olabilir.
  3. Fidye yazılımı bütün dosyaları şifreliyor; doktorlar saatlerce kayıtlara ulaşamıyor. Veri dışarı çıkmadı ve içeriği bozulmadı; ama kullanılamıyor. Erişilebilirlik ihlalidir.
  4. Bir doktor, yazdığı reçeteyi sonradan yazmadığını iddia ediyor ve kayıtlarda bunu çürütecek bir iz yok. Hesap verebilirlik eksiktir. Reçeteler doktorun özel anahtarıyla imzalansaydı inkâr mümkün olmazdı.

13.1.3Tehdit, zafiyet, saldırı ve istismar

Güvenlik dilinde dört sözcük birbirine karıştırılır, ama her biri zincirin ayrı bir halkasıdır (Şekil 13.2).

Tanım 13.2

Tehdit (threat) olası bir zarardır. Zafiyet (vulnerability) bu zararı mümkün kılan zayıflıktır. Saldırı (attack) zafiyeti kullanma girişimidir. İstismar (exploit) ise bu girişimi yapan kod ya da yöntemdir.

Tehditolası zararZafiyetzayıflıkSaldırıkullanma girişimiİstismarkod / yöntemİhlalCIA kaybıyama zafiyeti, kimlik doğrulama saldırıyı, kanarya/NX istismarı, yedek ihlalin sonucunu sınırlar
Şekil 13.2: Tehditten ihlale giden zincir. Her halkanın kendi savunması vardır: yama zafiyeti, kimlik doğrulama saldırıyı, kanarya ve NX istismarı, yedek de ihlalin sonucunu sınırlar.

Bir örnekle zincir somutlaşır. “Müşteri verilerinin çalınması” bir tehdittir. Web uygulamasındaki denetlenmemiş bir girdi alanı zafiyettir. Saldırganın bu alana özel hazırlanmış bir sorgu yazması saldırıdır. Bu sorgunun kendisi, yani zafiyeti tetikleyen dizgi ya da program, istismardır. Sonunda veritabanı dışarı aktarılırsa gizlilik ihlal edilmiş olur.

Zincir görüşünün değeri, savunmanın da her halkaya yerleştirilebilmesidir. Yama zafiyeti ortadan kaldırır. Güçlü kimlik doğrulama saldırganın sisteme girmesini zorlaştırır. Yığın kanaryası ve yürütülemez sayfalar gibi önlemler istismarın çalışmasını engeller. Yedekler ise her şey başarısız olsa bile ihlalin sonucunu sınırlar. Bir halkadaki savunma kırılsa bile sonraki halkalar devrede kalır.

İhlaller sunumdaki gibi yedi kategoride toplanabilir (Tablo 13.1). İlk üçü CIA hedeflerinin doğrudan karşılığıdır. Sonraki dördü bu hedefleri dolaylı yoldan bozar.

Tablo 13.1: İhlal kategorileri.
KategoriTanımÖrnek
Gizlilik ihlaliVerinin izinsiz okunmasıKredi kartı veritabanının sızdırılması
Bütünlük ihlaliVerinin izinsiz değiştirilmesiNot sisteminde kayıt tahrifatı
Erişilebilirlik ihlaliVerinin ya da hizmetin yok edilmesiFidye yazılımının diski şifrelemesi
Hizmet hırsızlığıKaynakların izinsiz kullanımıEle geçirilen sunucuda kripto para kazma
Hizmet reddi (DoS/DDoS)Meşru kullanımın engellenmesiBotnet ile SYN seli
Kimlik değiştirmeBaşkası gibi davranmaOltalama ile çalınan parola
Ayrıcalık yükseltmeHak edilenden fazla yetki kazanmasetuid programdaki hatadan root olma

Hizmet reddi (denial of service, DoS) saldırısında amaç veriyi okumak ya da değiştirmek değildir. Saldırgan sistemi meşru isteklere yanıt veremeyecek kadar meşgul eder. Bir TCP sunucusu her bağlantı isteği için yarı açık bir bağlantı kaydı tutar. Saldırgan saniyede binlerce sahte istek (SYN) gönderir ve el sıkışmayı hiç tamamlamaz. Bu tablo dolar ve gerçek kullanıcılar bağlanamaz. Saldırı binlerce ele geçirilmiş makineden aynı anda yapılırsa adı dağıtık hizmet reddi (DDoS) olur. Bu durumda tek bir kaynak adresi engellemek de işe yaramaz.

Kimlik değiştirme (masquerading) saldırısında saldırgan başka bir kullanıcının ya da makinenin kimliğine bürünür. Ayrıcalık yükseltme (privilege escalation) ise sıradan bir kullanıcının ya da sürecin, bir hatadan yararlanarak yönetici haklarına ulaşmasıdır. İşletim sistemi açısından en tehlikeli kategori budur, çünkü yönetici haklarıyla bütün öteki korumalar devre dışı bırakılabilir.

13.1.4Ağ saldırıları

Bugün hemen her bilgisayar ağa bağlıdır ve işletim sisteminin dışarıyla konuştuğu kanal da saldırı yüzeyinin parçasıdır. Güvenlik kitaplarında bu saldırılar geleneksel olarak üç kişiyle anlatılır. Alice ve Bob konuşmak isteyen iki taraftır. Eve (eavesdropper) yalnız dinleyen pasif saldırgandır. Mallory ise iletileri değiştirebilen etkin saldırgandır. Kanal şifresiz ve kimlik doğrulamasızsa dört saldırı da mümkündür.

Dinleme (eavesdropping)
Pasif saldırgan trafiğin bir kopyasını alır ve okur. İletilere dokunmadığı için fark edilmesi çok zordur. Gizliliği bozar. Çaresi şifrelemedir: bugün bunu çoğunlukla TLS yapar.
Tekrar saldırısı (replay)
Saldırgan geçerli bir iletiyi yakalar ve sonradan aynen yeniden gönderir. İleti şifreli ve imzalı olabilir: saldırganın onu okuması ya da değiştirmesi gerekmez. “1000 TL öde” iletisi iki kez işlenirse zarar iki katına çıkar. Çaresi her iletiye bir kez kullanılabilen bir değer eklemektir: tek kullanımlık sayı (nonce), zaman damgası ya da sıra numarası.
Ortadaki adam (man-in-the-middle, MITM)
Saldırgan iki tarafın arasına girer ve her birine öteki gibi görünür. Alice, Bob'la konuştuğunu sanır; aslında Mallory ile konuşur. Mallory iletileri okur, değiştirir ve iletir. Şifreleme tek başına çare değildir: Alice'in şifreli kanal kurduğu taraf Mallory'nin kendisi olabilir. Çaresi karşı tarafın kimliğini doğrulamaktır, yani sertifikalardır.
Oturum kaçırma (session hijacking)
Kullanıcı bir kez kimlik doğruladıktan sonra sunucu ona bir oturum belirteci verir; çoğunlukla bir çerez. Saldırgan bu belirteci çalarsa parolayı bilmeden oturuma girer. Çaresi belirteci yalnız şifreli kanaldan göndermek (Secure), betiklerin okumasını engellemek (HttpOnly) ve ömrünü kısa tutmaktır.
AliceistemciBobsunucuEve / MallorysaldırganAlice “Bob”la konuştuğunusanırBob “Alice” ilekonuştuğunu sanırortadaki adam: okur ve değiştirir
Şekil 13.3: Ortadaki adam: Mallory iki tarafa da karşı taraf gibi görünür; iletileri okur ve değiştirir.
AliceistemciBobsunucuEve / MallorysaldırganCookie: oturum=7f3a…çalınan çerezleoturuma girer
Şekil 13.4: Oturum kaçırma: kimlik doğrulamadan sonra verilen çerez çalınırsa saldırgan parolasız oturuma girer.
Sık yapılan hata

Şifrelemenin tekrar saldırısını önlediğini düşünmek. Saldırgan şifreli iletiyi çözmeden de yeniden gönderebilir. Alıcı aynı iletiyi daha önce gördüğünü anlamıyorsa ikinci kopyayı da geçerli sayar. Tekrarı yalnız iletiye eklenen tek kullanımlık bir değer ve alıcının bu değerleri izlemesi önler.

13.1.5Saldırganlar ve kazayla veri kaybı

Savunmanın gücü, karşısındaki saldırganın kim olduğuna göre ayarlanır. Bir öğrenci laboratuvarındaki makineyi meraklı bir arkadaşa karşı korumakla bir bankanın sunucusunu devlet destekli bir gruba karşı korumak aynı iş değildir. Saldırganlar kabaca dört gruba ayrılır.

Meraklı içeriden kişi
Teknik bilgisi azdır; başkasının e-postasına ya da dosyasına “bakmak” ister. Çoğu zaman bir izin hatasından yararlanır. Davranışı etik dışıdır ve çoğu zaman yasaya da aykırıdır. Doğru dosya izinleri bu gruba karşı çoğunlukla yeterlidir.
Kötü niyetli çalışan
Sistemde meşru bir hesabı ve yetkisi vardır; bu yetkiyi kötüye kullanır. Veri sızdırabilir, sabotaj yapabilir ya da işten çıkarılırsa tetiklenecek bir mantık bombası bırakabilir. Dışarıdan saldırganlara karşı kurulan duvarların içindedir; bu yüzden fark edilmesi en zor gruptur.
Siber suçlu
Amacı kârdır: fidye yazılımı, kimlik ve kart bilgisi hırsızlığı, ele geçirdiği makinelerden oluşan ağı (botnet) kiralamak. Bugün en yaygın tehdit budur. Bu grup çoğunlukla bilinen ve yaması çıkmış açıkları kullanır; yama yapılmamış sistemleri otomatik araçlarla tarar.
Devlet destekli gruplar
Literatürde “gelişmiş kalıcı tehdit” (advanced persistent threat, APT) olarak anılırlar. Amaçları askerî ya da ticari casusluk ve kritik altyapı sabotajıdır. Yıllarca sessizce içeride kalabilirler. Henüz kimsenin bilmediği açıkları (zero-day, sıfırıncı gün açıkları) ve tedarik zinciri saldırılarını kullanırlar. 2010'da ortaya çıkan Stuxnet, uranyum zenginleştirme santrifüjlerini hedef alan böyle bir yazılımdı.

Veri kaybının tek nedeni saldırganlar değildir. Kazalar, saldırılardan çok daha sık veri kaybettirir (Tablo 13.2). Bir disk arızalanır, bir yönetici yanlış diski biçimlendirir, bir dizüstü bilgisayar trende unutulur. Tanenbaum'un alaycı örneğiyle, yedek bantlarını kemiren fareler bile bu listeye girer.

Tablo 13.2: Kazayla veri kaybının nedenleri ve önlemleri.
NedenÖrnekÖnlem
Doğal olaylaryangın, sel, depremcoğrafi olarak ayrı yedek
Donanım ve yazılım hatasıdisk arızası, CPU hatası, yazılım hatasıRAID, sağlama toplamı, sürüm tutma
İnsan hatasıyanlış komut, yanlış diski biçimleme, kayıp aygıt3-2-1 yedekleme, şifreli disk

Yaygın yedekleme kuralı 3-2-1 diye anılır: verinin üç kopyası, iki farklı ortamda tutulur ve bir kopya başka bir yerde durur. Bugün buna bir koşul eklenir: uzaktaki kopyanın değiştirilemez (immutable) olması. Fidye yazılımları ağdan erişebildikleri yedekleri de şifreler ya da siler. Değiştirilemez bir kopya bu saldırıdan sağ çıkar. Böylece aynı kural hem kazaya hem saldırıya karşı işe yarar.

13.1.6Derinlemesine savunma

Hiçbir savunma kusursuz değildir. Güvenlik duvarının bir kuralı yanlış yazılır, bir çalışan oltalama e-postasına tıklar, bir kütüphanede yeni bir açık bulunur. Bu yüzden tek bir savunmaya güvenilmez; savunmalar iç içe katmanlar hâlinde dizilir. Bu ilkeye derinlemesine savunma (defense in depth) denir. Ortaçağ kalelerinin hendek, sur, iç sur ve kale burcundan oluşan düzenine benzer: saldırgan bir katmanı aşsa bile bir sonrakine takılır (Şekil 13.5).

Politika, eğitim, fiziksel güvenlikAğ: güvenlik duvarı, segmentasyonUç nokta: yama, EDR, disk şifrelemeİşletim sistemi: erişim denetimi, korumalı alanUygulama: girdi denetimi, bellek güvenli dilVeriGüvenlik duvarıİnternetPC 1PC 2PC 3yalnız izinli bağlantılar geçer
Şekil 13.5: Derinlemesine savunmanın katmanları (solda) ve bir ağın önündeki güvenlik duvarı (sağda).

Katmanlar dıştan içe şöyle sıralanır. En dışta politikalar, kullanıcı eğitimi ve fiziksel güvenlik vardır: sunucu odasının kilidi bu katmandadır. Ağ katmanında güvenlik duvarı (firewall) yalnız izinli bağlantıları geçirir; ağ bölütlemesi de bir bölümün ele geçirilmesinin ötekilere yayılmasını önler. Uç nokta katmanında yamalar, uç nokta tespit ve yanıt araçları (EDR) ve disk şifreleme bulunur. İşletim sistemi katmanı erişim denetimini ve korumalı alanı sağlar. Uygulama katmanında girdi denetimi ve bellek güvenli diller yer alır. En içte de korunan varlık, yani veri durur.

İyi uygulamalar da bu katmanlara dağılır. Güvenlik güncellemeleri hızla uygulanır, çünkü saldırıların çoğu yaması çoktan çıkmış açıkları kullanır. Güçlü kimlik doğrulama ve en az ayrıcalıkla çalışan erişim denetimi temel kuraldır. Günlük kayıtları tutulur ve izlenir; aksi hâlde bir ihlal aylarca fark edilmeyebilir. Düzenli sızma testleriyle savunmanın zayıf noktaları önceden aranır. Kullanıcılar oltalamaya karşı eğitilir.

Son yıllarda yaygınlaşan sıfır güven (zero trust) yaklaşımı derinlemesine savunmanın bir adım ötesidir. Geleneksel düzende güvenlik duvarının içi güvenilir sayılırdı: içerideki bir makine öteki makinelere serbestçe erişebilirdi. Sıfır güven bu varsayımı reddeder. Ağın içinden gelen istek de dışarıdan gelen gibi kimlik doğrulamasından ve yetki denetiminden geçer. Böylece içeri sızan bir saldırganın yanal hareketi zorlaşır.

13.1.7Güvenilir bilgi işleme tabanı

Her güvenlik iddiası bazı bileşenlerin doğru çalıştığı varsayımına dayanır. Dosya izinleri ancak onları denetleyen çekirdek kodu hatasızsa bir anlam taşır. Bu bileşenlerin toplamına güvenilir bilgi işleme tabanı denir (Şekil 13.6).

Tanım 13.3

Güvenilir bilgi işleme tabanı (trusted computing base, TCB), sistemin güvenlik politikasını uygulamaktan sorumlu bütün donanım, bellenim ve yazılım bileşenlerinin kümesidir. TCB'deki bir hata bütün sistemin güvenliğini bozabilir; TCB dışındaki bir hata ise politikayı çiğneyemez.

Kullanıcı alanıSüreç ASüreç BSüreç CSaldırganGüvenilir bilgi işleme tabanı (TCB)Referans izleyiciher erişimi denetlerÇekirdek, sürücülerKimlik doğrulamaDonanım (MMU, TPM)reddedildi
Şekil 13.6: Kullanıcı süreçlerinin bütün erişimleri TCB'nin içindeki referans izleyiciden geçer. Saldırganın isteği de oradan geçer ve reddedilir.

TCB'nin kalbi referans izleyicidir (reference monitor). Bu bileşen her erişim isteğini alır, politikaya bakar ve izin ya da ret kararı verir. Bir referans izleyicinin güvenilir olması için üç koşul sağlanmalıdır. Birincisi, her erişimde çağrılmalıdır; atlanabilen bir denetim, hiç denetim olmaması kadar kötüdür. İkincisi, kurcalanamaz olmalıdır; kullanıcı süreçleri onun kodunu ya da verisini değiştirememelidir. Üçüncüsü, doğruluğu denetlenebilecek kadar küçük olmalıdır.

Bu üçüncü koşul işletim sistemi tasarımında önemli bir sonuç doğurur. TCB ne kadar büyükse içinde hata bulunma olasılığı o kadar yüksektir. Linux çekirdeği on milyonlarca satırdır ve aygıt sürücüleri de dahil olmak üzere hepsi çekirdek kipinde, yani TCB'nin içinde çalışır. Mikro çekirdekler bu yüzden ilgi görür: dosya sistemini ve sürücüleri kullanıcı kipine taşıyarak TCB'yi küçültürler. seL4 mikro çekirdeği daha da ileri gider. Yaklaşık on bin satırlık kodunun, belirtimine uygun çalıştığı biçimsel olarak kanıtlanmıştır.

Sık yapılan hata

TCB'yi “güvenilir olduğu kanıtlanmış bileşenler” diye anlamak. Tanım tersini söyler: TCB, güvenilmek zorunda olunan bileşenlerdir. Bir yazıcı sürücüsü çekirdek kipinde çalışıyorsa, ne kadar özensiz yazılmış olursa olsun TCB'nin parçasıdır. Güvenli tasarımın amacı bu kümeyi olabildiğince küçük tutmaktır.

13.2Kriptografi

İşletim sistemi kriptografiyi her yerde kullanır: parolaları saklarken, diski şifrelerken, güncelleme paketlerinin imzasını doğrularken, ağ bağlantılarını korurken, önyükleme zincirini denetlerken. Bu kesim, bu kullanımları anlamaya yetecek temel araçları tanıtır. Amaç şifre tasarlamak değildir. Her aracın neyi sağladığını ve neyi sağlamadığını bilmek yeterlidir.

13.2.1Şifrelemenin temelleri

Şifrelemenin amacı, okunabilir bir iletiyi anahtarı bilmeyen birinin anlayamayacağı bir biçime dönüştürmektir. Okunabilir ileti düz metin (plaintext, P), dönüşmüş biçimi şifreli metin (ciphertext, C) diye anılır. Dönüşümü yapan fonksiyon şifreleme E, geri dönüşümü yapan fonksiyon çözme D'dir. İkisi de bir anahtar K kullanır (Şekil 13.7).

Tanım 13.4

Şifreleme (encryption), veriyi anahtar olmadan okunamaz hâle getirmektir. Simetrik ya da gizli anahtarlı şifrelemede şifreleme ve çözme aynı anahtarı kullanır:

C = E(P, K),   P = D(C, K)

Düz metin PŞifrele EŞifreli metin CÇöz DPanahtar Kanahtar K (aynı)saldırgan C’yi görürC = E(P, K) · P = D(C, K)
Şekil 13.7: Simetrik şifreleme modeli. Saldırgan şifreli metni görebilir; aynı K'yı bilmeden düz metni elde edemez.

Modelde saldırganın kanalı dinleyebildiği ve C'yi görebildiği varsayılır. Peki saldırgan şifreleme algoritmasını da biliyor mu? 1883'te Auguste Kerckhoffs'un ortaya koyduğu ilkeye göre bilmesi varsayılmalıdır. Kerckhoffs ilkesi, bir şifreleme sisteminin güvenliğinin yalnız anahtarın gizliliğine dayanması gerektiğini söyler. Algoritma açık olabilir, hatta açık olmalıdır. Gizli tutulan bir algoritma er geç tersine mühendislikle ortaya çıkar. Açık bir algoritma ise yıllarca dünyanın her yerinden kriptografların saldırısına uğrar; ayakta kalırsa güvenilir sayılır. Bugünkü bütün standart şifreler bu yüzden herkese açıktır.

Kerckhoffs ilkesinin bir sonucu, anahtar uzayının büyüklüğünün önemidir. Algoritmayı bilen bir saldırgan her anahtarı tek tek deneyebilir. Bu yönteme kaba kuvvet (brute force) saldırısı denir. Eski DES standardı 56 bitlik anahtar kullanırdı. Bu 256 anahtar 1998'de özel bir donanımla birkaç günde taranabildi. 128 bitlik bir anahtar uzayı ise bütün dünyanın hesaplama gücüyle bile taranamaz. Ancak büyük bir anahtar uzayı tek başına yeterli değildir; bir sonraki örnek bunu gösterir.

13.2.2Yerine koyma şifresi ve sıklık analizi

En eski şifrelerden biri tek alfabeli yerine koyma şifresidir (monoalphabetic substitution). Alfabenin her harfi sabit bir başka harfle değiştirilir. Anahtar, 26 harfin bir permütasyonudur. Sunumdaki anahtar, klavyenin üst sırasından başlayarak harfleri dizer: A → Q, B → W, C → E ve böyle sürer (Tablo 13.3).

Tablo 13.3: Yerine koyma şifresinin anahtarı.
açıkABCDEFGHIJKLM
şifreliQWERTYUIOPASD
açıkNOPQRSTUVWXYZ
şifreliFGHJKLZXCVBNM
Örnek 13.2

MERHABA sözcüğünü bu anahtarla şifreleyelim.

  1. M'nin altındaki harf D'dir: M → D.
  2. E → T, R → K, H → I.
  3. A → Q, B → W, A → Q.

Sonuç: MERHABA → DTKIQWQ. Çözmek için tablo ters yönde okunur: şifreli metindeki D'nin üstünde M vardır. Sözcükteki üç A'nın üçü de Q olmuştur.

AQBWCEDRETFYGUHIIOJPKALSMDNFOGPHQJRKSLTZUXVCWVXBYNZMDüz metinŞifreli metinMDETRKHIAQBWAQ
Şekil 13.8: MERHABA'nın şifrelenmesi. Aynı düz harf hep aynı şifreli harfe gider.

Bu şifrenin anahtar uzayı çok büyüktür: 26 harfin permütasyon sayısı 26! ≈ 4 × 1026'dır, yani yaklaşık 288. Saniyede bir milyar anahtar deneyen bir bilgisayar bu uzayı milyarlarca yılda tarayabilir. Buna karşın şifre birkaç satırlık bir metinle, kalem kâğıtla kırılır. Neden?

Örnekteki üç A'nın üçünün de Q olması zayıflığı açığa vurur. Şifre harfleri değiştirir, ama harf sıklıklarını değiştirmez. Türkçe bir metinde en sık harfler A, E ve İ'dir. Şifreli metinde en sık geçen harf büyük olasılıkla A'nın karşılığıdır. Ardından sık geçen iki harfli ve üç harfli kalıplar (“ve”, “bir”, “ler”) eşlenir. Birkaç tahminden sonra anahtar adım adım ortaya çıkar. Bu yönteme sıklık analizi denir. Yöntemi ilk kez dokuzuncu yüzyılda Arap matematikçi el-Kindî anlatmıştır.

Sık yapılan hata

Büyük anahtar uzayını güvenlikle eşitlemek. Anahtar uzayı yalnız kaba kuvvete karşı bir alt sınırdır. Şifrenin yapısı düz metnin istatistiğini sızdırıyorsa saldırgan anahtarları tek tek denemez, doğrudan yapıyı kullanır. Yerine koyma şifresinde 288'lik uzay bu yüzden hiçbir işe yaramaz.

13.2.3Bugünkü simetrik şifreler

Bugünkü simetrik şifreler sıklık bilgisini gizlemek için iki yapıdan birini kullanır. Blok şifreleri veriyi sabit boylu bloklara böler ve her bloğu birçok tur boyunca karıştırır. Standart blok şifresi AES'tir (Advanced Encryption Standard, 2001). 128 bitlik bloklar ve 128, 192 ya da 256 bitlik anahtarlar kullanır. Bugünkü işlemcilerde AES için özel komutlar (AES-NI) bulunur ve şifreleme saniyede gigabaytlar hızına ulaşır. Akış şifreleri ise anahtardan uzun bir rastgele görünümlü bayt dizisi üretir ve veriyle XOR'lar. ChaCha20 bu türün yaygın bir örneğidir; AES donanımı bulunmayan telefonlarda hızlıdır.

Bir şifrenin yalnız gizliliği sağlaması yetmez. Saldırgan şifreli metnin bitlerini değiştirirse alıcı bozuk bir düz metin elde eder ve bunu fark etmeyebilir. Bu yüzden bugün şifreleme her zaman bir bütünlük denetimiyle birlikte kullanılır. Bu birleşik yapıya kimlik doğrulamalı şifreleme (authenticated encryption) denir. AES-256-GCM ve ChaCha20-Poly1305 bu türün iki standart örneğidir: şifreli metnin yanına kısa bir doğrulama etiketi eklerler. Tek bir bit değişse etiket tutmaz ve alıcı iletiyi reddeder.

13.2.4Açık anahtarlı şifreleme

Simetrik şifrelemenin bir temel sorunu vardır: iki tarafın önceden aynı anahtarı paylaşmış olması gerekir. İnternette ilk kez bağlandığımız bir siteyle bu anahtarı nasıl paylaşırız? Anahtarı ağdan göndermek, dinleyen herkese vermek demektir. 1976'da Diffie ve Hellman bu soruya yeni bir cevap verdi: iki ayrı anahtar.

Tanım 13.5

Açık anahtarlı (public-key) ya da asimetrik şifrelemede her kullanıcının bir anahtar çifti vardır. Açık anahtar herkese dağıtılır; özel anahtarı yalnız kullanıcının kendisi bilir. Açık anahtarla şifrelenen bir ileti yalnız eşi olan özel anahtarla çözülebilir.

AlicegöndericiBobalıcıaçıkPub_BözelPriv_Baçık anahtar herkese dağıtılabilirE(P, Pub_B)D(C, Priv_B)CPub_B ile şifrelenen yalnız Priv_B ile çözülür.
Şekil 13.9: Alice, Bob'un açık anahtarı Pub_B ile şifreler; iletiyi yalnız Priv_B'yi bilen Bob çözebilir.

Alice, Bob'a gizli bir ileti göndermek istediğinde Bob'un açık anahtarını alır ve iletiyi onunla şifreler (Şekil 13.9). Şifreli metni dinleyen Eve de Bob'un açık anahtarını bilir, ama bu anahtarla iletiyi çözemez. Çözme yalnız özel anahtarla mümkündür ve o anahtar Bob'un makinesinden hiç çıkmaz. Böylece önceden paylaşılmış bir sır gerekmez.

Bu düzenin matematik temeli tek yönlü tuzak kapılı fonksiyonlardır. Böyle bir fonksiyonu bir yönde hesaplamak kolaydır, ters yönde hesaplamak çok zordur. Ancak gizli bir bilgi (tuzak kapı) bilinirse ters yön de kolaylaşır. RSA'da (1977) bu fonksiyon büyük asal sayıların çarpımıdır: iki 1024 bitlik asalı çarpmak bir anlıktır, ama çarpımı çarpanlarına ayırmanın bilinen hızlı bir yolu yoktur. Eliptik eğri kriptografisinde (ECC) zorluk, eğri üzerindeki ayrık logaritma problemidir.

Örnek 13.3

RSA'nın işleyişini oyuncak boyutlu sayılarla izleyelim. Gerçek sistemlerde sayılar yüzlerce basamaklıdır; adımlar aynıdır.

  1. Anahtar üretimi. Bob iki asal seçer: p = 3, q = 11. Çarpım n = 33'tür. φ = (p − 1)(q − 1) = 2 × 10 = 20. Açık üs e = 3 seçilir (20 ile ortak böleni yoktur). Özel üs d, e · d ≡ 1 (mod 20) koşulunu sağlayan sayıdır: 3 × 7 = 21 ≡ 1, yani d = 7. Açık anahtar (n, e) = (33, 3), özel anahtar d = 7'dir.
  2. Şifreleme. Alice m = 4 iletisini gönderir: c = me mod n = 43 mod 33 = 64 mod 33 = 31.
  3. Çözme. Bob cd mod n hesaplar: 317 mod 33 = 4. Özgün ileti geri gelir.

Eve n = 33'ü ve e = 3'ü bilir. d'yi bulmak için φ'yi, yani p ve q'yu bilmesi gerekir. 33'ü çarpanlarına ayırmak kolaydır. 2048 bitlik bir n'yi ayırmak ise bugünkü bilgisayarların yapabileceği bir iş değildir. Değerler Python ile doğrulandı.

Asimetrik şifrelemenin bedeli hızdır: simetrik şifrelemeden yüz ile bin kat yavaştır (Tablo 13.4). Bu yüzden gerçek sistemler ikisini birlikte kullanır. Asimetrik yöntem yalnız kısa bir işi yapar: iki taraf arasında bir oturum anahtarı kurar. Asıl veri bu oturum anahtarıyla simetrik olarak şifrelenir. TLS, SSH ve disk şifreleme bu karma düzeni kullanır.

Tablo 13.4: Simetrik ve asimetrik şifrelemenin karşılaştırılması.
SimetrikAsimetrik (açık anahtarlı)
AnahtarTek, paylaşılanAçık + özel çift
HızÇok hızlı (AES-NI)100–1000 kat yavaş
KullanımToplu veriAnahtar değişimi, imza
ÖrnekAES, ChaCha20RSA, ECDH/X25519, Ed25519, ML-KEM

Tablodaki son algoritma yeni bir tehdide yanıttır. Yeterince büyük bir kuantum bilgisayarı, Shor algoritmasıyla hem çarpanlara ayırmayı hem ayrık logaritmayı hızla çözebilir. Böyle bir makine bugün yoktur. Ancak bugün kaydedilen trafik yıllar sonra çözülebilir; bu yüzden geçiş şimdiden başlamıştır. ABD standart kurumu NIST, 2024'te kafes tabanlı ML-KEM algoritmasını kuantuma dayanıklı anahtar kurma standardı olarak yayımladı (FIPS 203).

13.2.5Özet fonksiyonları

Kriptografinin üçüncü temel aracı şifreleme değildir; hiçbir anahtar kullanmaz ve geri çevrilemez.

Tanım 13.6

Kriptografik özet fonksiyonu (cryptographic hash function), her boydaki girdiden sabit boylu bir çıktı, yani özet üretir ve şu özellikleri taşır:

  • Tek yönlülük: bir özetten onu veren girdiyi bulmak pratikte imkânsızdır.
  • Çakışma direnci: aynı özeti veren iki farklı girdi bulmak pratikte imkânsızdır.
  • Çığ etkisi: girdideki tek bir bitlik değişiklik, özetin bitlerinin yaklaşık yarısını değiştirir.

Bugünkü standartlar SHA-256 ve SHA-3'tür. SHA-256 her girdiden 256 bitlik, yani 64 onaltılık haneli bir özet üretir. Çığ etkisini görmek için iki sözcüğün özetini karşılaştıralım.

Örnek 13.4

“MERHABA” ile “MERHABa” yalnız son harfte ayrılır. ASCII'de A (0x41) ile a (0x61) tek bir bitte farklıdır. SHA-256 özetleri şöyledir:

MERHABA  cc44cc878588056ef8376b36fc7a2ba5124656c38597eb31291704e0af986112
MERHABa  57821b9db50b174af36bc659771a47e0eaa6aef8144b1a9e5b803c93e3280b18

İki özet arasında hiçbir benzerlik yoktur. Bit bit karşılaştırıldığında 256 bitin 124'ü farklıdır; bu, beklenen yarıya (128) çok yakındır. Özetler Python'un hashlib kütüphanesiyle hesaplandı.

Özet fonksiyonları işletim sisteminde birçok yerde karşımıza çıkar. İndirilen bir dosyanın özeti yayımlanan özetle karşılaştırılarak dosyanın bozulmadığı anlaşılır. Parolalar açık hâlde değil, özet olarak saklanır. Bütünlük denetimi yapan araçlar sistem dosyalarının özetlerini saklar ve değişeni bulur. Git her nesneyi özetiyle adlandırır.

Bir özet fonksiyonunun kırılması, çakışma bulmanın pratik hâle gelmesi demektir. MD5'te çakışmalar 2004'te, SHA-1'de 2017'de pratik olarak üretildi. İkisi de güvenlik amacıyla artık kullanılmamalıdır.

Sık yapılan hata

Özeti bir sıkıştırma ya da tek başına bir kanıt saymak. Özetten girdi geri elde edilemez; bu yüzden sıkıştırma değildir. İmzasız bir özet de bütünlüğü kanıtlamaz: belgeyi değiştiren saldırgan, yanındaki özeti de yeniden hesaplayıp değiştirebilir. Özetin güvenilir bir kanaldan gelmesi ya da imzalanması gerekir.

13.2.6Dijital imza

Açık anahtarlı şifreleme ters yönde de kullanılabilir. Özel anahtarla yapılan bir işlemi herkes açık anahtarla denetleyebilir; ama işlemi yalnız özel anahtarın sahibi yapabilir. Dijital imza bu gözleme dayanır.

Tanım 13.7

Dijital imza (digital signature), bir belgenin özetinin göndericinin özel anahtarıyla işlenmesiyle elde edilen değerdir. Herkes göndericinin açık anahtarıyla imzayı doğrulayabilir. Geçerli bir imza iki şeyi kanıtlar: belge değişmemiştir (bütünlük) ve özel anahtarın sahibinden gelmiştir (özgünlük, inkâr edilemezlik).

İmzalama ve doğrulama şu adımlarla yürür (Şekil 13.10).

  1. Özet. Gönderici Alice, D belgesinin özetini hesaplar: H(D). Belgenin kendisini değil özetini imzalamak hem hızlıdır hem de sabit boylu bir girdiyle çalışır.
  2. İmza. Alice özeti özel anahtarı Priv_A ile imzalar ve S imzasını elde eder. Bugünkü algoritmalar RSA-PSS, ECDSA ve Ed25519'dur.
  3. Gönderme. Belge, imza ve Alice'in açık anahtarını taşıyan sertifika birlikte gönderilir. Gizlilik istenmiyorsa belge şifrelenmez.
  4. Doğrulama. Alıcı Bob, belgenin özetini kendisi yeniden hesaplar ve imzayı Pub_A ile doğrular. Doğrulama, imzanın tam bu özete Priv_A ile atıldığını söylüyorsa belge bozulmamıştır ve Alice'ten gelmiştir.
GöndericiAlıcıBelge DSHA-256H(D)İmzala (Priv_A)imza SDS+ sertifika(Pub_A)SHA-256H(D) yenidenDoğrula (Pub_A)eşleşti
Şekil 13.10: Dijital imzanın akışı: gönderici özeti özel anahtarıyla imzalar, alıcı özeti yeniden hesaplar ve imzayı açık anahtarla doğrular.

Yolda belgenin tek bir baytı değişirse ne olur? Bob değişmiş D′ belgesinin özetini hesaplar. Çığ etkisi yüzünden bu özet H(D)'den tamamen farklıdır ve imza onunla eşleşmez (Şekil 13.11). Saldırgan yeni bir geçerli imza da üretemez, çünkü Priv_A onda yoktur.

GöndericiAlıcıBelge DSHA-256H(D)İmzala (Priv_A)imza SD'S+ sertifika(Pub_A)SHA-256H(D) yenidenDoğrula (Pub_A)EŞLEŞMEDİ
Şekil 13.11: Belge yolda D′'ye dönüşürse yeniden hesaplanan özet imzayla eşleşmez ve doğrulama başarısız olur.
Örnek 13.5

Oyuncak RSA anahtarıyla (n = 33, e = 3, d = 7) imzalamayı izleyelim. Belgenin özeti h = 4 olsun.

  1. Bob özel anahtarıyla imzalar: s = hd mod n = 47 mod 33 = 16.
  2. Alıcı açık anahtarla doğrular: se mod n = 163 mod 33 = 4. Sonuç kendi hesapladığı özete eşittir; imza geçerlidir.
  3. Saldırgan belgeyi değiştirir ve özet 5 olur. 163 mod 33 yine 4'tür ve 5'e eşit değildir; doğrulama başarısız olur. Yeni özete uyan imzayı üretmek için d = 7'yi bilmek gerekir.

İmza işlemi, şifrelemeyle karıştırılmaya çok yatkındır. İki işlem anahtarları ters yönde kullanır. Şifrelemede gönderici alıcının açık anahtarını kullanır ve yalnız alıcı çözebilir. İmzada gönderici kendi özel anahtarını kullanır ve herkes doğrulayabilir. Paylaşılan gizli bir anahtarla üretilen doğrulama kodu (MAC) bütünlüğü sağlar, ama inkâr edilemezliği sağlamaz: anahtarı alıcı da bildiği için aynı kodu alıcı da üretebilirdi.

13.2.7Sertifikalar ve açık anahtar altyapısı

Açık anahtarlı şifreleme bir soruyu açık bırakır. Bob, elindeki açık anahtarın gerçekten Alice'e ait olduğunu nereden bilir? Mallory kendi açık anahtarını “Alice'in anahtarı” diye dağıtırsa, Alice'e gönderilen bütün iletileri o okur. Ortadaki adam saldırısı tam olarak budur. Çözüm, anahtarı kimliğe bağlayan ve güvenilir bir üçüncü tarafın imzaladığı bir belgedir.

Tanım 13.8

Sertifika (X.509 biçiminde), bir açık anahtarı sahibinin kimliğine, örneğin bir alan adına bağlayan belgedir. Belgede geçerlilik süresi ve bunları onaylayan bir sertifika otoritesinin (certificate authority, CA) imzası da bulunur. Sertifikaları üreten, dağıtan ve geri alan kurum ve kuralların bütününe açık anahtar altyapısı (public key infrastructure, PKI) denir.

Kök CAöz imzalı; işletim sistemi/tarayıcıgüven deposundaAra CAkök tarafından imzalıwww.ornek.edu.trara CA tarafından imzalıaçık anahtar + alan adıimzalarimzalarTarayıcının doğrulaması1. Sunucu sertifikası + ara CA gelir2. İmzalar zincir boyunca doğrulanır3. Kök, güven deposunda mı?4. Alan adı eşleşiyor mu? Süresi?5. İptal (OCSP/CRL) ve CT kaydı6. Hepsi tamam → bağlantı güvenilirSahte sertifika (MITM)güvenilir bir CA imzalamadığı içinzincir kurulamaz → uyarı
Şekil 13.12: Sertifika zinciri: kök CA ara CA'yı, ara CA sunucu sertifikasını imzalar. Sağda tarayıcının doğrulama adımları.

Sertifikalar bir zincir oluşturur (Şekil 13.12). Zincirin başında kök CA vardır. Kök sertifika öz imzalıdır; onu kimse imzalamaz. Ona duyulan güven, işletim sisteminin ya da tarayıcının güven deposunda önceden yüklü olmasından gelir. Kök CA'lar anahtarlarını çevrimdışı tutar ve günlük işi ara CA'lara bırakır. Ara CA'nın imzaladığı sunucu sertifikası ise örneğin www.ornek.edu.tr alan adını sunucunun açık anahtarına bağlar.

Tarayıcı bir HTTPS sitesine bağlandığında şu denetimleri yapar. Sunucu kendi sertifikasını ve ara CA sertifikasını gönderir. Tarayıcı imzaları zincir boyunca doğrular ve zincirin güven deposundaki bir köke ulaştığını denetler. Sertifikadaki alan adının bağlanılan adla eşleştiğine ve sürenin dolmadığına bakar. Sertifikanın geri alınıp alınmadığını (OCSP ya da CRL ile) ve herkese açık sertifika şeffaflığı (CT) kayıtlarında bulunup bulunmadığını denetler. Hepsi tamamsa bağlantı güvenilir sayılır. Mallory'nin sahte sertifikası ise güvenilir bir CA'nın imzasını taşımadığı için zincir kurulamaz ve tarayıcı uyarı verir.

Sertifika dünyası son on yılda hızla değişti. Let's Encrypt, ACME protokolüyle sertifika almayı ücretsiz ve otomatik hâle getirdi; sertifikaları 90 günlüktür. Kısa ömür, çalınan bir anahtarın zararını sınırlar ve yenilemeyi otomasyona zorlar. Tarayıcı üreticileri ile CA'ların ortak kurulu, sertifika ömrünün 2029'a kadar kademeli olarak 47 güne indirilmesini kararlaştırdı.

13.2.8TLS 1.3 el sıkışması

Önceki araçların hepsi tek bir protokolde birleşir: TLS (Transport Layer Security). HTTPS, güvenli e-posta ve birçok başka protokol TLS'nin üzerinde çalışır. Güncel sürüm TLS 1.3'tür (RFC 8446, 2018). Bağlantının başındaki el sıkışması üç işi birlikte yapar: ortak bir oturum anahtarı kurar, sunucunun kimliğini doğrular ve el sıkışmasının değiştirilmediğini onaylar (Şekil 13.13).

İstemciSunucuClientHello: şifre takımları, key_share (X25519 açık değeri), rastgeleServerHello: seçilen takım, key_shareİki taraf ECDHE ile aynı gizli değeri hesaplar → oturum anahtarları{Certificate, CertificateVerify, Finished}{Finished} — istemci zinciri ve imzayı doğruladı{Uygulama verisi} ⇄ AES-GCM / ChaCha20-Poly1305{ } = şifreli gönderilir (yeşil)
Şekil 13.13: TLS 1.3 el sıkışması (basitleştirilmiş). Süslü ayraç içindeki iletiler şifreli gider.
  1. ClientHello. İstemci desteklediği şifre takımlarını, bir rastgele değeri ve geçici (ephemeral) bir Diffie-Hellman açık değerini gönderir. Bugün bu değer çoğunlukla X25519 eğrisindendir.
  2. ServerHello. Sunucu bir şifre takımı seçer ve kendi Diffie-Hellman açık değerini gönderir. Buraya kadarki her şey açık gider.
  3. Ortak sır. İki taraf da karşı tarafın açık değeri ile kendi gizli değerinden aynı ortak sırrı hesaplar. Bu sır ağda hiç dolaşmaz. Oturum anahtarları ondan türetilir ve bundan sonraki her ileti şifrelidir.
  4. Sunucunun kimliği. Sunucu sertifikasını gönderir. Ardından el sıkışmasının o ana kadarki özetini özel anahtarıyla imzalar (CertificateVerify) ve Finished iletisini ekler. Ortadaki bir saldırgan bu imzayı üretemez, çünkü sunucunun özel anahtarı onda yoktur.
  5. İstemcinin onayı. İstemci sertifika zincirini ve imzayı doğrular. Kendi Finished iletisiyle el sıkışmasının değiştirilmediğini onaylar. Bütün işlem tek bir gidiş-dönüşte (1-RTT) biter.
  6. Uygulama verisi. Veri artık simetrik, kimlik doğrulamalı şifreyle akar: AES-GCM ya da ChaCha20-Poly1305.

Geçici Diffie-Hellman değerleri önemli bir özellik kazandırır: ileriye dönük gizlilik (forward secrecy). Her oturumun anahtarı o oturum için üretilen geçici değerlerden türer ve oturum bitince bu değerler silinir. Sunucunun uzun ömürlü özel anahtarı yalnız imza için kullanılır. Bu anahtar yıllar sonra çalınsa bile, saldırganın kaydettiği eski trafik çözülemez.

13.2.9Kod izleme: Diffie-Hellman anahtar değişimi

TLS'nin kalbindeki Diffie-Hellman değişimi küçük sayılarla elle izlenebilir. İki taraf önceden iki açık sayı üzerinde anlaşır: bir asal p ve bir taban g. Her taraf gizli bir üs seçer, tabanı bu üsse yükseltir ve sonucu açıkça gönderir. Sonra karşı tarafın açık değerini kendi gizli üssüne yükseltir. Üs alma işleminin yer değiştirme özelliği sayesinde iki taraf aynı sayıya ulaşır:

A = ga mod p,   B = gb mod p,   s = Ba = Ab = gab mod p

Sunumdaki kod, büyük üsleri verimli hesaplayan modpow fonksiyonunu ve değişimin dört hesabını içerir.

long modpow(long g, long e, long p) {
    long r = 1;
    while (e > 0) {
        if (e & 1) r = r * g % p;
        g = g * g % p;
        e >>= 1;
    }
    return r;
}
/* açık: p = 23, g = 5 */
long A  = modpow(5, 6, 23);
long B  = modpow(5, 15, 23);
long sA = modpow(B, 6, 23);
long sB = modpow(A, 15, 23);

modpow “kare al ve çarp” yöntemini kullanır. Üs e'nin bitleri sağdan sola taranır. Her turda bit 1 ise sonuç r, o anki taban g ile çarpılır. Sonra taban kendisiyle çarpılarak bir sonraki bitin ağırlığına getirilir: g, g2, g4, g8 … Her çarpmadan sonra mod p alındığı için sayılar hiç büyümez. Üs n bitse döngü n tur döner. 515 için düz yöntem 14 çarpma isterken bu yöntem 4 turda biter. 2048 bitlik üslerde fark, mümkün ile imkânsız arasındaki farktır.

Alice gizli a = 6'yı seçmiştir. A = modpow(5, 6, 23) hesabı Tablo 13.5 gibi ilerler. 6'nın ikili gösterimi 110'dur.

Tablo 13.5: modpow(5, 6, 23) izlemesi. Başlangıçta r = 1, g = 5, e = 6. Değerler Python ile yeniden hesaplandı.
Ture & 1rg (sonra)e (sonra)Açıklama
1015 · 5 mod 23 = 23bit 0: r değişmez
211 · 2 = 22 · 2 = 41bit 1: r = r · g
312 · 4 = 84 · 4 = 160bit 2: r = r · g; döngü biter

Fonksiyon 8 döndürür: A = 8. Bu değer ağa açık gönderilir; a = 6 ise Alice'in makinesinden hiç çıkmaz. Bob da gizli b = 15 ile aynı fonksiyonu çalıştırır (Tablo 13.6). 15'in ikili gösterimi 1111'dir; dört bitin hepsi 1 olduğu için her turda çarpma yapılır.

Tablo 13.6: modpow(5, 15, 23) izlemesi. Başlangıçta r = 1, g = 5, e = 15.
Ture & 1rg (sonra)e (sonra)
111 · 5 = 525 mod 23 = 27
215 · 2 = 1043
3110 · 4 = 40 mod 23 = 17161
4117 · 16 = 272 mod 23 = 19256 mod 23 = 30

B = 19 ağdan Alice'e gider. Şimdi iki taraf karşı tarafın açık değerini kendi gizli üssüne yükseltir. Alice sA = modpow(19, 6, 23) hesaplar: turlar r = 1, 16, 2 değerlerinden geçer ve sonuç 2 olur. Bob sB = modpow(8, 15, 23) hesaplar: r = 8, 6, 12, 2 ve sonuç yine 2'dir. İki taraf da 56·15 mod 23 = 590 mod 23 değerini hesaplamıştır.

Alicea = 6 (gizli)s = 2Bobb = 15 (gizli)s = 2ağ (herkes görür)p = 23, g = 5A = 8B = 19sB = modpow(8, 15, 23)Bob: A^b mod p = 8¹⁵ mod 23 = 2her iki taraf da 5^(6·15) mod 23 = 2 buldu
Şekil 13.14: Değişimin sonu: Alice ve Bob ortak sır s = 2'ye ulaştı; ağdan yalnız p, g, A ve B geçti.

Ağı dinleyen Eve p = 23, g = 5, A = 8 ve B = 19'u görür. Ortak sırrı bulmak için a'yı ya da b'yi bilmesi gerekir. a'yı bulmak, 5a mod 23 = 8 denklemini çözmektir. Buna ayrık logaritma problemi denir. Bu küçük örnekte Eve 22 olasılığı deneyerek a = 6'yı hemen bulur. Gerçekte p 2048 bit uzunluğundadır ya da X25519 eğrisi kullanılır. Bilinen hiçbir algoritma bu boyda bir problemi makul sürede çözemez.

Sık yapılan hata

Diffie-Hellman'ın tek başına ortadaki adam saldırısını önlediğini sanmak. Değişim yalnız “ağı dinleyen” Eve'e karşı güvenlidir. Mallory araya girip Alice ile bir, Bob ile ayrı bir değişim yaparsa iki tarafla da ayrı birer ortak sır kurar ve bütün trafiği okur. Bu yüzden TLS'de sunucu, el sıkışmasını sertifikasındaki anahtarla imzalar. Kimlik doğrulamasız Diffie-Hellman güvenli değildir.

13.3Koruma

Kriptografi verinin sistem dışında, ağda ya da diskte korunmasını sağlar. Sistemin içinde ise başka bir soru sorulur: çalışan bir süreç hangi nesnelere hangi haklarla erişebilir? Bu kesim bu sorunun modelini (koruma matrisi), modelin iki uygulama biçimini (erişim denetim listeleri ve yetenekler) ve hakları en aza indirme yollarını anlatır.

13.3.1Koruma etki alanları

Bir bilgisayar sisteminde korunması gereken nesneler vardır: dosyalar, bellek kesimleri, yazıcılar, semaforlar, süreçler. Her nesnenin kendine özgü işlemleri bulunur: bir dosya okunur, yazılır, çalıştırılır; bir yazıcıya yalnız yazılır. Bir süreç belirli bir anda bu nesnelerin bir kısmına belirli haklarla erişebilir. Bu (nesne, hak) çiftlerinin kümesine etki alanı denir (Şekil 13.15).

Tanım 13.9

Koruma etki alanı (protection domain), (nesne, haklar) çiftlerinden oluşan bir kümedir. Her süreç her an bir etki alanında çalışır ve yalnız o alanın izin verdiği işlemleri yapabilir.

Etki alanı 1Dosya1[R]Dosya2[RW]Etki alanı 2Dosya3[R]Dosya4[RWX]Dosya5[RW]Etki alanı 3Dosya6[RWX]Çizici2[W]Yazıcı1[W]Yazıcı1 hem D2 hem D3’te: nesneler etki alanları arasında paylaşılabilir
Şekil 13.15: Üç koruma etki alanı. Yazıcı1 hem ikinci hem üçüncü alanda bulunur: nesneler etki alanları arasında paylaşılabilir.

Şekil 13.15'te birinci etki alanı Dosya1'i okuyabilir, Dosya2'yi okuyup yazabilir. İkinci alan Dosya3'ü okur, Dosya4 üzerinde bütün hakları kullanır, Dosya5'i okuyup yazar ve Yazıcı1'e yazar. Üçüncü alanda Dosya6 (RWX), Çizici2 (W) ve yine Yazıcı1 (W) vardır. Etki alanları ayrık olmak zorunda değildir: aynı nesne birden çok alanda, hatta farklı haklarla bulunabilir.

UNIX ve Linux'ta bir etki alanı, kullanıcı kimliği (UID) ile grup kimliklerinin (GID) kümesiyle belirlenir. Aynı UID ve GID'lerle çalışan iki süreç aynı nesnelere aynı haklarla erişir. Bunun yanında çekirdek kipi ve kullanıcı kipi de iki ayrı etki alanıdır. Çekirdek kipinde çalışan kod bütün belleğe ve bütün aygıtlara erişebilir.

Süreçler çalışırken etki alanı değiştirebilir. Bir sistem çağrısı süreci kullanıcı kipinden çekirdek kipine geçirir; çağrı bitince süreç eski alanına döner. Bir süreç setuid bitli bir programı çalıştırdığında ise programın sahibinin etki alanına geçer.

13.3.2Koruma matrisi

Bütün etki alanlarının bütün haklarını tek bir tabloda göstermek mümkündür. Lampson'ın 1971'de önerdiği bu tabloya koruma matrisi ya da erişim matrisi denir.

Tanım 13.10

Koruma matrisinde (access matrix) her satır bir etki alanını, her sütun bir nesneyi gösterir. Satır i ile sütun j'nin kesiştiği hücre, i etki alanındaki bir sürecin j nesnesi üzerindeki haklarını içerir.

Tablo 13.7: Etki alanlarının da nesne olarak yer aldığı koruma matrisi. “Gir” hakkı başka bir etki alanına geçmeye izin verir.
Dosya1Dosya2Dosya3Dosya4Dosya5Yazıcı1Dosya6Çizici2D1D2D3
D1RRWGir
D2RRWXRWW
D3WRWXW

Tablo 13.7 matrise ilginç bir özellik ekler: etki alanları da birer nesnedir. D1 satırının D2 sütunundaki Gir (enter) hakkı, D1'de çalışan bir sürecin D2'ye geçebileceğini söyler. Böylece etki alanı değiştirme de matrisin denetimi altına girer. Aynı yolla matrisin kendisini değiştirme hakları da modellenebilir: bir hakkı başkasına kopyalama, bir nesnenin sahibi olarak haklarını düzenleme gibi.

Matrisin her durumu güvenlik politikasıyla karşılaştırılabilir. Politikaya göre Eve'in bir dosyayı hiçbir zaman okuyamaması gerekiyorsa, Eve'in satırında o dosyanın hücresinde R görülmemelidir. Bir dizi meşru komuttan sonra o hücrede R belirirse sistem yetkili durumdan yetkisiz duruma geçmiş demektir. Doğal bir soru akla gelir: bir başlangıç durumundan ve izinli komutlardan, yetkisiz bir duruma varılıp varılamayacağı önceden hesaplanabilir mi? Harrison, Ruzzo ve Ullman 1976'da bu sorunun genel durumda karar verilemez olduğunu gösterdi. “Bir hak sızabilir mi?” sorusunu her matris için yanıtlayan bir algoritma yoktur. Bu sonuç, kuralları baştan kısıtlayan Bell-LaPadula ve Biba gibi modellerin neden geliştirildiğini açıklar.

Matrisin uygulamadaki sorunu boyutudur. Binlerce kullanıcı ve milyonlarca dosya bulunan bir sistemde matrisin milyarlarca hücresi olur; bunların çok büyük çoğunluğu boştur. Matris çok seyrektir. Tablo 13.7'deki küçük örnekte bile, yalnız sekiz nesne sütunu ele alındığında 24 hücreden 15'i boştur. Bu yüzden matrisin tamamı hiçbir zaman saklanmaz. Ya sütunlar ya da satırlar saklanır ve boş hücreler atlanır.

13.3.3Aynı matrisin iki biçimi: ACL ve yetenek

Matrisi sütun sütun saklamak, her nesnenin yanına “bu nesneye kimler hangi haklarla erişebilir?” listesini koymak demektir. Satır satır saklamak ise her etki alanına “bu alan hangi nesnelere hangi haklarla erişebilir?” listesini vermektir (Şekil 13.17).

Tanım 13.11

Erişim denetim listesi (access control list, ACL), matrisin bir sütunudur. Bir nesneye hangi etki alanlarının hangi haklarla erişebileceğini sıralar ve nesneyle birlikte saklanır. Yetenek listesi (capability list, C-listesi) ise matrisin bir satırıdır: bir etki alanının erişebildiği nesneleri ve haklarını sıralar. Listedeki her girdiye yetenek (capability) denir.

Dosya1Dosya2Dosya3Dosya4Dosya5Yazıcı1Dosya6Çizici2D1RRWD2RRWXRWWD3WRWXWACL = sütun (nesneyle saklanır)Dosya1D1:RDosya2D1:RWDosya4D2:RWXYazıcı1D2:W → D3:WDosya6D3:RWX
Şekil 13.16: Matrisin boş olmayan sütunları birer ACL olur. Örneğin Yazıcı1'in ACL'si D2:W ve D3:W'dir.
Dosya1Dosya2Dosya3Dosya4Dosya5Yazıcı1Dosya6Çizici2D1RRWD2RRWXRWWD3WRWXWYetenek listesi = satır (süreçle/çekirdekte saklanır)Süreç (D2)Dosya3 : RDosya4 : RWXDosya5 : RWYazıcı1 : WSüreç nesneye erişirken listedeki yeteneği gösterir; isim çözümleme ve ACL taraması gerekmez
Şekil 13.17: Aynı matrisin bir satırı: D2'nin yetenek listesi Dosya3:R, Dosya4:RWX, Dosya5:RW ve Yazıcı1:W'dir.

ACL düzeninde bir süreç bir nesneye erişmek istediğinde çekirdek nesnenin ACL'sini açar ve sürecin kimliğini bu listede arar. Yetenek düzeninde ise süreç erişirken elindeki yeteneği gösterir. Çekirdeğin yalnız yeteneğin geçerli olduğunu denetlemesi yeterlidir; bir ad çözümlemesi ya da liste taraması gerekmez.

İki gösterim aynı bilgiyi taşır, ama farklı soruları kolay yanıtlar (Tablo 13.8).

Tablo 13.8: ACL ve yetenek listesinin karşılaştırılması.
SoruACL (sütun)Yetenek (satır)
Nerede saklanır?Nesnenin yanındaEtki alanında (süreçte ya da çekirdekte)
“Bu nesneye kim erişebilir?”Kolay: listeye bakılırZor: bütün süreçler taranır
“Bu süreç neye erişebilir?”Zor: bütün nesneler taranırKolay: listeye bakılır
Bir hakkı geri almaKolay: tek girdi silinirZor: bütün kopyalar bulunmalı
Bir hakkı devretmeNesnenin listesi değişmeliKolay: yetenek kopyalanır
Erişim anındaki maliyetListe taramasıYeteneğin geçerliliği denetlenir
Örnek 13.6

Tablo 13.7'deki matriste D3'ün Yazıcı1 hakkı hemen kaldırılmak isteniyor. Ayrıca D2, Dosya5 üzerindeki okuma hakkını D1'e devretmek istiyor. Her iş hangi gösterimde kolaydır?

  1. Geri alma. ACL düzeninde Yazıcı1'in listesi {D2:W, D3:W}'dir; D3 girdisi silinir ve iş biter. Yetenek düzeninde D3'ün listesindeki yetenek silinmelidir. Ama D3 bu yeteneği daha önce başka süreçlere kopyalamış olabilir. Bütün kopyaları bulmak için sistemdeki bütün yetenek listelerini taramak gerekir.
  2. Devretme. Yetenek düzeninde D2, Dosya5:R yeteneğinin bir kopyasını D1'e verir; Dosya5'in kendisine dokunulmaz. ACL düzeninde ise Dosya5'in listesine yeni bir D1:R girdisi eklenmelidir; bunu yalnız nesnenin sahibi yapabilir.

Gerçek sistemler çoğu zaman iki gösterimi birleştirir. UNIX, bir dosyayı açarken izin bitlerini, yani bir tür ACL'yi denetler. Açılan dosya için sürece bir dosya tanımlayıcısı verir. Bu tanımlayıcı aslında bir yetenektir: sonraki read ve write çağrılarında izin yeniden denetlenmez. Dosyanın izinleri bu arada değiştirilse bile açık tanımlayıcı çalışmayı sürdürür.

13.3.4UNIX izinleri ve POSIX ACL'leri

Klasik UNIX, ACL fikrinin çok sıkıştırılmış bir biçimini kullanır. Her dosyanın bir sahibi ve bir grubu vardır. Dosyanın i-düğümünde üç sınıf için üçer bit tutulur: sahip (u), grup (g) ve diğerleri (o). Her üçlüde okuma (r), yazma (w) ve çalıştırma (x) bitleri vardır. Toplam dokuz bit, sekizli tabanda üç rakamla yazılır: r = 4, w = 2, x = 1.

$ ls -l rapor.txt
-rw-r----- 1 ali muhasebe 4096 rapor.txt
 rw-  sahip   r--  grup   ---  diğer

$ setfacl -m u:ayse:rw rapor.txt
$ getfacl rapor.txt
user::rw-
user:ayse:rw-
group::r--
mask::rw-
other::---

Çıktıdaki -rw-r----- dizgisi ilk karakterden sonra üç üçlüye bölünür. Sahip ali okur ve yazar (rw- = 4 + 2 = 6). muhasebe grubunun üyeleri yalnız okur (r-- = 4). Diğerlerinin hiçbir hakkı yoktur (--- = 0). Dosyanın sekizli modu 640'tır ve chmod 640 rapor.txt komutuyla bu hâle getirilebilir.

Yeni oluşturulan dosyaların izinleri umask değeriyle belirlenir. Program genellikle dosya için 666, dizin için 777 ister. Çekirdek umask'te 1 olan bitleri bu değerden siler. Yaygın umask 022 ile dosyalar 644 (rw-r--r--), dizinler 755 (rwxr-xr-x) olur. Daha sıkı bir umask olan 077 ile dosyalar yalnız sahibine açıktır: 600.

Dokuz bitlik düzen hızlıdır ve i-düğümüne sığar, ama kaba tanelidir. Ali dosyasını muhasebe grubunun tamamına değil, yalnız Ayşe'ye yazılabilir kılmak isterse dokuz bit yetmez. POSIX ACL'leri bu boşluğu doldurur. setfacl -m u:ayse:rw rapor.txt komutu listeye adlı bir kullanıcı girdisi ekler. getfacl çıktısında bu girdiyi ve yeni bir satırı görürüz: mask. Maske, adlı kullanıcı ve grup girdilerinin ulaşabileceği en fazla hakkı sınırlar. Ayşe'nin girdisi rw- olsa bile maske r-- yapılırsa Ayşe etkin olarak yalnız okuyabilir. ACL taşıyan dosyalar ls -l çıktısında izin dizgisinin sonundaki + işaretiyle ayırt edilir.

Örnek 13.7

Bir betik dosyasının modu 754'tür. Sahip, grup üyeleri ve diğerleri neler yapabilir? umask 027 iken oluşturulan yeni bir dosya ve dizin hangi izinleri alır?

  1. 7 = 4 + 2 + 1: sahip okur, yazar ve çalıştırır (rwx).
  2. 5 = 4 + 1: grup okur ve çalıştırır (r-x).
  3. 4: diğerleri yalnız okur (r--). Dizgi rwxr-xr--'dur.
  4. umask 027, gruptan yazmayı (2) ve diğerlerinden her şeyi (7) siler. Dosya: 666 → 640 (rw-r-----). Dizin: 777 → 750 (rwxr-x---).

Windows'un NTFS dosya sistemi daha zengin bir ACL modeli kullanır. Her nesnenin isteğe bağlı erişim denetim listesi (DACL) sıralı girdilerden oluşur. Her girdi bir güvenlik kimliği (SID) ile bir hak maskesini ve bir izin ya da ret türünü taşır. Açık ret girdileri izinlerden önce gelir. Bir klasörün ACL'si içindeki dosyalara kalıtım yoluyla geçer. Komut satırında icacls aracı bu listeleri gösterir ve düzenler. POSIX, NFSv4 ve NTFS ACL'lerinin anlamları tam örtüşmez. Bu yüzden dosyalar sistemler arasında taşınırken haklar bazen beklenmedik biçimde değişir.

ACL düzeninin artısı anlaşılır olmasıdır. Bir nesneye kimin erişebildiği tek bakışta görülür ve bir hak nesne başına kolayca geri alınır. Eksisi büyük sistemlerde yönetimin zorlaşması ve her erişimde listenin taranmasıdır. Tarama maliyeti önbellekle hafifletilir: UNIX'te izin denetimi yalnız open anında yapılır.

Örnek 13.8

Kullanıcılar dört gruba ve bir yönetici rolüne ayrılmış, dört nesne (A, B, C, D) var (Tablo 13.9). C nesnesinin ACL'si nedir? Grup 4 hangi nesnelere erişebilir?

Tablo 13.9: Gruplar ve nesneler için koruma matrisi.
GrupABCD
Grup 1RRWX——
Grup 2W———
Grup 3——XR
Grup 4————
YöneticiRWXRWXRWXRWX

C'nin ACL'si sütunun boş olmayan hücreleridir: {Grup 3: X, Yönetici: RWX}. Grup 4'ün satırı tamamen boştur, yani hiçbir ACL'de yer almaz. Güvenli varsayılan gereği bu grup hiçbir nesneye erişemez.

13.3.5Kod izleme: erişim denetim listesi

Çekirdeğin bir ACL'yi nasıl taradığını küçük bir C fonksiyonuyla izleyebiliriz. A dosyasının ACL'si koruma matrisinin A sütunudur: Grup 1 okur, Grup 2 yazar, yönetici her şeyi yapar. Haklar bit olarak kodlanır: R = 4, W = 2, X = 1.

/* A dosyasının ACL'si: R=4 W=2 X=1 */
struct girdi { int grup, hak; } acl[] =
    {{G1, 4}, {G2, 2}, {YON, 7}};

int erisim(int grup, int istek) {
    for (int i = 0; i < 3; i++)
        if (acl[i].grup == grup) {
            int h = acl[i].hak;
            return (h & istek) == istek;
        }
    return 0;   /* listede yok: yasak */
}

Dizide yalnız üç girdi vardır; Grup 3 ve Grup 4'ün A üzerindeki hücreleri boş olduğu için saklanmaz. erisim fonksiyonu listeyi baştan tarar. İsteyen grubu bulduğu ilk girdide kararı verir ve döner. Karar ifadesi (h & istek) == istek'tir. İstenen hakların hepsi girdide varsa VE işleminin sonucu isteğin kendisine eşit olur. Biri bile eksikse sonuç farklıdır ve erişim reddedilir. Grup listede yoksa döngü tamamlanır ve fonksiyon 0 döndürür. Tablo 13.10 dört çağrıyı izler.

Tablo 13.10: erisim fonksiyonunun dört çağrısı. Değerler Python ile yeniden hesaplandı.
ÇağrıBakılan iEşleşen girdih & istekSonuç
erisim(G2, W)0, 1i = 1, h = 22 & 2 = 2izin
erisim(G1, W)0i = 0, h = 44 & 2 = 0 ≠ 2ret
erisim(G4, R)0, 1, 2yok—ret (0)
erisim(YON, R|X)0, 1, 2i = 2, h = 77 & 5 = 5izin
istek: YON · R|X (5)izinacl[] (A dosyasıyla birlikte saklanır)G1 : R--i = 0G2 : -W-i = 1YON : RWXi = 2
Şekil 13.18: Son çağrı: yönetici okuma ve çalıştırma hakkını birlikte istiyor (5); üçüncü girdide eşleşme bulunur ve 7 & 5 = 5 olduğu için izin verilir.

İzleme üç dersi açıkça gösterir. Birincisi, karar ilk eşleşen girdide verilir: Grup 1'in yazma isteği reddedilir ve liste daha fazla taranmaz. NTFS'te ret girdilerinin başa konmasının nedeni de budur. İkincisi, listede bulunmayan bir grubun isteği için bütün liste taranır. Uzun ACL'lerde her erişimin maliyeti budur: n girdili bir listede en kötü durumda O(n) karşılaştırma. Üçüncüsü, güvenli varsayılan ilkesi koda gömülüdür. Açıkça izin verilmeyen her şey yasaktır; fonksiyonun son satırı bunu söyler.

Sık yapılan hata

Karar ifadesini (h & istek) != 0 diye yazmak. Bu ifade istenen haklardan biri varsa izin verir. Grup 1 okuma ve yazmayı birlikte isterse (6) sonuç 4 & 6 = 4 ≠ 0 olur ve yazma hakkı olmadığı hâlde izin verilir. Doğru ifade, istenen bitlerin hepsinin girdide bulunmasını ister.

13.3.6Yetenek listeleri

Yetenek düzeninde bir yetenek, sahibine bir nesneye erişme hakkı veren bir bilettir. Biletin en önemli özelliği sahte üretilememesidir. Bir süreç kendi kendine “Dosya7'ye yazma yeteneği” üretebilseydi düzen hiçbir şey korumazdı. Yetenekleri sahte üretimden korumanın üç yolu vardır.

Çekirdekte tutmak
Yetenek listesi çekirdeğin belleğinde durur. Süreç yalnız listedeki bir girdinin indisini bilir ve bu indisi sistem çağrısına verir: read(cap 2, …). UNIX dosya tanımlayıcıları tam olarak böyle çalışır (Şekil 13.19).
Etiketli donanım
Bellekteki her sözcüğe, onun bir yetenek olup olmadığını gösteren ek bir bit eklenir. Bu bit yalnız özel komutlarla değiştirilebilir. Cambridge Üniversitesi'nin CHERI mimarisi bu yaklaşımı bugünkü işlemcilere taşır.
Şifreli koruma
Yetenek kullanıcının elinde durur, ama bir doğrulama alanı taşır. Bu alan, nesne ve hakların yalnız sunucunun bildiği bir gizli değerle birlikte tek yönlü bir fonksiyondan (örneğin HMAC) geçirilmesiyle elde edilir. Kullanıcı hakları değiştirirse doğrulama alanı tutmaz. Amoeba dağıtık işletim sistemi bu yöntemi kullanırdı.
Süreçkullanıcı moduyalnız indis görür:read(cap 2, …)Çekirdekteki C-listesi0Dosya3 R1Dosya4 RWX2Dosya5 RW3Yazıcı1 WŞifreli korumalı yetenekSunucuNesneHaklarf(Nesne, Haklar, Gizli)Kullanıcıda dursa bile sahte üretilemez:f tek yönlü (ör. HMAC); gizli değeriyalnız sunucu bilir (Amoeba).
Şekil 13.19: Solda çekirdekte tutulan C-listesi: süreç yalnız indis görür. Sağda şifreli korumalı yetenek biçimi.

Yetenekler üzerinde dört temel işlem tanımlanır. Yeteneği kopyalamak aynı nesne için yeni bir yetenek üretir; devretme budur. Nesneyi kopyalamak yeni bir nesne ve ona ait yeni bir yetenek üretir. Yeteneği kaldırmak listeden bir girdiyi siler; nesne yerinde kalır. Nesneyi yok etmek ise nesneyi ve ona ait yeteneği kalıcı olarak siler.

Saf yetenek sistemleri bugün araştırma ve özel alanlarda yaşar: biçimsel olarak doğrulanmış seL4 mikro çekirdeği ve Google'ın Fuchsia sistemi baştan sona yeteneklerle çalışır. FreeBSD'nin Capsicum altyapısı ise sıradan bir UNIX'e yetenek kipi ekler. Bu kipe geçen bir süreç artık dosya adlarıyla yeni dosya açamaz; yalnız elindeki tanımlayıcıları kullanabilir.

13.3.7En az ayrıcalık ve setuid

Saltzer ve Schroeder'in 1975'teki ünlü makalesi, güvenli sistem tasarımının ilkelerini sıralar. Bunların en çok bilineni şudur.

Tanım 13.12

En az ayrıcalık ilkesi (principle of least privilege): her bileşen, işine yetecek en küçük hak kümesiyle çalışmalıdır. Bu haklar da yalnız gerektiği süre boyunca tutulmalıdır. Bileşen ele geçirilirse verebileceği zarar bu kümeyle sınırlı kalır.

UNIX'te bu ilkeyle çatışan klasik bir durum vardır. Parolaların özetleri /etc/shadow dosyasında durur. Dosyanın sahibi root'tur ve modu -rw-r-----'dır: sıradan kullanıcılar onu okuyamaz bile. Peki Ali kendi parolasını nasıl değiştirir? Çözüm setuid bitidir. /usr/bin/passwd programının sahibi root'tur ve izinlerinde x yerine s görülür: -rwsr-xr-x. Bu bit açıkken program, onu çalıştıranın değil dosya sahibinin haklarıyla çalışır.

Bu davranışı anlamak için bir sürecin üç kullanıcı kimliğini bilmek gerekir. Gerçek kimlik (ruid) süreci başlatan kullanıcıdır. Etkin kimlik (euid) izin denetimlerinde kullanılan kimliktir. Saklı kimlik (suid), sürecin daha sonra geri dönebileceği bir kimliği saklar. Normalde üçü eşittir. setuid bitli bir program execve ile başlatıldığında etkin ve saklı kimlik dosya sahibine çevrilir; gerçek kimlik değişmez.

/* /usr/bin/passwd  -rwsr-xr-x root */
int main(void) {
    uid_t me = getuid();
    int fd = open("/etc/shadow", O_RDWR);
    update_own_entry(fd, me);
    close(fd);
    setresuid(me, me, me);
    /* ... kalan iş ... */
    open("/etc/shadow", O_RDWR);
}

Kod, ayrıcalığı yalnız gerektiği kadar kullanan bir passwd taslağıdır. getuid() gerçek kimliği döndürür. Program kimin adına çalıştığını buradan öğrenir ve yalnız onun satırını değiştirir. open çağrısında çekirdek erişimi etkin kimliğe göre denetler. euid 0 olduğu için dosya açılır. İş biter bitmez setresuid(me, me, me) üç kimliğin üçünü de 1000 yapar. Saklı kimlik de değiştiği için geri dönüş yoktur. Son satırdaki ikinci open artık EACCES hatasıyla başarısız olur ve −1 döner (Tablo 13.11).

Tablo 13.11: Ali (uid 1000) passwd'yi çalıştırdığında kimliklerin izlenmesi. Değerler Python benzetimiyle doğrulandı.
AdımruideuidsuidSonuç
kabuk (ali)100010001000ayrıcalıksız
execve (setuid root)100000etkin kimlik dosya sahibine döner
getuid()1000001000 döner
open("/etc/shadow")100000izin verildi (euid 0)
setresuid(1000, 1000, 1000)100010001000ayrıcalık kalıcı bırakıldı
open("/etc/shadow")100010001000EACCES, fd = −1
passwd süreciruid = 1000 (ali)euid = 1000/etc/shadow-rw-r-----root shadowEACCES: izin reddedildi
Şekil 13.20: Ayrıcalık bırakıldıktan sonra euid 1000'dir ve /etc/shadow'a erişim reddedilir.

Ayrıcalığı bu kadar erken bırakmanın değeri, programın geri kalanında bir hata çıktığında anlaşılır. Diyelim ki programın sonraki kısmında bir tampon taşması var ve saldırgan bu hatayı istismar ederek kendi kodunu çalıştırıyor. Ayrıcalık bırakılmasaydı saldırganın kodu root olarak çalışırdı. Bırakıldığı için Ali'nin haklarıyla çalışır ve Ali'nin zaten yapabildiğinden fazlasını yapamaz. setuid root programlar bu yüzden ayrıcalık yükseltme saldırılarının klasik hedefidir. Her biri dikkatle incelenmeli ve sayıları en aza indirilmelidir.

Sık yapılan hata

Ayrıcalığı seteuid(getuid()) ile bıraktığını sanmak. Bu çağrı yalnız etkin kimliği değiştirir; saklı kimlik 0 olarak kalır. Ayrıcalıksız bir süreç etkin kimliğini gerçek ya da saklı kimliğine çevirebildiği için, saldırganın kodu seteuid(0) ile yeniden root olur. Kalıcı bırakmada saklı kimlik de değiştirilmelidir: setresuid(me, me, me).

13.3.8Linux yetenekleri ve tasarım ilkeleri

Geleneksel UNIX'te root ya her şeyi yapabilir ya da hiçbir şeyi. 1024'ün altındaki kapılar ayrıcalıklıdır. Bu yüzden 80. kapıyı dinlemek isteyen bir web sunucusu root olmak zorundadır. Böylece web sunucusu dosya izinlerini aşma, saati değiştirme, çekirdek modülü yükleme haklarını da gereksiz yere kazanır. Linux, root'un tek parça yetkisini yaklaşık 41 ayrı parçaya böler ve bunlara yetenek (capability) der (Şekil 13.21). Buradaki “yetenek” sözcüğü, yetenek listesi düzenindekiyle aynı değildir; anlamı “ayrıcalık parçası”dır.

root (uid 0)her şeye izinCAP_NET_BIND_SERVICE1024 altı kapıCAP_NET_ADMINağ yapılandırmaCAP_SYS_TIMEsaati ayarlamaCAP_DAC_OVERRIDEdosya izinlerini aşmaCAP_KILLbaşkasına sinyalCAP_SYS_ADMIN“yeni root”: çok geniş≈ 41 yetenek; her iş parçacığının izinli, etkin, kalıtılabilir ve sınırlayıcı kümeleri var
Şekil 13.21: Root yetkisinin Linux yeteneklerine bölünmesi. CAP_SYS_ADMIN o kadar geniştir ki “yeni root” diye anılır.

Örneğin CAP_NET_BIND_SERVICE 1024'ün altındaki kapıları açma hakkıdır. CAP_DAC_OVERRIDE dosya izinlerini aşar, CAP_KILL başka kullanıcıların süreçlerine sinyal gönderir, CAP_SYS_TIME sistem saatini ayarlar. Her iş parçacığının dört yetenek kümesi vardır: izinli, etkin, kalıtılabilir ve sınırlayıcı. Bir dosyaya da yetenek atanabilir. Aşağıdaki komutlar web sunucusuna yalnız düşük kapı açma hakkını verir.

$ sudo setcap cap_net_bind_service=+ep /usr/local/bin/websrv
$ getcap /usr/local/bin/websrv
/usr/local/bin/websrv cap_net_bind_service=ep     # 80. kapıyı açabilir, başka hiçbir root hakkı yok

=ep soneki yeteneğin izinli (p) ve etkin (e) kümelere eklendiğini söyler. Program artık root olmadan 80. kapıyı dinleyebilir. Ele geçirilse bile dosya izinlerini aşamaz ya da başka süreçleri öldüremez.

Saltzer ve Schroeder'in listesi en az ayrıcalıkla bitmez. Öteki ilkeler de bugünkü sistemlerde karşılık bulur.

Güvenli varsayılan
Açıkça izin verilmeyen her şey yasaktır. ACL taramasının son satırındaki return 0 bu ilkedir.
Tam aracılık
Her erişim denetlenir; bir kez verilen izin önbellekte sonsuza dek geçerli sayılmaz. Referans izleyicinin birinci koşuludur.
Açık tasarım
Güvenlik, tasarımın gizli kalmasına dayanmaz. Kerckhoffs ilkesinin genel biçimidir.
Ayrıcalıkların ayrılması
Kritik bir işlem birden çok koşula ya da kişiye bağlanır. İki anahtarlı kasa ve iki kişi onayı bu ilkenin örnekleridir.
Psikolojik kabul edilebilirlik
Güvenlik mekanizması kullanıcıyı bezdirmemelidir. Aksi hâlde kullanıcılar onu atlatmanın yolunu bulur: parolayı ekrana yapıştırır, izinleri 777 yapar.

Bugünkü yazılımlar bu ilkeleri ayrıcalık ayrımı (privilege separation) ile uygular. OpenSSH sunucusu buna iyi bir örnektir. Küçük bir root süreci yalnız kimlik doğrulama gibi ayrıcalık gerektiren işleri yapar. Ağdan gelen verinin ayrıştırılması gibi riskli işler, hiçbir ayrıcalığı olmayan bir çocuk süreçte yürür. systemd de hizmet dosyalarında CapabilityBoundingSet= ile bir hizmetin hangi yetenekleri kullanabileceğini sınırlar. NoNewPrivileges= ise hizmetin setuid programlar aracılığıyla yeni ayrıcalık kazanmasını engeller.

13.4Biçimsel güvenlik modelleri

Koruma matrisi her politikayı ifade edebilir, ama bir hakkın sızıp sızmayacağı genel durumda hesaplanamaz. Biçimsel modeller bu sorunu kuralları baştan kısıtlayarak çözer. Kurallar o kadar basittir ki uyulduğu sürece belirli bir zararın imkânsız olduğu kanıtlanabilir. Bu kesimde iki klasik model ve onların bile kapatamadığı bir sızıntı yolu, gizli kanallar ele alınır.

İki modelde de denetimi kullanıcı değil sistem yapar. Sıradan UNIX izinlerinde dosyanın sahibi izinleri istediği gibi değiştirebilir; buna isteğe bağlı erişim denetimi (discretionary access control, DAC) denir. Biçimsel modellerde ise politikayı yönetici belirler ve hiçbir süreç onu gevşetemez; buna zorunlu erişim denetimi (mandatory access control, MAC) denir.

13.4.1Bell-LaPadula modeli

Askerî kuruluşlarda belgeler gizlilik düzeylerine ayrılır. Sunumdaki düzenle bu düzeyler büyükten küçüğe Çok Gizli (4), Gizli (3), Hizmete Özel (2) ve Tasnif Dışı (1)'dir. Her kişinin de bir yetki düzeyi vardır. Bell ve LaPadula'nın 1973'te tanımladığı model, bu düzenin bilgisayardaki karşılığıdır. Amacı tek bir şeydir: bilginin yüksek düzeyden alçak düzeye sızmasını engellemek.

Tanım 13.13

Bell-LaPadula modelinde (BLP) her süreç ve her nesne bir gizlilik düzeyi taşır. Model iki kural koyar:

  • Basit güvenlik özelliği: k düzeyindeki bir süreç yalnız düzeyi k'ye eşit ya da k'den küçük nesneleri okuyabilir (yukarı okuma yok).
  • * özelliği (yıldız özelliği): k düzeyindeki bir süreç yalnız düzeyi k'ye eşit ya da k'den büyük nesnelere yazabilir (aşağı yazma yok).

Birinci kural sezgiyle uyumludur: Gizli yetkili bir kişi Çok Gizli bir belgeyi okuyamaz. İkinci kural ilk bakışta tuhaf görünür. Gizli düzeydeki bir süreç neden Tasnif Dışı bir dosyaya yazamasın? Cevap, sürecin okuduğu bilgiyi yazdığı yere taşıyabilmesidir. Gizli bir belgeyi okuyan süreç, onun içeriğini Tasnif Dışı bir dosyaya kopyalarsa bilgi aşağı sızmış olur. Yukarı yazmak ise gizliliği bozmaz: Gizli bilgi Çok Gizli bir dosyaya geçerse daha sıkı korunur. Bu tür yazma genellikle “kör” bir eklemedir; süreç yazdığı dosyayı okuyamaz.

Çok Gizli (4)nesneGizli (3)nesneSüreçHizmete Özel (2)nesneTasnif Dışı (1)nesneoku ✗
Şekil 13.22: Yukarı okuma yok: Gizli düzeydeki süreç Çok Gizli nesneyi okuyamaz.
Çok Gizli (4)nesneGizli (3)nesneSüreçHizmete Özel (2)nesneTasnif Dışı (1)nesneyaz ✗Truva atı Gizli süreç içinde çalışsa bile bilgiyi aşağı yazamaz
Şekil 13.23: Aşağı yazma yok: süreç içinde çalışan bir Truva atı bile bilgiyi Tasnif Dışı düzeye yazamaz.
Örnek 13.9

Gizli (3) düzeyde çalışan bir süreç dört düzeydeki nesnelere okuma ve yazma isteği yapıyor. BLP hangilerine izin verir?

  1. Okuma. Nesne düzeyi ≤ 3 olmalıdır. Çok Gizli (4): ret. Gizli, Hizmete Özel, Tasnif Dışı: izin.
  2. Yazma. Nesne düzeyi ≥ 3 olmalıdır. Çok Gizli ve Gizli: izin. Hizmete Özel ve Tasnif Dışı: ret.

Süreç kendi düzeyinde hem okur hem yazar. Aşağıyı yalnız okur, yukarıya yalnız yazar.

BLP'nin asıl kazancı, kuralların kullanıcının iyi niyetine bağlı olmamasıdır. Gizli yetkili bir kullanıcı, içinde bir Truva atı gizlenmiş bir program çalıştırsın. Program kullanıcının haklarıyla çalışır ve Gizli belgeleri okuyabilir. DAC düzeninde program okuduğunu herkese açık bir dosyaya yazabilirdi. BLP'de ise bu yazma aşağı yazma olduğu için sistem reddeder. Kural, programın ne yapmaya çalıştığından bağımsız olarak işler.

13.4.2Biba modeli

BLP yalnız gizliliği korur; bütünlük hakkında hiçbir şey söylemez. Tasnif Dışı bir süreç Çok Gizli bir dosyaya yazabilir ve onu bozabilir. Biba 1977'de bütünlüğü koruyan bir model önerdi. Biba, BLP'nin aynasıdır: düzeyler bu kez gizliliği değil güvenilirliği gösterir. Sunumdaki örnekte düzeyler Yüksek (sistem), Orta (kullanıcı) ve Düşük (İnternet)'tir.

Tanım 13.14

Biba modelinde her süreç ve nesne bir bütünlük düzeyi taşır. Model iki kural koyar:

  • Basit bütünlük özelliği: k düzeyindeki bir süreç yalnız düzeyi k'ye eşit ya da k'den büyük nesneleri okuyabilir (aşağı okuma yok).
  • * bütünlük özelliği: k düzeyindeki bir süreç yalnız düzeyi k'ye eşit ya da k'den küçük nesnelere yazabilir (yukarı yazma yok).

Yukarı yazma yasağının anlamı açıktır: kullanıcı süreçleri sistem dosyalarını değiştiremez. Aşağı okuma yasağı daha incedir. İnternetten gelen güvenilmeyen bir veriyi okuyup ona göre davranan bir süreç “kirlenir”. Kötü niyetli bir girdi sürecin davranışını değiştirebilir ve süreç sonra bu davranışla daha güvenilir nesnelere yazabilir. Biba bunu kaynağında engeller.

Yüksek (sistem) (3)nesneOrta (kullanıcı) (2)nesneDüşük (İnternet) (1)nesneSüreçyaz ✗Düşük bütünlüklü tarayıcı süreci kullanıcı dosyalarına yazamaz
Şekil 13.24: Biba'da yukarı yazma yok: Düşük bütünlüklü tarayıcı süreci Orta düzeydeki kullanıcı dosyalarına yazamaz.

Biba'nın gerçek bir uygulaması Windows'un zorunlu bütünlük denetimidir (Mandatory Integrity Control, MIC). Windows'ta süreçler ve nesneler Düşük, Orta, Yüksek ve Sistem bütünlük düzeylerinden birini taşır. Sıradan uygulamalar Orta düzeyde çalışır. Tarayıcıların sekme süreçleri ise Düşük düzeyde çalışır. Bir web sayfasındaki istismar tarayıcı sürecini ele geçirse bile, kullanıcının Orta düzeydeki belgelerine yazamaz. Bu, yukarı yazma yasağının ta kendisidir.

13.4.3İki modelin karşılaştırılması

İki model aynı yapıyı ters yönde kullanır (Tablo 13.12).

Tablo 13.12: Bell-LaPadula ve Biba.
Bell-LaPadula (1973)Biba (1977)
KorurGizlilikBütünlük
OkumaAşağı serbest, yukarı yokYukarı serbest, aşağı yok
YazmaYukarı serbest, aşağı yokAşağı serbest, yukarı yok
EngellenenBilginin aşağı sızmasıKirli verinin yukarı bulaşması
BugünSELinux MLS, askerî sistemlerWindows MIC, FreeBSD ve Linux bütünlük politikaları
Bell-LaPadula (gizlilik)Çok GizlisüreçHizmete ÖzelokurokuyamazyazaryazamazBiba (bütünlük)YükseksüreçDüşükokurokuyamazyazaryazamaz
Şekil 13.25: İki modelde sürecin okuyup yazabildiği yönler. Okları ezberlemek yerine her modelin neyi engellediği akılda tutulur.
Örnek 13.10

Bir süreç Orta düzeyde. Yüksek'i okumak, Yüksek'e yazmak, Düşük'ü okumak ve Düşük'e yazmak isteklerine iki model ne der? İkisi birlikte uygulanırsa süreç neye erişebilir?

Tablo 13.13: Orta düzeydeki sürecin dört isteği. Kararlar Python ile doğrulandı.
İstekBLP (gizlilik)Biba (bütünlük)
Yüksek'i okumak (yukarı okuma)retizin
Yüksek'e yazmak (yukarı yazma)izinret
Düşük'ü okumak (aşağı okuma)izinret
Düşük'e yazmak (aşağı yazma)retizin

Her satırda modellerden biri reddeder. İki model birlikte uygulanırsa süreç yalnız kendi düzeyindeki nesneleri okuyup yazabilir. Biri gizliliği, öteki bütünlüğü korur ve hedefleri çatışır.

Adlandırmalar karıştırılmaya çok yatkındır. BLP'de basit güvenlik özelliği yukarı okumayı, * özelliği aşağı yazmayı yasaklar. Biba'da basit bütünlük özelliği aşağı okumayı, * bütünlük özelliği yukarı yazmayı yasaklar. İki modelde de “basit” sözcüğü okuma kuralını, yıldız da yazma kuralını gösterir.

Sık yapılan hata

BLP kurallarını “yukarı yazma yok” diye hatırlamak. Gizlilikte tehlike bilginin aşağı akmasıdır; yasaklanan yazma da aşağı doğru olandır. Kuralı çıkarmanın yolu şudur: önce modelin neyi korumak istediği sorulur, sonra bilginin hangi yönde akarsa bu hedefi bozacağı düşünülür.

İki modelin ortak bir sınırı vardır: yalnız açık okuma ve yazma işlemlerini denetlerler. Bilgi bir dosyaya yazılmadan da aktarılabilir. Bir sonraki konu bu yolları ele alır.

13.4.4Gizli kanallar ve steganografi

Lampson 1973'te bir soru sordu: bir program, verdiği hizmet sırasında işlediği gizli bilgiyi dışarı sızdırmasın diye tam olarak hapsedilebilir mi? Buna hapsetme problemi (confinement problem) denir. Senaryo şöyledir: bir istemci, gizli verisini işlemesi için bir sunucuya verir. Sunucu kötü niyetlidir ve veriyi dışarıdaki bir işbirlikçiye aktarmak ister. İşletim sistemi sunucuyu hapseder: dosya yazamaz, ağa bağlanamaz, işbirlikçiyle ileti alışverişi yapamaz. Lampson'ın cevabı olumsuzdur.

Tanım 13.15

Gizli kanal (covert channel), sistem tasarımcısının iletişim için öngörmediği ve güvenlik politikasını atlayan bir bilgi aktarma yoludur.

İstemcihapsedilmişSunucugizli veri işlerİşbirlikçigizli veriaçık kanal ✗gizli kanal ✓Steganografi181…1114…073…1209…190…037…1son bit = gizli ileti
Şekil 13.26: Hapsedilmiş sunucunun açık kanalı kapalıdır, ama işbirlikçiye gizli bir kanaldan veri sızdırabilir. Sağda steganografi: piksellerin son bitlerinde gizlenen ileti.

Paylaşılan her kaynak bir gizli kanal olabilir. Kanallar üç türe ayrılır.

Depolama kanalı
Paylaşılan bir durumun değişmesiyle bilgi aktarılır: bir dosyanın var olup olmaması, kilitli ya da açık olması, diskin doluluk oranı.
Zamanlama kanalı
Olayların zamanlamasıyla bilgi aktarılır. Sunucu CPU'yu yoğun kullanırsa 1, boşta kalırsa 0 gönderir. İşbirlikçi kendi işinin ne kadar yavaşladığını ölçerek bitleri okur. Önbellek gecikmesi de böyle bir kanaldır.
Kaynak kanalı
Paylaşılan bir kaynağın kullanım miktarıyla bilgi aktarılır: sayfa hatası oranı, ağ trafiğinin hacmi.

Bütün gizli kanalları kapatmak pratikte imkânsızdır, çünkü süreçlerin paylaştığı her kaynağın durumunu öteki süreçler gözleyebilir. Yapılabilecek olan kanalların bant genişliğini, yani saniyede aktarabildikleri bit sayısını düşürmektir. Gürültü eklemek, kaynakları düzeylere göre ayırmak ve saatlerin çözünürlüğünü azaltmak bu yöntemlerdendir.

Gizli kanalın yakın bir akrabası steganografidir: bilgiyi şifrelemek yerine varlığını gizlemek. Bir renkli görüntüde her pikselin kırmızı, yeşil ve mavi bileşenleri sekizer bittir. Her bileşenin en düşük anlamlı bitini değiştirmek rengi en fazla 1/256 oranında değiştirir. Göz bu farkı göremez. Şekil 13.26'daki altı değerin son bitleri sırayla 1, 0, 1, 1, 0, 1'dir. Kanal başına bir bitle 1920 × 1080'lik bir fotoğraf 777.600 bayt saklayabilir. Tanenbaum'un bilinen örneğinde üç zebralı bir fotoğrafın içine beş Shakespeare oyunu gizlenir; görüntü gözle hiç değişmez.

13.4.5Dosya kilidiyle gizli kanal

Somut bir depolama kanalı kuralım. Sunucu ve işbirlikçi önceden anlaşır: her zaman aralığında F dosyası kilitliyse 1, serbestse 0 gönderilmiş sayılır. Sunucu bir bit göndermek için F'yi kilitler ya da bırakır. İşbirlikçi aynı aralıkta F'yi kilitlemeyi dener. Deneme başarısız olursa dosya kilitlidir ve bit 1'dir; başarılı olursa bit 0'dır. Bu düzende ne okuma ne yazma vardır; F'nin içeriği hiç değişmez. BLP'nin denetlediği hiçbir işlem yapılmaz, ama bilgi akar.

SunucuDosya Fİşbirlikçit1kilitlekilitli1t2açserbest0t3kilitlekilitli1t4kilitlekilitli1t5açserbest0t6açserbest0t7kilitlekilitli1t8açserbest0Alınan bitler: 10110010
Şekil 13.27: Sekiz aralıkta bir bayt: işbirlikçi kilit denemelerinden 10110010 dizisini okur.

Şekil 13.27'deki zaman çizelgesinde sunucu sekiz aralıkta F'yi kilitle, aç, kilitle, kilitle, aç, aç, kilitle, aç sırasıyla değiştirir. İşbirlikçi 10110010 dizisini, yani 0xB2 = 178 değerini alır. Aralık 10 ms ise saniyede 100 aralık, dolayısıyla yaklaşık 100 bit/s'lik bir kanal elde edilir. 256 bitlik bir şifreleme anahtarı bu hızla 2,56 saniyede sızar.

Örnek 13.11

Sunucu sir = 'K' değerini en yüksek bitten başlayarak gönderiyor:

for (int i = 7; i >= 0; i--) {
    if ((sir >> i) & 1) kilitle(F);
    else                birak(F);
    bekle(10);                      /* ms */
}
  1. 'K'nin ASCII kodu 0x4B'dir; ikili gösterimi 01001011.
  2. i = 7'den 0'a bitler 0, 1, 0, 0, 1, 0, 1, 1'dir. Sunucu sırayla bırak, kilitle, bırak, bırak, kilitle, bırak, kilitle, kilitle yapar.
  3. İşbirlikçi her aralıkta bit = kilitlemeyi_dene(F) ? 0 : 1 hesaplar ve 80 ms sonunda 01001011 = 0x4B = 'K' değerini bulur.

Kanalı bulan bir yönetici aralığı uzatabilir ya da kilit durumuna rastgele gecikmeler ekleyebilir. Bu önlemler kanalın hızını düşürür, ama sıfırlamaz.

13.5Kimlik doğrulama

Koruma matrisinin bütün kararları, sürecin hangi kullanıcıya ait olduğu bilgisine dayanır. Bu bilgi sistem açılırken kullanıcının kendini tanıtmasıyla elde edilir. Kimlik doğrulama zayıfsa en iyi erişim denetimi de işe yaramaz: saldırgan meşru bir kullanıcının kimliğiyle içeri girer ve onun bütün haklarını kullanır.

13.5.1Kimlik doğrulama etkenleri

Tanım 13.16

Kimlik doğrulama (authentication), bir kullanıcının iddia ettiği kişi olduğunu doğrulamaktır. Hangi işlemlere izin verileceğine karar vermek ise ayrı bir adımdır ve yetkilendirme (authorization) diye anılır.

Kimlik doğrulama dört tür kanıta, yani etkene dayanabilir.

Bilinen bir şey
Parola, PIN, güvenlik sorusu. Ucuzdur ve her yerde kullanılabilir. Ama çalınabilir, tahmin edilebilir ve kullanıcılar aynı parolayı birçok sitede yeniden kullanır.
Elde tutulan bir şey
Telefon, akıllı kart, FIDO2 güvenlik anahtarı, TOTP üreteci. Fiziksel olarak çalınabilir, ama uzaktan kopyalanamaz.
Kişinin kendisi
Parmak izi, yüz, iris. Kullanımı kolaydır, ama değiştirilemez: sızarsa kalıcı olarak “yanar”.
Bulunulan yer ya da davranış
Konum, IP adresi, yazım ritmi, aygıt parmak izi. Genellikle tek başına değil, ek bir risk sinyali olarak kullanılır.

Çok etkenli kimlik doğrulama (multi-factor authentication, MFA), farklı kategorilerden en az iki etkenin birlikte istenmesidir. Kategori koşulu önemlidir. “Parola + güvenlik sorusu” MFA değildir, çünkü ikisi de bilinen bir şeydir ve aynı oltalama sayfası ikisini birden toplayabilir. MFA, çalınan parolalara karşı tek başına en etkili önlemdir.

Eski sistemlerde bir tür soru-yanıt (challenge-response) doğrulaması kullanılırdı. Kullanıcıya kayıt sırasında sorular sorulur, girişte bunlardan biri rastgele seçilirdi. Tipik sorular annenin kızlık soyadı ya da ilk evcil hayvanın adıydı. Bu yanıtların çoğu bugün sosyal medyadan kolayca bulunabildiği için yöntem zayıf kabul edilir. Soru-yanıt fikrinin güçlü biçimi ise kriptografiktir: sunucu rastgele bir sayı gönderir, kullanıcının aygıtı onu gizli bir anahtarla işler. FIDO2 bu fikri kullanır.

13.5.2Parola saklama: tuz ve yavaş özet

Parolalar hiçbir zaman açık hâlde saklanmaz. Saklansaydı parola dosyasını ele geçiren bir saldırgan, ya da dosyayı okuyabilen bir yönetici, bütün parolaları anında öğrenirdi. Kullanıcılar aynı parolayı başka yerlerde de kullandığı için zarar tek sistemle sınırlı kalmazdı. Sistem bunun yerine parolanın özetini saklar. Girişte kullanıcının yazdığı parolanın özeti hesaplanır ve saklananla karşılaştırılır.

Ancak düz bir özet yeterli değildir (Şekil 13.28). İnsanlar sık sık aynı parolaları seçer. Aynı parola aynı özeti verdiği için, özet dosyasına bakan saldırgan hangi kullanıcıların aynı parolayı seçtiğini hemen görür. Daha kötüsü, saldırgan milyonlarca yaygın parolanın özetini önceden bir kez hesaplayıp bir tabloya koyabilir. Bu tür tablolara gökkuşağı tablosu (rainbow table) denir. Sızan dosyadaki her özet bu tabloda aranır ve tek seferde binlerce parola kırılır.

ParolaTuz (salt)Yavaş özet Hali7Gx!veli7Gx!cankQ4zAynı parola → aynıözet olurdu: saldırgantekrarı görür, öncedenhesaplanmış tabloyla kırar
Şekil 13.28: Tuzsuz özette ali ile veli'nin parolası aynı olduğu için özetleri de aynıdır; saldırgan tekrarı görür.
Tanım 13.17

Tuz (salt), her kullanıcı için ayrı üretilen ve özetten önce parolaya eklenen rastgele bir değerdir. Tuz gizli değildir; özetin yanında açıkça saklanır.

Tuzun etkisi basittir: aynı parola artık farklı bir girdidir. ali ile veli'nin parolası aynı olsa da tuzları farklı olduğu için özetleri tamamen farklıdır. Önceden hesaplanmış tablolar da işe yaramaz, çünkü her olası tuz için ayrı bir tablo gerekir. 1970'lerin UNIX'i bile 2 karakterlik, yani 12 bitlik bir tuz kullanırdı. Bu, her parolanın 4096 farklı biçimde saklanabileceği ve tablo boyunun 4096 kat büyüyeceği anlamına geliyordu.

Tuz tek başına yetmez. SHA-256 gibi genel amaçlı özet fonksiyonları hızlı olsun diye tasarlanmıştır. Bugünkü bir ekran kartı saniyede milyarlarca SHA-256 hesaplayabilir. Parola saklamada istenen tam tersidir: her deneme pahalı olmalıdır. Bu yüzden parolalar kasıtlı olarak yavaş ve bellek yoğun fonksiyonlarla özetlenir. Güncel öneri Argon2id'dir (RFC 9106); scrypt ve bcrypt de kullanılır. Tek bir doğrulama birkaç milisaniye sürer ve kullanıcı bunu fark etmez. Milyarlarca deneme ise yıllar alır.

# Kayıt / parola değiştirme
salt = os.urandom(16)
h = argon2(password, salt)
store(user, salt, h)

# Giriş denemesi
salt, h = lookup(user)
g = argon2(attempt, salt)
if constant_eq(g, h): ok()

Sunumdaki sözde kod iki işlemi gösterir. Kayıt ya da parola değiştirmede 16 baytlık rastgele bir tuz üretilir. Parola bu tuzla Argon2'den geçirilir ve kullanıcı adı, tuz ve özet birlikte saklanır. Girişte kullanıcının tuzu ve özeti bulunur, girilen deneme aynı tuzla özetlenir ve iki özet karşılaştırılır.

Karşılaştırmanın constant_eq ile yapılması bir ayrıntı değildir. Sıradan bir karşılaştırma ilk farklı baytta durur. Saldırgan yanıt süresini çok hassas ölçebiliyorsa, ilk kaç baytın doğru olduğunu süreden çıkarabilir. Sabit zamanlı karşılaştırma her zaman bütün baytları karşılaştırır ve bu zamanlama sızıntısını önler.

ParolaTuz (salt)Yavaş özet Hali7Gx!a3f1+b91c4e…veli7Gx!9b2e+2f87aa…cankQ4z5d7c+d013f5…Depolanan: tuz + H.Argon2 kasten yavaşve bellek-yoğun: GPU/ASICile kaba kuvvet pahalı
Şekil 13.29: Her kullanıcının ayrı tuzu vardır; aynı parola farklı özetler verir. Depolanan değer tuz ve yavaş özettir.
Sık yapılan hata

Tuzun gizli tutulması gerektiğini ya da tuz sayesinde zayıf parolaların güvenli hâle geldiğini düşünmek. Tuz yalnız toplu saldırıyı ve önceden hesaplamayı engeller. Saldırgan tek bir kullanıcıyı hedeflerse o kullanıcının tuzunu bilir ve sözlükteki parolaları tek tek dener. Zayıf parolaya karşı yavaş özet ve parolanın uzunluğu işe yarar. Bir sızıntıdan sonra da parolalar her durumda sıfırlanmalıdır.

13.5.3Kaba kuvvet süresi

Tuzun ve yavaşlığın ayrı ayrı katkısını sayılarla görmek öğreticidir.

Örnek 13.12

Parolalar 8 küçük harften oluşuyor (26 harfli alfabe). Saldırgan sızan veritabanındaki tek bir kullanıcının özetini kırmak istiyor. En kötü durumda ne kadar sürer?

  1. Olası parola sayısı. Her konum için 26 seçenek vardır: 268 = 208.827.064.576 ≈ 2,09 × 1011.
  2. Düz SHA-256. Saniyede 1010 deneme yapılırsa: 2,09 × 1011 / 1010 ≈ 21 saniye.
  3. Argon2id. Her deneme pahalı olduğu için saniyede yalnız 104 deneme yapılabilsin: 2,09 × 1011 / 104 ≈ 2,09 × 107 saniye ≈ 242 gün. Yavaş özet her denemeyi 106 kat pahalılaştırmıştır.
  4. Daha uzun parola. 10 karakter ve 62 simge (büyük, küçük harf ve rakam) ile uzay 6210 ≈ 8,4 × 1017 olur. Düz SHA-256'da bile yaklaşık 2,66 yıl, Argon2id ile yaklaşık 2,66 milyon yıl sürer.

Bütün değerler Python ile hesaplandı.

Bu hesapta tuz nerede? Tek bir kullanıcının süresini tuz değiştirmez. Tuzun etkisi, saldırgan bütün kullanıcıları kırmak istediğinde ortaya çıkar. Tuzsuz düzende saldırgan her adayın özetini bir kez hesaplar ve bir milyon kullanıcının özetiyle birden karşılaştırır: iş, tek kullanıcınınkiyle aynıdır. Tuzlu düzende her kullanıcı için baştan başlamak zorundadır. Bir milyon kullanıcı ve düz SHA-256 ile 21 saniyelik iş 106 × 21 saniyeye, yani yaklaşık 242 güne çıkar. Tuz işi kullanıcı sayısıyla çarpar; yavaşlık her denemenin fiyatını artırır. İkisi birbirinin yerini tutmaz.

13.5.4MFA ve TOTP

Parolanın yanına eklenen en yaygın ikinci etken telefondur. Telefon, ya sunucudan gelen bir kodu alır ya da kodu kendisi üretir (Şekil 13.30).

Sunucupaylaşılan gizli KUygulamaaynı gizli KTOTP = HMAC(K, zaman / 30sn)KsaatHMAC739 412her 30 sn’de yenilenirKod ağda gizli K’yi taşımaz; yeniden kullanılamaz (yalnız o 30 sn geçerli)
Şekil 13.30: TOTP: sunucu ve uygulama aynı gizli K'yı ve aynı saati bilir; kod HMAC(K, zaman / 30 s)'den türetilir.
SMS kodu
Yaygındır ama zayıftır. Saldırgan operatörü kandırıp numarayı kendi SIM kartına taşıyabilir (SIM takası) ya da telefon ağının SS7 protokolündeki açıklarla iletileri yönlendirebilir. Yine de hiç ikinci etken olmamasından iyidir.
TOTP üreteci uygulaması
Zaman tabanlı tek kullanımlık parola (time-based one-time password, TOTP, RFC 6238). Kayıt sırasında sunucu ile uygulama, çoğunlukla bir QR kod aracılığıyla, gizli bir anahtar paylaşır. Uygulama bu anahtar ve saatten her 30 saniyede yeni bir kod üretir. Çevrimdışı çalışır. Ama oltalamaya açıktır: kullanıcı sahte bir siteye kodu da yazabilir.
Anlık bildirim onayı
Kullanıcı telefona gelen giriş onayı bildirimine dokunur. Kolaydır, ama onay yorgunluğu saldırısına açıktır: saldırgan art arda onlarca istek gönderir ve kullanıcı sonunda bıkıp birini onaylar. Bu yüzden ekrandaki bir sayıyı telefona yazdıran numara eşleştirme eklenir.

TOTP kodunun ağda gizli anahtarı taşımadığına dikkat edilmelidir. Kod, anahtarın ve zamanın tek yönlü bir fonksiyonudur. Saldırgan bir kodu görse bile ondan anahtarı çıkaramaz. Kod da yalnız kendi 30 saniyelik penceresinde geçerlidir.

13.5.5Kod izleme: TOTP kodu üretimi

Telefon ile sunucunun aynı kodu nasıl ürettiği sunumdaki C fonksiyonunda görülür. İzlemede RFC 6238'in test anahtarı kullanılır: ASCII “12345678901234567890” dizgisinin 20 baytı.

uint32_t totp(uint8_t *K, uint64_t t) {
    uint64_t T = t / 30;    /* 30 s */
    uint8_t h[20];
    hmac_sha1(K, T, h);
    int o = h[19] & 0x0F;   /* ofset */
    uint32_t v = (h[o] & 0x7F) << 24
               | h[o+1] << 16
               | h[o+2] << 8
               | h[o+3];
    return v % 1000000;     /* 6 hane */
}

Fonksiyon dört adımda çalışır.

  1. Zaman adımı. Unix zamanı t (1970'ten bu yana geçen saniye) 30'a bölünür: T = t / 30. Tamsayı bölmesi olduğu için aynı 30 saniyelik penceredeki her an aynı T'yi verir. 0–29 saniye T = 0'a, 30–59 saniye T = 1'e, 60–89 saniye T = 2'ye düşer. t = 59 için T = 1'dir.
  2. HMAC. T, 8 baytlık büyük uçlu bir sayı olarak K ile birlikte HMAC-SHA1'den geçirilir. Sonuç 20 baytlık bir özettir: 75 a4 8a 19 d4 cb e1 00 64 4e 8a c1 39 7e ea 74 7a 2d 33 ab. K'yı bilmeyen biri bu değeri üretemez.
  3. Dinamik kesme. 20 bayttan 4'ünü seçmek gerekir. Seçimin yerini özetin kendisi belirler: son baytın alt yarısı ofsettir. h[19] = 0xab'dir; 0xab & 0x0F = 0xb = 11. Dolayısıyla o = 11.
  4. Kod. h[11] … h[14] baytları, yani c1 39 7e ea, 32 bitlik bir sayıya birleştirilir. İlk baytın en üst biti & 0x7F ile silinir (0xc1 → 0x41). Bunun nedeni, sayının işaretli yorumlandığı sistemlerde negatif çıkmasını önlemektir. v = 0x41397eea = 1094287082'dir. Son altı hane v mod 1.000.000 = 287082 olur.
750a418a2193d44cb5e160076484e98a10c11139127e13ea1474157a162d173318ab19h[11..14] = c1 39 7e eaen üst bit silinir → v = 1094287082
Şekil 13.31: h[19] = 0xab ofseti 11 seçer; h[11..14] = c1 39 7e ea, üst bit silinince v = 1094287082.

Telefon 287082'yi gösterir; sunucu aynı hesabı yapıp kullanıcının yazdığı değerle karşılaştırır. 30 saniye sonra durum tamamen değişir (Tablo 13.14). t = 75'te T = 2 olur. Tek bitlik farklı bir T, tamamen farklı bir özet verir. Bu kez son bayt 0x44'tür, ofset 4'tür ve kod 359152 olur.

Tablo 13.14: İki zaman anında TOTP hesabı. Değerler Python'un hmac kütüphanesiyle yeniden hesaplandı; 8 haneli sonuç (94287082) RFC 6238'in test vektörüyle aynıdır.
tTh[19]oh[o..o+3]vKod
5910xab11c1 39 7e ea1094287082287082
7520x44408 2f ef 30137359152359152

Telefonun saati sunucununkinden birkaç saniye sapabilir. Sunucular bu yüzden genellikle bir önceki ve bir sonraki adımın kodlarını da kabul eder: T − 1, T ve T + 1. Bu, kodun yaklaşık 90 saniyelik bir pencerede geçerli olması demektir. Rastgele tahminle doğru kodu bulma olasılığı her denemede 3 / 106'dır. Sunucu deneme sayısını sınırladığı sürece bu olasılık ihmal edilebilir.

Örnek 13.13

t = 1.700.000.000 anında T kaçtır? Aynı kod hangi aralıkta geçerlidir? Sunucu T − 1 … T + 1'i kabul ediyorsa, şu anda girilen bir kod hangi aralıkta üretilmiş olabilir?

  1. 1.700.000.000 / 30 = 56.666.666,67; tamsayı kısmı T = 56.666.666.
  2. Pencere T · 30 = 1.699.999.980'de başlar ve 30 saniye sürer: 1.699.999.980 … 1.700.000.009.
  3. T − 1'in başı 1.699.999.950, T + 1'in sonu 1.700.000.039'dur. Kabul edilen pencere 90 saniyedir.

13.5.6FIDO2, WebAuthn ve geçiş anahtarları

TOTP parolanın çalınmasına karşı güçlüdür, ama oltalamaya karşı zayıftır. Kullanıcı sahte bir giriş sayfasına hem parolasını hem de o anki kodu yazar. Saldırgan bu ikisini birkaç saniye içinde gerçek siteye iletir ve kod henüz geçerliyken içeri girer. Sorunun kökü, kullanıcının hangi siteye kod verdiğini denetleyen bir mekanizmanın olmamasıdır. FIDO2 ve onun web arayüzü WebAuthn bu açığı kapatır (Şekil 13.32).

TarayıcıGüvenlik anahtarıözel anahtar burada kalırSunucurastgele meydan okuma (challenge)kökene bağlı imzaimzalı yanıt (özel anahtarla)açık anahtarlaimzayı doğrularİmza sitenin kökenini içerir: sahte siteye verilen yanıt gerçek sitede geçersiz → oltalanamaz
Şekil 13.32: FIDO2: güvenlik anahtarı sunucunun rastgele sınamasını, sitenin kökenine bağlı olarak imzalar; sunucu imzayı açık anahtarla doğrular.

Düzen açık anahtarlı kriptografiye dayanır. Kullanıcı bir siteye kaydolurken aygıtı o site için yeni bir anahtar çifti üretir. Özel anahtar aygıtın güvenli donanımından, yani TPM'den, Secure Enclave'den ya da USB güvenlik anahtarından hiç çıkmaz. Sunucuya yalnız açık anahtar gönderilir. Girişte sunucu rastgele bir sınama (challenge) gönderir. Tarayıcı bu sınamaya bağlandığı sitenin kökenini (origin), yani protokol, alan adı ve kapı üçlüsünü ekler. Aygıt bu ikisini özel anahtarla imzalar ve sunucu imzayı saklı açık anahtarla doğrular.

Oltalamaya karşı direnç bu kökenden gelir. Kullanıcı ornek-giris.com gibi sahte bir siteye girerse tarayıcı imzaya o sahte kökeni koyar. Ayrıca aygıt, sahte site için kayıtlı bir anahtar bulamaz. Saldırgan yanıtı gerçek siteye iletse bile köken eşleşmediği için imza geçersizdir. Kullanıcının dikkatsizliği sonucu değiştirmez; denetimi tarayıcı yapar.

Düzenin öteki kazançları da önemlidir. Sunucu yalnız açık anahtarları saklar; veritabanı sızsa bile bu anahtarlarla kimse giriş yapamaz. Paylaşılan bir sır yoktur ve aynı anahtar başka sitede yeniden kullanılmaz, çünkü her siteye ayrı çift üretilir. Geçiş anahtarları (passkeys), FIDO2 kimlik bilgilerinin kullanıcının aygıtları arasında güvenli biçimde eşitlenebilen biçimidir. Parolaların yerini almak üzere tasarlanmıştır.

13.5.7Biyometrik kimlik doğrulama

Biyometri, kişinin fiziksel ya da davranışsal bir özelliğini ölçer: parmak izi, yüz, iris, ses. İlk bakışta ideal görünür: unutulmaz, kaybolmaz, devredilemez. Ancak her ölçüm biraz farklıdır ve sistem ölçülen değeri kayıtlı şablonla bir eşik değerine göre karşılaştırır. Bu yüzden iki tür hata vardır (Tablo 13.15).

Tablo 13.15: Biyometrik sistemlerin ölçütleri.
ÖlçütAçıklama
Yanlış kabul oranı (FAR)Yabancıyı kabul etme oranı: güvenlik riski
Yanlış ret oranı (FRR)Gerçek kullanıcıyı reddetme oranı: kullanılabilirlik sorunu
Canlılık testiFotoğraf, maske ya da parmak kalıbına karşı denetim
İptal edilemezlikParmak izi sızarsa değiştirilemez; parola değiştirilebilir

FAR ile FRR birbirine bağlıdır. Eşik sıkılaştırılırsa yabancılar daha az kabul edilir, ama gerçek kullanıcı da daha sık reddedilir. Eşik gevşetilirse tersi olur. Küçük bir FAR bile büyük sayılarda önem kazanır. FAR 1/100.000 olan bir sistemde bin farklı yabancının denemesinden en az birinin kabul edilme olasılığı 1 − (1 − 10−5)1000 ≈ %1'dir.

Biyometrinin temel sınırı şudur: bir kimlik için iyidir, bir sır için kötüdür. Yüz ve parmak izi gizli değildir; insanlar her gün dokundukları yüzeylere parmak izi, sosyal medyaya fotoğraf bırakır. Bu yüzden doğru kullanım yerel kullanımdır. Biyometri, aygıtın içindeki güvenli donanımın kilidini açan bir etken olarak çalışır; örneğin Face ID Secure Enclave'deki anahtarlara erişimi açar. Ham şablon aygıttan hiç çıkmaz. Tek başına uzaktan kimlik doğrulama için uygun değildir ve genellikle elde tutulan bir aygıtla birleştirilir. Parmak uzunluğunu ölçen ilk aygıtlar bugün tarihseldir. Bugünkü sistemler parmak izi çizgilerinin ayrıntı noktalarını (minutiae), üç boyutlu yüz şeklini ve iris desenini kullanır. Donanım destekli canlılık testi de şarttır.

13.5.8Saldırganlar sisteme nasıl girer?

Kimlik doğrulamanın zayıf noktaları, saldırganların en sık kullandığı giriş yollarıdır (Tablo 13.16).

Tablo 13.16: Yaygın ilk erişim yolları ve önlemleri.
YolAçıklamaÖnlem
Oltalama (phishing)Sahte giriş sayfasıyla parola toplamaFIDO2, kullanıcı eğitimi
Kimlik bilgisi doldurmaSızan parolaları başka sitelerde denemeBenzersiz parola, MFA
Kaba kuvvet / sözlükZayıf parolayı tahmin etmeYavaş özet, hız sınırı, kilitleme
Yama yapılmamış açıkBilinen bir zafiyeti kullanmaHızlı yama yönetimi
Sosyal mühendislikYardım masasını kandırmaSüreç ve doğrulama
Varsayılan ya da zayıf kimlikadmin/admin, açık bırakılmış kapıSağlamlaştırma (hardening)

Gerçek bir saldırı nadiren tek bir adımdır; genellikle bir zincirdir (Şekil 13.33). Saldırgan önce oltalama ya da bir açıkla ilk erişimi elde eder. Bu erişim çoğunlukla sıradan bir kullanıcı hesabıdır. Ardından yerel bir açıkla ayrıcalık yükseltme yapar ve root olur. Sonra aynı ağdaki öteki makinelere yanal hareketle yayılır. Sonunda bir arka kapı ya da rootkit kurarak kalıcılık sağlar: makine yeniden başlatılsa da içeride kalır.

1 · İlk erişimoltalama, açık2 · Ayrıcalık yükseltmeyerel açık → root3 · Yanal hareketdiğer makineler4 · Kalıcılıkarka kapı, rootkitMFA ve FIDO2 · yama ve en az ayrıcalık · ağ bölütleme · EDR ve güvenli önyükleme: her halkada bir savunma
Şekil 13.33: Saldırı zinciri ve her halkadaki savunma: MFA ve FIDO2, yama ve en az ayrıcalık, ağ bölütleme, EDR ve güvenli önyükleme.

Zincir görüşü savunmanın da katmanlı olması gerektiğini bir kez daha gösterir. MFA ilk erişimi zorlaştırır. Yama ve en az ayrıcalık yükseltmeyi engeller. Ağ bölütlemesi yanal hareketi durdurur. Uç nokta izleme ve güvenli önyükleme kalıcılığı yakalar. Tek bir halkanın kopması bütün sistemin ele geçirilmesine yol açmamalıdır.

13.6Yazılım açıkları

Kimlik doğrulama ve erişim denetimi kusursuz olsa bile programlardaki hatalar saldırganlara yeni kapılar açar. Bir hata, programın tasarımcısının hiç öngörmediği bir şey yapmasına yol açıyorsa güvenlik açığına dönüşür. En tehlikelileri, saldırganın kendi seçtiği kodu çalıştırmasına izin veren bellek hatalarıdır. Bu kesim bunların en klasiğini, yığın tampon taşmasını, ona karşı geliştirilen savunmaları ve bir yarış durumu açığı olan TOCTOU'yu ele alır.

13.6.1Yığın tampon taşması

C'de bir fonksiyon çağrıldığında yığında onun için bir çerçeve açılır. Çerçevede fonksiyonun yerel değişkenleri, çağıranın kayıtlı çerçeve işaretçisi ve dönüş adresi bulunur. Dönüş adresi, fonksiyon bittiğinde işlemcinin yürütmeye devam edeceği yerdir. x86 ailesinde yığın yüksek adreslerden düşük adreslere doğru büyür. Bu yüzden önce çağrılan fonksiyonun dönüş adresi yığına konur, yerel diziler ondan daha düşük adreslerde durur.

Tanım 13.18

Tampon taşması (buffer overflow), bir tampona boyundan fazla veri yazılması ve fazla baytların bitişik belleğin üzerine taşmasıdır. Yığındaki bir tampon taşarsa en tehlikeli kurban dönüş adresidir.

/* küçük, kasıtlı olarak hatalı örnek */
void A(char *in) {
    char buffer[8];
    strcpy(buffer, in);   // sınır denetimi YOK
    return;
}
A(argv[1]);               // in: kullanıcı girdisi

Bu küçük ve kasıtlı olarak hatalı fonksiyon, kullanıcıdan gelen bir dizgiyi 8 baytlık bir diziye kopyalar. strcpy hedefin boyunu bilmez; kaynaktaki sonlandırıcı \0'a kadar kopyalamayı sürdürür. Girdi 7 karakter ya da daha kısa olduğu sürece sorun yoktur: sonlandırıcıyla birlikte en çok 8 bayt yazılır ve dizi taşmaz. Girdi daha uzunsa fazla baytlar dizinin üstündeki hücrelere yazılır. Dizi düşük adreste, dönüş adresi yüksek adreste durduğu ve kopyalama artan adres yönünde ilerlediği için taşma doğrudan dönüş adresine doğru gider (Şekil 13.34).

YÜKSEK adresDÜŞÜK adres (yığın aşağı büyür)argv[1] işaretçisidönüş adresiBOZULDU ✗çerçeve işaretçisibuffer[4..7]buffer[0..3]yazma yönü
Şekil 13.34: Yığın çerçevesi. Yazma yönü yukarı doğrudur; uzun bir girdi önce çerçeve işaretçisini, sonra dönüş adresini bozar.

Fonksiyon return ettiğinde işlemci yığındaki dönüş adresini okur ve oraya atlar. Adres rastgele baytlarla bozulmuşsa program büyük olasılıkla bir segmentasyon hatasıyla (SIGSEGV) çöker. Ama girdiyi seçen bir saldırgan, dönüş adresinin yerine kendi seçtiği bir adresi koyabilir. O zaman yürütme akışı saldırganın istediği yere gider. Klasik saldırıda bu adres, saldırganın aynı girdiyle tampona yerleştirdiği makine koduna işaret eder. Program setuid root ise ya da bir ağ hizmetiyse, saldırgan root haklarıyla bir kabuk elde eder. Aleph One'ın 1996'da yayımladığı “Smashing the Stack for Fun and Profit” makalesi bu tekniği ayrıntılı anlatarak bir saldırı kuşağının başlangıcı oldu.

Örnek 13.14

64 bitlik bir makinede char ad[8] dizisine strcpy ile “Giresun-Ordu-Samsun” kopyalanıyor. Kanarya ve dolgu yoktur: çerçevede 8 baytlık ad, 8 baytlık kayıtlı çerçeve işaretçisi (rbp) ve 8 baytlık dönüş adresi vardır. Kaç bayt yazılır, kaçı taşar, dönüş adresinin kaç baytı bozulur?

  1. Dizgi 19 karakterdir. strcpy sonlandırıcıyla birlikte 19 + 1 = 20 bayt yazar.
  2. İlk 8 bayt “Giresun-” diziye tam sığar. Henüz \0 gelmediği için kopyalama sürer.
  3. Sonraki 8 bayt “Ordu-Sam” kayıtlı rbp'nin üzerine yazılır.
  4. Kalan “sun” ve \0 dönüş adresinin ilk dört baytına yazılır: 73 75 6e 00. Makine küçük uçlu olduğu için bu baytlar adresin düşük dört baytıdır; adres …006e7573 olur.

Toplam 20 bayttan 20 − 8 = 12'si taşmıştır; dönüş adresinin 4 baytı bozulmuştur. Fonksiyon dönerken işlemci bu geçersiz adrese atlar ve program çöker. Değerler Python ile doğrulandı.

Düzeltme, kopyalamayı hedefin boyuyla sınırlamaktır. snprintf en çok sizeof buffer − 1 karakter kopyalar ve her zaman bir sonlandırıcı ekler.

void A(const char *in) {
    char buffer[8];
    snprintf(buffer, sizeof buffer, "%s", in);   /* en çok 7 karakter + '\0' */
}
Sık yapılan hata

Sonlandırıcıyı saymamak. 8 baytlık bir diziye 8 karakterlik bir dizgi sığmaz: strcpy 9 bayt yazar ve bir bayt taşar. Taşan tek bir bayt bile, örneğin kayıtlı çerçeve işaretçisinin en düşük baytını sıfırlayarak, istismar edilebilir. Bu tür hatalara “birer fazla” (off-by-one) hatası denir.

13.6.2Tampon taşmasına karşı savunmalar

Tampon taşması kırk yılı aşkın bir süredir bilinir ve ona karşı birçok savunma katmanı geliştirilmiştir. Her savunma saldırının farklı bir adımını hedefler.

Yığın kanaryası
Derleyici, dönüş adresinin hemen altına süreç başında rastgele seçilen bir değer koyar. Fonksiyon dönmeden önce bu değerin bozulup bozulmadığına bakar. Dönüş adresine ulaşmak isteyen bir taşma önce kanaryayı ezmek zorundadır. Bozulma görülürse program durdurulur. GCC'de bu özellik yığın parçalama koruması (SSP) adıyla bilinir.
DEP / NX
Veri sayfaları sayfa tablosunda yürütülemez olarak işaretlenir (x86-64'teki NX biti). Yığına enjekte edilen kod, işlemci oraya atlasa bile çalışmaz; bir sayfa hatası oluşur. Bir sayfanın hem yazılabilir hem çalıştırılabilir olmaması kuralına W^X da denir.
ASLR
Adres alanı yerleşiminin rastgeleleştirilmesi (address space layout randomization): yığın, öbek ve kütüphaneler her çalıştırmada farklı adreslere yüklenir. Saldırgan hangi adrese atlayacağını bilemez. Programın kendisi de konumdan bağımsız (PIE) derlenirse onun adresi de rastgele olur. Linux'ta 64 bitlik süreçlerde kütüphane yerleşimi 28 bitlik bir rastgelelik taşır; yaklaşık 268 milyon olasılık.
CFI
Denetim akışı bütünlüğü (control-flow integrity): dolaylı atlamaların ve çağrıların yalnız derleyicinin önceden belirlediği geçerli hedeflere gitmesine izin verilir.
Gölge yığın
Dönüş adresinin bir kopyası, programın sıradan yazma komutlarıyla değiştiremeyeceği ayrı bir yığında tutulur. Dönüşte iki adres karşılaştırılır. Intel CET ve ARM GCS bunu donanımda sağlar. ARM'ın işaretçi doğrulama (PAC) ve dal hedefi belirleme (BTI) özellikleri ayrı ama benzer amaçlı korumalardır.
Bellek güvenli dil
Rust, Go, Java ve C# gibi dillerde dizi sınırları ve nesne ömürleri derleyici ya da çalışma zamanınca denetlenir. Tampon taşması bu dillerde baştan oluşamaz. En köklü çözüm budur.

Savunmalar geliştikçe saldırılar da değişti. NX, yığına enjekte edilen kodun çalışmasını engelleyince saldırganlar yeni kod getirmeyi bıraktı. Bunun yerine bellekte zaten var olan kodu kullanmaya başladılar. return-to-libc saldırısında dönüş adresi libc'deki system() fonksiyonuna yönlendirilir ve ona “/bin/sh” argümanı verilir. Daha genel biçimi dönüş yönelimli programlamadır (return-oriented programming, ROP). Saldırgan, programın ve kütüphanelerin içinde ret komutuyla biten küçük kod parçaları (gadget) bulur. Yığına bu parçaların adreslerini art arda yazar. Her parça birkaç komut çalıştırır ve ret ile bir sonrakine geçer. Yeterince parçayla istenen her hesap yapılabilir. Bu kodların hepsi zaten çalıştırılabilir sayfalarda durduğu için NX bu saldırıyı durduramaz. ASLR parçaların adreslerini gizler, CFI ve gölge yığın da dönüşlerin beklenmedik yerlere gitmesini engeller. Bu yüzden savunmalar birlikte kullanılır; tek başına hiçbiri yeterli değildir.

13.6.3Kod izleme: yığın kanaryası

Kanaryanın nasıl çalıştığını bayt bayt izleyelim. Aşağıdaki kodda kanarya satırlarını programcı değil derleyici ekler; gerçek derlenmiş kodda bu satırlar fonksiyonun giriş ve çıkış komutlarıdır.

/* kanarya satırlarını derleyici ekler */
void kopyala(const char *girdi) {
    long kanarya = __stack_chk_guard;
    char buf[8];
    strcpy(buf, girdi);
    if (kanarya != __stack_chk_guard)
        __stack_chk_fail();
}
/* girdi: "AAAAAAAABBBBBBBB" */

Fonksiyon “AAAAAAAABBBBBBBB” girdisiyle çağrılır: 16 karakter ve bir sonlandırıcı. buf ise 8 bayttır. Çerçevede düşük adresten yükseğe doğru buf, kanarya, kayıtlı rbp ve dönüş adresi bulunur. İzleme Tablo 13.17 adımlarıyla ilerler.

Tablo 13.17: kopyala("AAAAAAAABBBBBBBB") çağrısında çerçevenin durumu. Baytlar bellekteki sırayla (düşük adresten yükseğe) yazılmıştır. Değerler Python ile doğrulandı.
Adımbuf[8]kanaryakayıtlı rbpdönüş adresi
çağrı(belirsiz)(belirsiz)f0 c4 20 3a fd 7f 00 0096 11 40 00 00 00 00 00
giriş kodu(belirsiz)00 5f b8 d4 e2 71 3c 9aaynıaynı
ilk 8 baytA A A A A A A Aaynıaynıaynı
sonraki 8 baytA × 8B B B B B B B Baynıaynı
\0A × 8B × 800 c4 20 3a fd 7f 00 0096 11 40 00 00 00 00 00
çıkış denetimi0x4242424242424242 ≠ 0x9a3c71e2d4b85f00 → __stack_chk_fail()
  1. Çağrı. call komutu dönüş adresini (0x401196) yığına koyar. Fonksiyonun giriş kodu çağıranın çerçeve işaretçisini (0x7ffd3a20c4f0) kaydeder. Küçük uçlu düzende adresin en düşük baytı önce gelir: 0x401196, bellekte 96 11 40 00 … diye görünür.
  2. Kanarya. Derleyicinin eklediği giriş kodu, süreç başında rastgele seçilmiş __stack_chk_guard değerini buf ile kayıtlı rbp arasına koyar. Bu örnekte değer 0x9a3c71e2d4b85f00'dır. İlk baytının, yani bellekteki en düşük baytının 0x00 olması bilinçli bir seçimdir. Dizgi işlevleri bu baytta durduğu için kanarya bir dizgi okumasıyla sızdırılamaz ve strcpy ile aynen yazılamaz. Geri kalan 56 bit rastgeledir: 256 olasılık.
  3. İlk 8 bayt. strcpy “AAAAAAAA”yı buf'a yazar. Henüz bir sorun yoktur.
  4. Taşma. “BBBBBBBB” buf'ın dışına, kanaryanın üzerine yazılır. Kanarya artık 0x4242424242424242'dir (B'nin ASCII kodu 0x42).
  5. Sonlandırıcı. \0 kayıtlı rbp'nin ilk baytına yazılır: f0 → 00. Girdi biraz daha uzun olsaydı sıra dönüş adresine gelirdi. Ama dönüş adresine ulaşmanın tek yolu kanaryanın üzerinden geçmektir.
  6. Çıkış denetimi. Fonksiyon dönmeden önce çıkış kodu yığındaki kanaryayı süreç başındaki değerle karşılaştırır. İkisi farklıdır.
  7. Durdurma. __stack_chk_fail “*** stack smashing detected ***: terminated” iletisini yazar ve süreci SIGABRT ile sonlandırır. Bozulmuş çerçeveye hiç dönülmez.
dönüş adresi9611400000000000kayıtlı rbp00c4203afd7f0000kanaryaBBBBBBBBbuf[8]AAAAAAAAdüşük adres →strcpy yukarı doğru yazar ↑0x4242424242424242 ≠ 0x9a3c71e2d4b85f00
Şekil 13.35: Çıkış denetimi: yığındaki kanarya (B'ler) süreç başındaki değerle eşleşmiyor.

Kanaryanın kazancı, bir kod yürütme saldırısını bir çökmeye dönüştürmesidir. Bu hâlâ bir kayıptır, çünkü hizmet durur ve erişilebilirlik bozulur. Ama saldırgan kodunu çalıştıramaz. Kanaryanın sınırları da vardır. Saldırgan başka bir hatayla kanaryanın değerini okuyabilirse onu aynen geri yazabilir. Taşma dönüş adresi yerine bir işlev işaretçisini bozuyorsa kanarya hiç devreye girmez.

13.6.4Diğer bellek ve enjeksiyon hataları

Tampon taşması, geniş bir hata ailesinin yalnız bir üyesidir (Tablo 13.18).

Tablo 13.18: Bellek ve enjeksiyon hataları.
AçıkNeden tehlikeliÖnlem
Biçim dizgisiprintf(user): %x ile belleği okur, %n ile yazarprintf("%s", user)
Tamsayı taşmasılen = a + b sarması küçük ayırmaya yol açarDenetimli aritmetik, boyut tipleri
Serbest sonrası kullanımSerbest bırakılmış belleğe erişim (UAF)Sahiplik (Rust), akıllı işaretçi, karantina
Çifte serbest bırakmaAynı blok iki kez free edilir; öbek bozulurfree sonrası NULL, güçlendirilmiş ayırıcı
Sınır dışı okumaHeartbleed gibi bellek sızıntısıSınır denetimi, bulanıklaştırma
Komut/SQL enjeksiyonuGirdi koda ya da sorguya karışırParametreli sorgu, kaçış, izin listesi

Biçim dizgisi hatasında programcı kullanıcının girdisini doğrudan printf'e biçim dizgisi olarak verir. Kullanıcı girdiye %x yazarsa printf olmayan argümanları yığından okur. Böylece belleğin içeriği ekrana dökülür. %n ise o ana kadar yazılan karakter sayısını bir adrese yazar; saldırgan bununla belleği değiştirebilir. Tamsayı taşmasında iki uzunluğun toplamı 32 bitlik bir değişkeni aşar ve küçük bir sayıya sarar. Program bu küçük değerle bellek ayırır, sonra büyük veriyi bu alana kopyalar ve öbekte bir taşma oluşur.

Serbest sonrası kullanımda (use-after-free) program serbest bıraktığı bir bloğa eski işaretçi üzerinden erişmeyi sürdürür. Ayırıcı bu arada bloğu başka bir nesneye vermişse, saldırgan o nesnenin içeriğini denetleyerek programın eski nesneyi nasıl yorumlayacağını belirler. Tarayıcı açıklarının büyük bölümü bu türdendir. Sınır dışı okumanın ünlü örneği, 2014'te OpenSSL'de bulunan Heartbleed'dir. Sunucu, istemcinin bildirdiği uzunluğu denetlemeden o kadar baytı yanıta kopyalıyordu. Her istekte belleğinden 64 KiB'a kadar veri, içinde özel anahtarlar ve parolalar olabilecek biçimde sızıyordu.

Bu hataların ortak kökü, verinin kodla ya da denetim bilgisiyle karışması ve güvenilmeyen girdinin denetimsiz kullanılmasıdır. Biçim dizgisinde veri biçim komutu olarak yorumlanır. SQL enjeksiyonunda kullanıcının yazdığı tırnak işareti sorgunun yapısını değiştirir. Savunma da ortaktır: girdi doğrulanır, veri koddan ayrılır, bellek güvenli diller kullanılır. Programa rastgele bozuk girdiler veren bulanıklaştırma (fuzzing) araçları da hataları saldırganlardan önce bulur.

13.6.5TOCTOU yarış durumu

Bazı güvenlik açıkları bellek hatası değil, zamanlama hatasıdır. Bir program bir koşulu denetler ve bir süre sonra bu denetime dayanarak bir işlem yapar. İki an arasında koşul değişebiliyorsa program artık geçersiz bir bilgiye göre davranır.

Tanım 13.19

TOCTOU (time of check to time of use, kontrol zamanı ile kullanım zamanı) açığı bir yarış durumudur. Saldırgan, kaynağın denetlendiği an ile kullanıldığı an arasında kaynağı değiştirebilir.

/* TOCTOU: setuid root yardımcı */
if (access(path, W_OK) == 0) {   // KONTROL
    fd = open(path, O_WRONLY);     // KULLANIM
    write(fd, data, n);
}

Kod, setuid root bir yardımcı programın parçasıdır. Program, kendisini çalıştıran kullanıcının yazma izni olmayan bir dosyaya root haklarıyla yazmasını önlemek ister. Bunun için access çağrısını kullanır. access izni etkin kimliğe değil gerçek kimliğe göre denetler: “ali bu dosyaya yazabilir mi?” sorusunu yanıtlar. Cevap olumluysa program dosyayı open ile açar. open ise etkin kimliği, yani root'u kullanır.

Sorun, iki çağrının dosya adını ayrı ayrı çözmesidir (Şekil 13.36).

  1. Kontrol. /tmp/f sıradan, Ali'ye ait bir dosyadır. access izin olduğunu söyler.
  2. Pencere. Kontrol ile kullanım arasında küçük bir zaman aralığı vardır. Çizelgeleyici tam bu sırada süreci CPU'dan alabilir.
  3. Saldırı. Saldırgan bu aralıkta /tmp/f'yi siler ve yerine /etc/passwd'ye işaret eden bir sembolik bağ koyar: ln -sf /etc/passwd /tmp/f. Dosya adı aynıdır, ama hedef değişmiştir.
  4. Kullanım. open("/tmp/f") adı yeniden çözer ve bağı izleyerek /etc/passwd'yi root haklarıyla açar. write bu kritik dosyayı bozar.
Kurban (root)Saldırganaccess("/tmp/f") → izin var(CPU bırakıldı)ln -sf /etc/passwd /tmp/fopen("/tmp/f")→ artık /etc/passwd!write(): passwd bozuldupencere
Şekil 13.36: TOCTOU zaman çizelgesi: kontrol ile kullanım arasındaki pencerede saldırgan dosya adını sembolik bağla değiştirir.

Pencere çok kısa olabilir, ama saldırgan denemeyi binlerce kez tekrarlar. Çok çekirdekli bir makinede kendi sürecini ayrı bir çekirdekte sürekli bağ değiştirecek biçimde çalıştırarak şansını artırır. Bir kez tutturması yeterlidir.

Çözümün ilkesi, adı iki kez çözmemektir. Dosya bir kez açılır ve sonraki bütün denetimler aynı dosya tanımlayıcısı üzerinde yapılır. Tanımlayıcı açıldığı anda hangi dosyaya bağlandıysa ona bağlı kalır; adın sonradan değişmesi onu etkilemez. Ayrıca program, açmadan önce ayrıcalığını kullanıcının kimliğine düşürür. Böylece izin denetimini access değil, open'ın kendisi doğru kimlikle yapar. O_NOFOLLOW bayrağı ise son bileşen bir sembolik bağsa açmayı reddeder.

/* düzeltilmiş: ad bir kez çözülür, denetim aynı tanımlayıcı üzerinde yapılır */
uid_t ruid = getuid();
seteuid(ruid);                                /* önce ayrıcalık düşürülür */
int fd = open(path, O_WRONLY | O_NOFOLLOW);   /* izin denetimini çekirdek yapar */
if (fd >= 0) {
    struct stat st;
    if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode))
        write(fd, data, n);
    close(fd);
}

Güvenli bir dizinde çalışan programlar openat ailesini kullanarak yolu dizin tanımlayıcısına göre çözer; bu da yolun ara bileşenlerinin değiştirilmesini engeller.

Sık yapılan hata

Pencereyi küçültmeyi çözüm saymak. access ile open art arda yazıldığı için pencere mikrosaniyelerle ölçülür; ama küçük bir pencere yalnız saldırının deneme sayısını artırır. Çözüm pencereyi kapatmaktır: denetim ve kullanım aynı nesne üzerinde, tek bir ad çözümlemesiyle yapılmalıdır.

13.7İçeriden saldırılar

Saldırıların bir kısmı sistemi dışarıdan değil, içeriden gelir. Saldırgan sistemi geliştiren ya da işleten biridir: bir programcı, bir yönetici, bir yüklenici. Meşru erişimi olduğu için dış savunmaların hepsini zaten aşmıştır. Bu grubun üç klasik yöntemi vardır.

Mantık bombası (logic bomb)
Belirli bir koşulda tetiklenen zararlı koddur. Koşul bir tarih olabilir ya da programcının adının bordrodan silinmesi gibi bir olay. Çoğu zaman hoşnutsuz bir çalışan koyar: kod her gün çalışır, programcının hâlâ şirkette olup olmadığına bakar ve değilse dosyaları siler.
Arka kapı (back door)
Kimlik doğrulamayı atlayan gizli bir giriştir (Şekil 13.37). Arka kapılar tedarik zincirine de sokulabilir. 2024'te Linux dağıtımlarının kullandığı xz sıkıştırma kütüphanesinde bir arka kapı son anda fark edildi. Arka kapıyı yıllarca güven kazanmış bir katkıcı eklemişti ve SSH kimlik doğrulamasını etkiliyordu.
Giriş sahtekârlığı (login spoofing)
Saldırgan, gerçek giriş ekranına benzeyen bir program çalıştırır ve terminalin başından ayrılır. Gelen kullanıcı adını ve parolasını yazar. Program bunları kaydeder, “parola yanlış” iletisi gösterir ve gerçek giriş ekranına devreder. Kullanıcı ikinci denemede girer ve hiçbir şeyden kuşkulanmaz.
(a) Normal kodif (user_ok(name, pw)) grant_access();else deny();(b) Arka kapılı kodif (user_ok(name, pw) || eq(name, "zzz")) grant_access();else deny();“zzz” her zaman girer
Şekil 13.37: (a) Normal oturum açma kodu; (b) “zzz” kullanıcı adıyla her zaman giriş izni veren arka kapılı sürüm.

Giriş sahtekârlığına karşı güvenli dikkat dizisi (secure attention key) kullanılır. Windows'ta Ctrl+Alt+Del birleşimini hiçbir kullanıcı programı yakalayamaz; bu tuşlar her zaman doğrudan işletim sisteminin gerçek giriş ekranını çağırır. Kullanıcı giriş yapmadan önce bu tuşlara basmaya alıştırılırsa, ekranda sahte bir program çalışıyor olsa bile gerçek ekran öne gelir.

Arka kapılara karşı savunma kurumsal ve tekniktir. Kod incelemesinde her değişikliği en az bir başka kişi görür. Kritik değişiklikler için iki kişi onayı istenir. Yeniden üretilebilir derleme (reproducible builds) ise aynı kaynak koddan herkesin bayt bayt aynı ikili dosyayı elde etmesini sağlar. Böylece dağıtılan programın yayımlanan kaynaktan derlendiği bağımsız olarak doğrulanabilir. Ken Thompson'ın 1984'teki Turing Ödülü konuşması bu konunun sınırını gösterir. Thompson, kendini derlerken arka kapıyı yeniden ekleyen bir derleyicinin kaynak kodda hiçbir iz bırakmayacağını anlatır. Sonuç olarak her güven zinciri bir yerde, kendimiz yazmadığımız bir araca güvenmekle başlar.

13.8Kötü amaçlı yazılımlar

Kötü amaçlı yazılım (malware), sistem sahibinin isteği dışında çalışan programların genel adıdır. Bu programlar zarar vermek, veri çalmak ya da kaynak kullanmak için tasarlanır. Önceki kesimlerdeki açıklar, bu programların sisteme girmek için kullandığı kapılardır.

13.8.1Türler

Kötü amaçlı yazılımlar yayılma biçimlerine ve amaçlarına göre sınıflandırılır (Tablo 13.19).

Tablo 13.19: Kötü amaçlı yazılım türleri.
TürYayılmaAmaç / davranış
VirüsBaşka bir programa kendini ekler; kullanıcı o programı çalıştırınca bulaşırDosyaları bozar, yayılır
SolucanAğ üzerinden kendi kendine; kullanıcı gerekmezHızlı yayılır, kaynak tüketir
Truva atıYararlı görünen bir programın içindeArka kapı açar, veri çalar
Fidye yazılımıOltalama, açık, RDPDosyaları şifreler, fidye ister
RootkitAyrıcalık kazanıldıktan sonra kurulurKendini ve öteki zararlıları gizler
Casus yazılımTruva atı, paket yazılım, sahte eklentiVeri toplar, uzağa gönderir
Bot / botnetSolucan + arka kapıUzaktan komutla DDoS, spam, kazım

Virüs ile solucan arasındaki fark yayılmanın kime bağlı olduğudur. Virüs bir taşıyıcıya ihtiyaç duyar: başka bir programa ya da belgeye yerleşir ve o dosya çalıştırıldığında ya da açıldığında etkinleşir. Solucan (worm) ise bağımsız bir programdır. Ağdaki yamalanmamış bir hizmeti kullanarak makineden makineye kendini kopyalar ve kullanıcının hiçbir şey yapmasına gerek kalmaz. Kasım 1988'deki Morris solucanı, o günkü İnternet'e bağlı makinelerin önemli bir kısmını birkaç saatte etkiledi. 2017'deki WannaCry ise fidye yazılımı taşıyan bir solucandı ve Windows'un dosya paylaşım protokolündeki bir açıkla yayıldı.

Truva atı (Trojan horse) adını Truva savaşındaki tahta attan alır. Kullanıcının kendi isteğiyle kurduğu, yararlı görünen bir oyun, eklenti ya da “ücretsiz” bir yazılımdır. Kullanıcının haklarıyla çalıştığı için o kullanıcının erişebildiği her şeye erişir. Casus yazılım (spyware) kullanıcının etkinliklerini izler ve uzağa gönderir. Tarayıcının ana sayfasını ya da arama motorunu değiştirebilir, istenmeyen araç çubukları ekleyebilir, durdurulamayan reklam pencereleri açabilir.

Bugün sınırlar bulanıktır. Modern bir zararlı genellikle birkaç türü birleştirir: solucan gibi yayılır, rootkit ile gizlenir, bir botnet'e bağlanır ve sonunda fidye yazılımı yükünü çalıştırır.

13.8.2Parazitik virüsler

Klasik virüslerin en yaygın türü, çalıştırılabilir dosyalara yerleşen parazitik virüslerdir. Virüs bir dosyaya bulaşırken iki iş yapar: kendi kodunu dosyaya ekler ve programın giriş noktasını değiştirir. Program çalıştırıldığında önce virüs çalışır, yeni dosyalara bulaşır, sonra asıl programa atlar. Kullanıcı programın normal çalıştığını görür ve bir şeyden kuşkulanmaz. Virüs kodunu dosyanın neresine koyduğuna göre üç türe ayrılır.

Başta yerleşik
Virüs kodu programın başına eklenir ve giriş noktası virüse çevrilir.
Sonda yerleşik
Virüs programın sonuna eklenir; programın başına virüse atlayan bir komut konur. En yaygın türdür, çünkü programın geri kalanını kaydırmak gerekmez.
Boşluklara yayılmış
Çalıştırılabilir dosyalarda hizalama yüzünden kullanılmayan boşluklar bulunur. Virüs kendini parçalara bölüp bu boşluklara dağıtır. Dosya boyu değişmediği için tespit edilmesi zorlaşır (Şekil 13.38).
(d) boşluklara yayılmışPrgVPrgVPrgVPrgGiriş noktası virüse yönlendirilir; virüs çalışır, sonra asıl programa atlar
Şekil 13.38: Boşluklara yayılmış virüs: parçalar programın kullanılmayan alanlarına dağılır; dosya boyu değişmez.

Başka türler de vardır. Eşlik eden virüs asıl programa dokunmaz: MS-DOS'ta aynı adlı .com dosyası .exe'den önce çalıştığı için, prog.exe'nin yanına prog.com adıyla yerleşir. Bellekte yerleşik virüsler bellekte kalıp kesme vektörlerini ele geçirir. Önyükleme sektörü virüsleri işletim sisteminden önce çalışır. Aygıt sürücüsü virüsleri çekirdek kipinde çalışır. Makro virüsleri belgelerin içindeki makrolara, kaynak kodu virüsleri derlenmeden önce kaynak dosyalara yerleşir. Bunların çoğu bugün tarihseldir. Modern zararlılar betikleri, diske hiç dosya yazmayan bellek içi (fileless) teknikleri ve tedarik zinciri yollarını kullanır.

13.8.3Fidye yazılımı

Fidye yazılımı (ransomware), kurbanın verilerini şifreleyip çözme anahtarı karşılığında para isteyen kötü amaçlı yazılımdır. Bugün kurumların karşılaştığı en yıkıcı tehditlerden biridir. Tipik bir saldırı beş adımda ilerler (Şekil 13.39).

  1. İlk erişim. Çoğunlukla bir oltalama e-postasının eki, internete açık ve yaması yapılmamış bir hizmet ya da çalınmış bir uzak masaüstü (RDP) parolasıyla olur.
  2. Yayılma. Zararlı çalışır ve ağda yanal hareketle olabildiğince çok makineye ulaşır. Saldırganlar bu aşamada günler ya da haftalar geçirebilir.
  3. Yedeklerin silinmesi. Kurtarmayı engellemek için gölge kopyalar ve ağdan erişilebilen yedekler silinir. Çevrimdışı ya da değiştirilemez yedek bu yüzden şarttır.
  4. Şifreleme. Dosyalar güçlü bir simetrik şifreyle, örneğin AES ile kilitlenir. Simetrik anahtar saldırganın açık anahtarıyla şifrelenir ya da saldırganın sunucusuna gönderilir. Kurbanın elinde anahtarın hiçbir kopyası kalmaz.
  5. Fidye notu. Ekranda ödeme yönergeleri görüntülenir. Son yıllarda saldırganlar şifrelemeden önce veriyi dışarı da kopyalar ve ödeme yapılmazsa yayımlamakla tehdit eder.
Oltalama eki / açıkÇalışır, yayılırYedekleri silerDosyaları şifrelerFidye notuDosyalar AES ile şifreliÖdeme = anahtar garantisi değil; yedek + yama tek güvenilir savunma
Şekil 13.39: Fidye yazılımı saldırı zinciri. Ödeme anahtarın verileceğini garanti etmez; yedek ve yama tek güvenilir savunmadır.

Fidye yazılımı, sağlam kriptografinin kötü amaçla nasıl kullanılabileceğini gösterir. AES doğru kullanıldığında anahtar olmadan çözülemez. Dolayısıyla şifreleme başladıktan sonra yapılabilecek pek bir şey kalmaz; savunma önceden yapılmalıdır. Ödeme, anahtarın verileceğini garanti etmez ve yeni saldırıları teşvik eder. Savunma katmanları bilinen araçlardır: 3-2-1 kuralına uygun ve değiştirilemez yedek, hızlı yama, MFA, ağ bölütlemesi ve şüpheli davranışı yakalayan uç nokta izleme (EDR).

13.8.4Rootkit ve gizlenme

Rootkit, sisteme yerleşmiş bir saldırganın varlığını gizlemek için kullandığı programlar topluluğudur. Adını UNIX'teki root hesabından alır. Rootkit, dosyaları, süreçleri ve ağ bağlantılarını işletim sisteminden ve onun araçlarından saklar. Gizlendiği katmana göre türleri vardır (Şekil 13.40).

Uygulamals, ps çıktısını değiştirirKütüphanelibc fonksiyonlarını saptırırÇekirdeksistem çağrı tablosunu değiştirirHipervizörişletim sistemini sanal makineye alırBellenim (firmware)UEFI/çevre birimi; yeniden kurulumla silinmezdaha derin = daha gizli, kaldırması daha zor
Şekil 13.40: Rootkitlerin saklanabileceği katmanlar. Aşağı inildikçe gizlenme güçlenir, kaldırmak zorlaşır.
Uygulama düzeyi
ls ve ps gibi araçlar, çıktılarından zararlının dosyalarını ve süreçlerini çıkaran sürümlerle değiştirilir. Bütünlük denetimiyle kolayca yakalanır.
Kütüphane düzeyi
libc'deki fonksiyonlar saptırılır. Örneğin dizin okuyan fonksiyon belirli adları atlar. Bu kütüphaneyi kullanan bütün programlar aldatılır.
Çekirdek düzeyi
Rootkit bir çekirdek modülü olarak yüklenir ve sistem çağrı tablosunu ya da çekirdeğin iç veri yapılarını değiştirir. Çekirdeğe sorulan her soru yalan bir cevap alır.
Hipervizör düzeyi
Rootkit, çalışan işletim sistemini fark ettirmeden bir sanal makinenin içine alır ve onun altında çalışır. İşletim sisteminin içinden bakıldığında hiçbir iz görülmez.
Bellenim düzeyi
UEFI belleniminde ya da bir çevre biriminin belleniminde saklanır. İşletim sistemi yeniden kurulsa ya da disk değiştirilse bile silinmez.

Rootkit ne kadar derine yerleşirse o kadar güçlüdür, ama kurması da o kadar zordur. Çekirdek ve altındaki rootkitlere karşı içeriden tarama güvenilir değildir, çünkü tarayıcının sorduğu sorulara rootkit cevap verir. Savunma birkaç yönden gelir. İmzalı sürücü zorunluluğu, çekirdeğe yalnız güvenilir modüllerin yüklenmesini sağlar. Güvenli önyükleme, değiştirilmiş bir önyükleyicinin ya da çekirdeğin çalışmasını engeller. Ölçülü önyükleme ve TPM, önyükleme bileşenlerinin özetini kaydeder ve değişikliği ortaya çıkarır. Son çare olarak disk, çevrimdışı olarak, temiz bir sistemden taranır.

13.8.5Antivirüs ve kaçırma teknikleri

Antivirüs yazılımları ile virüs yazarları arasında uzun süredir bir yarış vardır. Her tespit yöntemi yeni bir kaçırma tekniği doğurmuştur.

En eski yöntem imza taramadır. Bilinen her virüsün kodundan karakteristik bir bayt dizisi, yani imza çıkarılır. Tarayıcı dosyalarda bu dizileri arar. Hızlıdır ve yanlış alarmı azdır, ama yalnız bilinen virüsleri yakalar. Virüs yazarları ilk olarak sıkıştırmaya başvurdu: virüslü program sıkıştırılınca imza görünmez olur. Tarayıcılar buna dosyaları açıp içlerini tarayarak karşılık verdi. Sonra şifreli virüsler çıktı: virüsün gövdesi her kopyada farklı bir anahtarla şifrelenir, yalnız küçük bir çözücü açıkta kalır. Tarayıcılar bu kez çözücünün imzasını aramaya başladı.

Bunun da yanıtı çok şekilli (polymorphic) virüslerdir (Şekil 13.41). Bu virüsler çözücüyü de her kopyada değiştirir. Aynı işi yapan farklı komut dizileri üretilir: araya etkisiz komutlar eklenir, yazmaçlar değiştirilir, komutların sırası karıştırılır. İki kopya arasında ortak bir bayt dizisi kalmadığı için imza yöntemi işe yaramaz.

(e) çok şekilliDeğişen çözücüŞifreli virüsProgramÇok şekilli (polymorphic): çözücü her kopyada farklı → imza işe yaramaz, davranış analizi gerekir
Şekil 13.41: Çok şekilli virüs: çözücü her kopyada farklıdır, gövde şifrelidir; sabit bir imza kalmaz.

Bugünkü güvenlik yazılımları bu yüzden birkaç yöntemi birlikte kullanır.

İmza tarama
Bilinen desenleri hızlı ve düşük yanlış alarm oranıyla yakalar; yeniyi kaçırır.
Bütünlük denetimi
Sistem dosyalarının özetlerini saklar ve herhangi bir değişikliği fark eder.
Davranışsal ve sezgisel analiz
Programın ne olduğuna değil ne yaptığına bakar. Kısa sürede yüzlerce dosyayı şifrelemek, başka süreçlere kod enjekte etmek ve gölge kopyaları silmek şüpheli eylemlerdir.
Korumalı alan ve bulut
Şüpheli dosya yalıtılmış bir ortamda çalıştırılır ve davranışı gözlenir. Sonuç bulut üzerinden bütün müşterilerle paylaşılır.

13.9Savunma ve yalıtım

Hataların ve açıkların tamamen ortadan kalkmayacağı kabul edilirse savunmanın iki yolu kalır. Birincisi, sisteme yalnız güvenilir kaynaktan gelen kodun girmesini sağlamaktır. İkincisi, güvenilmeyen ya da ele geçirilmiş kodun verebileceği zararı sınırlamaktır. Bu kesim ilk yol için kod imzalamayı, ikinci yol için korumalı alanları, konteynerleri ve zorunlu erişim denetimini anlatır.

13.9.1Kod imzalama

Kod imzalama, dijital imzanın programlara uygulanmasıdır (Şekil 13.42). Amaç, bir programın değiştirilmediğini ve iddia ettiği yayıncıdan geldiğini çalıştırmadan önce doğrulamaktır.

  1. Özet. Yayıncı programın özetini hesaplar.
  2. İmza. Özet, yayıncının özel anahtarıyla imzalanır. İmza programla birlikte dağıtılır.
  3. Dağıtım. Kullanıcı programı ve imzayı alır. Yayıncının sertifikası açık anahtarını taşır ve bir sertifika otoritesine bağlanır.
  4. Doğrulama. İşletim sistemi özeti yeniden hesaplar ve imzayı açık anahtarla doğrular. Eşleşirse program değiştirilmemiştir ve o yayıncıdandır.
Yayıncıİşletim sistemiProgramözetözel anahtarlaimzalaimzaProgramimzaaçık anahtarladoğrulagüvenilir ✓
Şekil 13.42: Kod imzalama: yayıncı özeti özel anahtarıyla imzalar, işletim sistemi açık anahtarla doğrular.

Bugünkü sistemlerin çoğu bu temele dayanır. Mobil uygulama mağazaları yalnız imzalı uygulamaları dağıtır. Windows, 64 bitlik sürümlerinde çekirdek sürücülerinin imzalı olmasını şart koşar. Linux dağıtımlarının paket yöneticileri (apt, dnf) her paketin imzasını dağıtımın anahtarıyla denetler. Bazı platformlar daha da ileri gider ve yalnız imzalı kodun çalışmasına izin verir.

Kod imzalamanın neyi kanıtlamadığı da önemlidir. İmza, programın kimden geldiğini ve yolda değişmediğini gösterir; programın zararsız olduğunu göstermez. Yayıncının imza anahtarı çalınırsa ya da yayıncının derleme sunucusu ele geçirilirse zararlı kod da geçerli bir imza taşır. Tedarik zinciri saldırıları tam bu noktayı hedefler.

13.9.2Korumalı alan

Tanım 13.20

Korumalı alan (sandbox), güvenilmeyen bir programı sınırlı haklarla, sistemin geri kalanından yalıtılmış bir ortamda çalıştırma yöntemidir. Program ele geçirilse bile verebileceği zarar alanın sınırlarıyla kısıtlı kalır.

Fikir, Lampson'ın hapsetme probleminin pratik bir cevabıdır. Şekil 13.43 eski bir benzetmeyi kullanır: program bir hapishanededir ve yaptığı her sistem çağrısını bir gardiyan denetler. İzin verilmeyen çağrılar engellenir. Erken UNIX'teki chroot hapisleri ve FreeBSD'nin jail mekanizması bu düşüncenin ilk uygulamalarıdır.

Hapis (jail)Mahkûm programGardiyanHer sistem çağrısıgardiyan tarafındandenetlenir, izinsizlerengellenirModern korumalı alan• seccomp-bpf: izinli sistem çağrıları• namespaces: ayrı PID/ağ/dosya görünümü• cgroups: CPU/bellek sınırı• yetenekler düşürülür• SELinux/AppArmor profili
Şekil 13.43: Solda hapsedilmiş program ve gardiyanı; sağda Linux'taki modern korumalı alanın yapı taşları.

Bugün tarayıcı sekmeleri, mobil uygulamalar ve birçok sunucu hizmeti korumalı alanda çalışır. Linux'ta bir korumalı alan birkaç çekirdek mekanizmasının birleşimidir.

seccomp-bpf
Sürecin yapabileceği sistem çağrılarını bir filtreyle sınırlar. Örneğin bir görüntü çözücü yalnız read, write ve exit çağırabilir. Başka bir çağrı yapmaya kalkarsa çekirdek süreci öldürür.
Ad alanları (namespaces)
Sürece sistemin ayrı bir görünümünü verir. PID ad alanındaki süreç yalnız kendi alanındaki süreçleri görür; ağ ad alanının kendi ağ arayüzleri, bağlama ad alanının kendi dosya sistemi ağacı vardır.
cgroups
Bir süreç grubunun kullanabileceği CPU, bellek ve G/Ç miktarını sınırlar. Kaynak tüketme yoluyla hizmet reddini önler.
Yeteneklerin düşürülmesi
Root olarak başlayan bir süreç bile ihtiyaç duymadığı bütün Linux yeteneklerini bırakır.
Zorunlu erişim denetimi
SELinux ya da AppArmor profili, sürecin erişebileceği dosyaları ve kaynakları ayrıca sınırlar.

13.9.3Konteynerler

Ad alanları ve cgroups bir araya geldiğinde ortaya çıkan yapıya konteyner denir (Şekil 13.44). Konteynerdeki uygulama kendine ait bir dosya sistemi, ağ yığını ve süreç ağacı görür; sanki tek başına bir makinedeymiş gibi çalışır. Ama gerçekte bütün konteynerler aynı çekirdeği paylaşır. Docker ve Kubernetes gibi araçlar bu çekirdek özellikleri üzerine kurulmuştur.

DonanımTek paylaşılan çekirdek (namespaces + cgroups + seccomp)Konteyner 1UygulamaKütüphanelerKonteyner 2UygulamaKütüphanelerKonteyner 3UygulamaKütüphanelerKonteyner 4UygulamaKütüphaneler
Şekil 13.44: Dört konteyner: her birinin kendi uygulaması ve kütüphaneleri var, ama hepsi tek bir çekirdeği paylaşır.

Konteynerin sanal makineyle karşılaştırılması güvenlik açısından öğreticidir (Tablo 13.20). Sanal makinede her konuk kendi çekirdeğini çalıştırır ve konukları birbirinden hipervizör ile donanım ayırır. Konteynerde yalıtım tamamen çekirdeğin kendi özelliklerine dayanır.

Tablo 13.20: Konteyner ve sanal makine yalıtımı.
KonteynerSanal makine
YalıtımÇekirdek özellikleriDonanım + hipervizör
Ek yükDüşük, saniyede başlarYüksek, ayrı çekirdek
Saldırı yüzeyiÇekirdek açığı = kaçış riskiDaha güçlü sınır

Bu farkın sonucu açıktır. Paylaşılan çekirdekte bir açık bulunursa, konteynerdeki bir saldırgan bu açığı kullanarak konteynerden kaçabilir ve aynı makinedeki bütün öteki konteynerlere erişebilir. Sanal makinede ise konuk çekirdekteki bir açık yalnız o konuğu etkiler; dışarı çıkmak için hipervizörde ikinci bir açık gerekir. Bulut sağlayıcıları bu yüzden farklı müşterilerin konteynerlerini çoğunlukla ayrı sanal makinelerde ya da hafif sanal makinelerde (örneğin Firecracker) çalıştırır.

Sık yapılan hata

Konteynerde root olarak çalışmayı zararsız saymak. Kullanıcı ad alanı kullanılmıyorsa konteynerdeki root, çekirdek açısından gerçek root'tur (uid 0). Bir yapılandırma hatası ya da çekirdek açığıyla konteynerden çıkan bu süreç bütün makineye hükmeder. Konteyner süreçleri de en az ayrıcalıkla çalıştırılmalıdır.

13.9.4Zorunlu erişim denetimi: SELinux ve AppArmor

UNIX izinleri ve ACL'ler isteğe bağlı erişim denetimidir (DAC): bir dosyanın izinlerini sahibi belirler ve istediği zaman değiştirebilir. Bunun bir zaafı vardır. Ali'nin hesabıyla çalışan bir zararlı da Ali'nin dosyalarının izinlerini değiştirebilir, çünkü çekirdek açısından o da Ali'dir. Zorunlu erişim denetimi (MAC) bu zaafı kapatır: politikayı sistem yöneticisi belirler ve hiçbir süreç, root bile olsa, kendi kısıtını gevşetemez.

SELinux
Her özneye ve nesneye bir güvenlik etiketi verir. Kurallar tip zorlaması (type enforcement) ile yazılır: “httpd_t tipindeki süreçler httpd_sys_content_t tipindeki dosyaları okuyabilir” gibi. Çok ayrıntılı ve güçlüdür, ama karmaşıktır. Ayrıca BLP tarzı çok düzeyli güvenliği (MLS) de destekler.
AppArmor
Dosya yollarına dayanan, uygulama başına profiller kullanır: “/usr/sbin/nginx yalnız /var/www/ altını okuyabilir” gibi. Yazması ve anlaması daha kolaydır.

Linux'ta her iki sistem de çekirdeğin Linux Güvenlik Modülleri (LSM) altyapısını kullanır. Çekirdek, kritik işlemlerin önüne kancalar koyar. Bir süreç örneğin open çağırdığında önce olağan DAC denetimi yapılır. DAC izin verirse LSM kancası çağrılır ve MAC politikası sorulur (Şekil 13.45). İşlemin yapılabilmesi için ikisinin de “evet” demesi gerekir. DAC reddederse MAC'e hiç sorulmaz.

httpd süreciopen(/etc/shadow)DAC: rwx, ACLsahip değiştirebilirMAC: SELinux/AppArmorpolitika, süreç değiştiremezizinEACCESDAC reddederse MAC’e hiç sorulmazikisi de “evet” demeli
Şekil 13.45: Bir open() isteği önce DAC izin bitlerinden, sonra LSM kancasındaki MAC politikasından geçer.
Örnek 13.15

Bir web sunucusu, bir açık yüzünden ele geçirildi. Saldırgan sunucunun kullanıcı hesabıyla komut çalıştırabiliyor. İki gözlem yapılıyor: (1) saldırgan, sunucuya ait bir dosyanın iznini chmod ile rahatça değiştirebiliyor; (2) izin bitleri izin verse bile /home altındaki dosyalara erişemiyor. Bu davranışlar hangi denetimden kaynaklanır?

  1. (1) DAC'tir. Dosyanın sahibi sunucu hesabıdır ve DAC'te sahip, zararlı da olsa, izinleri değiştirebilir.
  2. (2) MAC'tir. SELinux ya da AppArmor profili sunucu sürecini yalnız web dosyalarıyla sınırlar. İzin bitleri “evet” dese de MAC “hayır” der ve sonuç EACCES olur.

MAC, ele geçirilen bir süreci bile profilinin izin verdiği işlemlerle sınırlar. Saldırgan yalnız o profilin tanımladığı dosyalara erişebilir. Android de uygulamaları birbirinden ayırmak için SELinux'u bütünüyle zorunlu kipte çalıştırır.

13.10Donanım düzeyinde güvenlik

Önceki kesimlerin hepsi işletim sisteminin doğru çalıştığını varsaydı. Peki işletim sisteminin kendisi değiştirilmişse? Ya da donanım, yazılımın bütün denetimlerine rağmen bilgi sızdırıyorsa? Bu kesim güven zincirinin en altını ele alır.

13.10.1Güvenli önyükleme ve TPM

Bilgisayar açıldığında sırasıyla bellenim, önyükleyici, çekirdek ve işletim sistemi çalışır. Bir saldırgan bu zincirin herhangi bir halkasını değiştirebilirse, kendi kodunu işletim sisteminden önce çalıştırır. İşletim sistemi açıldığında artık her şeyi denetleyen bu kod olur ve onu içeriden fark etmek imkânsızdır. Önyükleme sürecine yerleşen bu tür zararlılara önyükleme kiti (bootkit) denir.

Tanım 13.21

Güvenli önyükleme (secure boot), önyükleme zincirindeki her katmanın bir sonrakinin dijital imzasını doğrulamadan onu çalıştırmamasıdır. Zincir, donanımdaki değiştirilemez bir kök güvene dayanır.

Donanım kök güvenideğişmezUEFI bellenimimza ✓Önyükleyiciimza ✓Çekirdekimza ✓İşletim sistemiimza ✓Her aşama bir sonrakinin imzasını doğrulamadan çalıştırmaz (güven zinciri)İmzasız/değiştirilmişçalıştırılmazTPMölçümleri saklar, mühür
Şekil 13.46: Güven zinciri: her aşama bir sonrakinin imzasını doğrular. İmzasız ya da değiştirilmiş bir bileşen çalıştırılmaz. TPM ölçümleri saklar.

Zincir şöyle işler (Şekil 13.46). Donanımdaki kök güven, UEFI belleniminin imzasını doğrular. UEFI, diskteki önyükleyicinin imzasını kendi veritabanındaki anahtarlarla denetler. Önyükleyici çekirdeğin, çekirdek de yüklediği sürücülerin imzasını denetler. Bir önyükleme kiti diskteki önyükleyiciyi değiştirmişse, UEFI imzayı doğrulayamaz ve önyükleyiciyi çalıştırmaz.

Güvenli önyüklemenin tamamlayıcısı TPM'dir (Trusted Platform Module, Güvenilir Platform Modülü). TPM, anakarta ya da işlemciye yerleşik küçük bir güvenlik yongasıdır. İçinde platform yapılandırma yazmaçları (PCR) vardır. Ölçülü önyüklemede (measured boot) her bileşen çalıştırılmadan önce özeti alınır ve bir PCR'ye eklenir. Ekleme işlemi yazmacın eski değeriyle yeni özetin birlikte özetlenmesidir. Bu yüzden bir PCR'nin son değeri, bütün zincirin sırasıyla birlikte bir parmak izidir ve geriye doğru değiştirilemez.

TPM bu ölçümleri iki biçimde kullanır. Birincisi mühürlemedir: disk şifreleme anahtarı (örneğin BitLocker ya da LUKS anahtarı) belirli PCR değerlerine mühürlenir. TPM anahtarı yalnız sistem beklenen durumda açıldıysa serbest bırakır. Önyükleyici değiştirilmişse ölçüm farklı çıkar ve anahtar açılmaz. İkincisi uzaktan kanıtlamadır (attestation): TPM ölçümleri kendi anahtarıyla imzalayıp uzaktaki bir sunucuya gönderir. Sunucu makinenin güvenilir bir yazılımla açıldığını doğrulayabilir.

Sık yapılan hata

Güvenli önyüklemeyi ve ölçülü önyüklemeyi aynı şey saymak. Güvenli önyükleme imzasız bileşeni çalıştırmaz. Ölçülü önyükleme ise her şeyi çalıştırır, ama ne çalıştığını kaydeder ve beklenmeyen bir ölçümde anahtarı açmaz. TPM hiçbir şeyi onarmaz ya da engellemez; yalnız ölçer, saklar ve buna göre anahtar verir.

13.10.2Spectre, Meltdown ve yan kanallar

Gizli kanalda iki süreç bilerek işbirliği yapar. Yan kanalda ise kurban hiçbir şeyin farkında değildir; saldırgan onun davranışının dolaylı izlerini ölçer.

Tanım 13.22

Yan kanal (side channel), veriyi hesaplamanın dolaylı fiziksel etkilerinden sızdıran bir saldırı yoludur. Bu etkiler süre, güç tüketimi, önbellek durumu, elektromanyetik yayılım ya da ses olabilir.

Klasik bir örnek, parolayı karakter karakter karşılaştıran ve ilk farkta duran bir fonksiyondur. Doğru başlayan bir deneme biraz daha uzun sürer; saldırgan süreleri ölçerek parolayı karakter karakter bulur. Sabit zamanlı karşılaştırmanın nedeni budur. Önbellek de güçlü bir yan kanaldır. Bir verinin önbellekte olup olmadığı, ona erişim süresinden anlaşılır: önbellekten birkaç nanosaniyede, ana bellekten yüz nanosaniye civarında gelir.

2018'in başında duyurulan Meltdown ve Spectre, bu yan kanalı işlemcilerin spekülatif yürütmesiyle birleştirdi (Şekil 13.47). Bugünkü işlemciler hız kazanmak için, sonucu henüz kesinleşmemiş komutları önceden yürütür. Örneğin bir dal koşulu hesaplanmadan, tahmin edilen yöndeki komutlar çalıştırılır. Tahmin yanlış çıkarsa işlemci bu komutların mimari sonuçlarını, yani yazmaç değerlerini geri alır. Ama komutların önbelleğe getirdiği veriler önbellekte kalır.

Saldırgan süreciKurban / çekirdekgizli veriPaylaşılan önbellekCPU donanımıspekülatif erişimZamanlama ölçümübit bit sızdırırMimari sonuç geri alınır ama önbellek izi kalır → gizli veri çıkarılır
Şekil 13.47: Spekülatif erişimin mimari sonucu geri alınır, ama paylaşılan önbellekte bıraktığı iz kalır ve zamanlama ölçümüyle okunur.

Saldırgan bunu şöyle kullanır. İşlemciyi, erişme hakkı olmayan bir gizli baytı spekülatif olarak okumaya yönlendirir. Spekülatif kod bu baytın değerini, büyük bir dizinin içinde bir indis olarak kullanır ve o indisteki satırı önbelleğe getirir. İşlemci hatayı fark eder ve sonucu geri alır; saldırgan gizli baytı hiç görmez. Ama sonra dizinin bütün satırlarına erişip süreleri ölçer. Hızlı gelen satırın indisi, gizli baytın değeridir. Meltdown bu yolla kullanıcı kipindeki bir sürecin çekirdek belleğini okumasına izin veriyordu. Spectre ise başka bir sürecin ya da aynı süreçteki korumalı bir alanın belleğini okumayı sağlıyordu.

Önlemler hem yazılımda hem donanımdadır. Meltdown'a karşı işletim sistemleri çekirdek sayfa tablosu yalıtımını (KPTI) getirdi: kullanıcı kipindeyken çekirdek belleğinin büyük kısmı sayfa tablosundan tamamen çıkarılır. Spectre'a karşı mikrokod güncellemeleri ve derleyicinin eklediği spekülasyon bariyerleri kullanılır. Bu önlemlerin çoğu bir performans bedeliyle gelir; sistem çağrısı yoğun iş yüklerinde yavaşlama belirgindir. Bu açıklar önemli bir dersi de gösterdi: koruma mekanizmalarının doğruluğu yalnız mimari belirtime değil, donanımın gerçekleme ayrıntılarına da bağlıdır.

13.11Özet

  • Güvenliğin üç temel hedefi gizlilik, bütünlük ve erişilebilirliktir; bunlara özgünlük ve hesap verebilirlik eklenir. Tehdit olası zarar, zafiyet zayıflık, saldırı kullanma girişimi, istismar da bunu yapan koddur.
  • Ağda dinleme, tekrar, ortadaki adam ve oturum kaçırma saldırıları vardır. Çareleri sırasıyla şifreleme, tek kullanımlık değerler, sertifikayla kimlik doğrulama ve güvenli çerezlerdir.
  • Savunma derinlemesine kurulur; güvenlik iddiaları küçük tutulması gereken TCB'ye ve her erişimi denetleyen referans izleyiciye dayanır.
  • Simetrik şifreleme hızlıdır ama paylaşılan anahtar ister; açık anahtarlı şifreleme anahtar dağıtımını çözer ama yavaştır. Gerçek sistemler ikisini birlikte kullanır. Güvenlik anahtara dayanır, algoritmanın gizliliğine değil (Kerckhoffs).
  • Özet fonksiyonu tek yönlü ve çakışmaya dayanıklıdır. Dijital imzada özet özel anahtarla imzalanır, açık anahtarla doğrulanır. Sertifikalar açık anahtarı kimliğe bağlar. TLS 1.3 geçici Diffie-Hellman, sertifika ve kimlik doğrulamalı şifrelemeyi tek gidiş-dönüşte birleştirir.
  • Diffie-Hellman örneğinde (p = 23, g = 5, a = 6, b = 15) A = 8, B = 19 ve ortak sır 2'dir. Kare al ve çarp yöntemi n bitlik üssü n turda hesaplar.
  • Koruma matrisi seyrektir; sütunları ACL, satırları yetenek listesi olarak saklanır. ACL'de geri alma, yetenekte devretme kolaydır. UNIX izinleri dokuz bitlik bir ACL'dir; dosya tanımlayıcısı bir yetenektir.
  • En az ayrıcalık ilkesi gereği setuid programlar ayrıcalığı işleri biter bitmez setresuid ile kalıcı olarak bırakır. Linux root'u yaklaşık 41 yeteneğe böler.
  • Bell-LaPadula gizliliği korur: yukarı okuma ve aşağı yazma yoktur. Biba bütünlüğü korur: aşağı okuma ve yukarı yazma yoktur. İkisi de gizli kanalları kapatamaz; kanalların yalnız bant genişliği düşürülebilir.
  • Parolalar tuzlu ve yavaş bir özetle (Argon2id) saklanır: tuz toplu saldırıyı, yavaşlık her denemeyi pahalılaştırır. MFA farklı kategorilerden iki etken ister. TOTP kodu HMAC(K, ⌊t / 30⌋)'tan dinamik kesmeyle türetilir. FIDO2 imzası sitenin kökenine bağlı olduğu için oltalamaya dayanıklıdır.
  • Yığın tampon taşması dönüş adresini bozar. Savunmalar katmanlıdır: kanarya bozulmayı dönüşte yakalar, NX enjekte kodu çalıştırmaz, ASLR adresleri gizler, CFI ve gölge yığın ROP'u zorlaştırır; en köklü çözüm bellek güvenli dillerdir.
  • TOCTOU açığında kontrol ile kullanım arasında kaynak değişir; çözüm adı bir kez çözüp aynı tanımlayıcı üzerinde çalışmaktır.
  • İçeriden saldırılar mantık bombası, arka kapı ve giriş sahtekârlığıdır. Kötü amaçlı yazılımlar virüs, solucan, Truva atı, fidye yazılımı, rootkit, casus yazılım ve botlardır; çok şekilli virüsler imza taramasını aşar.
  • Kod imzalama kaynağı doğrular. Korumalı alan ve konteyner zararı sınırlar; konteyner çekirdeği paylaştığı için sanal makineden zayıf bir sınırdır. MAC (SELinux, AppArmor) ele geçirilen süreci bile profiliyle sınırlar.
  • Güvenli önyükleme imzasız bileşeni çalıştırmaz; TPM ölçümleri saklar ve anahtarları bunlara mühürler. Spectre ve Meltdown, spekülatif yürütmenin önbellekte bıraktığı izi bir yan kanal olarak kullanır.

13.12Kavram listesi

Terimlerin İngilizce karşılıkları ve öteki bölümlerdeki kullanımları terim sözlüğünde bulunur.

13.13Kendini Dene

  1. Tablo 13.3'teki yerine koyma anahtarıyla GIRESUN sözcüğü nasıl şifrelenir? Şifreli ZTLZ neyi gizler?

    Cevap

    G → U, I → O, R → K, E → T, S → L, U → X, N → F: UOKTLXF. Ters yönde Z → T, T → E, L → S, Z → T: TEST. İki Z'nin ikisi de T'ye gider; sıklık yine korunur.

  2. Diffie-Hellman'da p = 23 ve g = 5'tir. Alice a = 4, Bob b = 3 seçiyor. A, B ve ortak sır nedir?

    Cevap

    A = 54 mod 23 = 625 mod 23 = 4. B = 53 mod 23 = 125 mod 23 = 10. Alice: 104 mod 23 = 10000 mod 23 = 18. Bob: 43 mod 23 = 64 mod 23 = 18. Ortak sır 18'dir.

  3. Bir arkadaş, “Alice belgeyi Bob'la paylaştığı gizli anahtarla HMAC'leyip gönderirse bu da bir imzadır” diyor. Bu düzen bütünlüğü ve inkâr edilemezliği sağlar mı?

    Cevap

    Bütünlüğü sağlar: anahtarı bilmeyen biri belgeyi değiştirip geçerli bir kod üretemez. İnkâr edilemezliği sağlamaz: anahtarı Bob da bildiği için aynı kodu Bob da üretebilirdi. Alice “bunu Bob üretti” diyebilir. İnkâr edilemezlik için yalnız Alice'in bildiği bir özel anahtar gerekir.

  4. Kod izlemedeki ACL ile erisim(G2, R|W) ve erisim(YON, W) ne döndürür? Karar ifadesi (h & istek) != 0 olsaydı ilk çağrının sonucu değişir miydi?

    Cevap

    G2'nin girdisi h = 2'dir; istek 6'dır. 2 & 6 = 2 ≠ 6, ret (0). YON için h = 7, 7 & 2 = 2, izin (1). Hatalı ifadeyle 2 & 6 = 2 ≠ 0 olur ve G2'ye okuma hakkı olmadığı hâlde izin verilirdi.

  5. Bir dosyanın modu 754'tür. Grup üyeleri dosyayı değiştirebilir mi? umask 027 iken oluşturulan yeni bir dosya ve dizin hangi modları alır?

    Cevap

    754 = rwxr-xr--. Grubun hakkı r-x'tir; yazma yoktur, değiştiremez. umask 027 ile dosya 666 → 640, dizin 777 → 750 olur.

  6. Gizli düzeydeki bir süreç için BLP hangi işleme izin verir: Tasnif Dışı bir duyuruyu okumak mı, Hizmete Özel bir dosyaya yazmak mı? Aynı süreç Biba'da Orta düzeyde olsaydı Düşük düzeydeki bir İnternet dosyasını okuyabilir miydi?

    Cevap

    BLP'de aşağı okuma serbesttir; Tasnif Dışı duyuruyu okumak izinlidir. Hizmete Özel dosyaya yazmak aşağı yazmadır ve yasaktır. Biba'da aşağı okuma yasaktır; Orta düzeydeki süreç Düşük dosyayı okuyamaz.

  7. Dosya kilidiyle çalışan bir gizli kanalda aralık 5 ms'ye indiriliyor. Kanalın hızı nedir? 2048 bitlik bir RSA özel anahtarı ne kadar sürede sızar?

    Cevap

    Saniyede 1000 / 5 = 200 aralık, yani 200 bit/s. 2048 / 200 = 10,24 saniye.

  8. Parolalar 12 küçük harften oluşuyor ve düz SHA-256 ile saklanıyor. Saniyede 1010 denemeyle tek bir kullanıcının parolası en kötü durumda ne kadar sürede bulunur? Tuz eklemek bu süreyi değiştirir mi?

    Cevap

    2612 ≈ 9,54 × 1016; 1010'a bölününce ≈ 9,54 × 106 saniye, yaklaşık 110 gün. Tuz tek kullanıcının süresini değiştirmez; bütün kullanıcılar hedeflendiğinde işi kullanıcı sayısıyla çarpar.

  9. t = 1.000.000.000 anında TOTP sayacı T kaçtır? Bu koda karşılık gelen 30 saniyelik pencere hangi aralıktır?

    Cevap

    1.000.000.000 / 30 = 33.333.333,3; T = 33.333.333. Pencere T · 30 = 999.999.990'dan 1.000.000.019'a kadardır.

  10. 64 bitlik bir makinede kanaryasız bir fonksiyon char ad[16] dizisine 30 karakterlik bir dizgiyi strcpy ile kopyalıyor. Kaç bayt taşar? Kayıtlı rbp ve dönüş adresinin kaçar baytı bozulur?

    Cevap

    Sonlandırıcıyla 31 bayt yazılır; 31 − 16 = 15 bayt taşar. İlk 8'i kayıtlı rbp'nin tamamını, kalan 7'si (son karakter ve \0 dahil) dönüş adresinin 7 baytını bozar.

13.14İleri okuma

  • J. H. Saltzer ve M. D. Schroeder, “The Protection of Information in Computer Systems”, 1975: en az ayrıcalık, güvenli varsayılan ve tam aracılık ilkelerini ilk kez bir arada sıralayan klasik makale. Bugün de günceldir.
  • R. Anderson, Security Engineering, 3. baskı: güvenliği teknik olduğu kadar ekonomik ve insani bir sorun olarak ele alır. Parola, erişim denetimi ve biçimsel modeller bölümleri gerçek olay örnekleri içerir.
  • Aleph One, “Smashing the Stack for Fun and Profit”, Phrack 49, 1996: yığın tampon taşmasının istismarını adım adım gösteren tarihî metin. Bugünkü savunmaların neden gerektiğini anlamaya yardım eder.
  • P. Kocher vd., “Spectre Attacks: Exploiting Speculative Execution” ve M. Lipp vd., “Meltdown”, 2018: spekülatif yürütmenin önbellek yan kanalıyla nasıl birleştiğini özgün kaynağından anlatır.

13.15Kaynaklar

  1. A. S. Tanenbaum, H. Bos, Modern Operating Systems, 4. baskı (2014) / 5. baskı (2023), Pearson — Bölüm 9: Security.
  2. A. Silberschatz, P. B. Galvin, G. Gagne, Operating System Concepts, 10. baskı, Wiley, 2018 — Bölüm 16: Security; Bölüm 17: Protection.
  3. R. H. Arpaci-Dusseau, A. C. Arpaci-Dusseau, Operating Systems: Three Easy Pieces (OSTEP), ostep.org — güvenlik bölümleri.
  4. R. Anderson, Security Engineering, 3. baskı, Wiley, 2020.
  5. J. H. Saltzer, M. D. Schroeder, “The Protection of Information in Computer Systems”, 1975.
  6. D. E. Bell, L. J. LaPadula (1973); K. J. Biba (1977) — biçimsel güvenlik modelleri. B. W. Lampson, “A Note on the Confinement Problem”, 1973.
  7. RFC 8446 (TLS 1.3), RFC 6238 (TOTP), RFC 9106 (Argon2); FIDO2/WebAuthn (W3C); NIST FIPS 203 (ML-KEM).
  8. Aleph One, “Smashing the Stack for Fun and Profit”, Phrack 49, 1996; Kocher vd., “Spectre”; Lipp vd., “Meltdown”, 2018.

İlgili sayfalar: Bölüm 13 sunumu · Çalışma soruları · Terim sözlüğü · © Sercan Külcü. Tüm hakları saklıdır.