İçeriğe geç
academia.sh

Ders 14 / 25

Roller ve Yetkiler

En az yetki ilkesinin veritabanında uygulanması: rol tabanlı erişim denetimi, rol devralmasının ürettiği fazla yetkinin sayılması, salt okunur bağlantıyla ikinci savunma katmanı ve uygulama hesabı ile bakım hesabının ayrılması.

İçindekiler

Bu kursun buraya kadarki bölümü verinin nerede durduğunu ve hangi yoldan okunduğunu kurdu: sayfa düzeni, günlük, dizin türleri, bölümleme ve parçalama kalıpları. Veri düzeni ve erişim yolları yerine oturduğunda sistem çalışır hâle gelir — ama henüz işletilmiş sayılmaz. İşletim, çalışan bir sistemin zaman içinde güvenli, kurtarılabilir ve erişilebilir kalmasıdır.

Bu konunun ilk sorusu en eskisidir: bu veriye kim erişebilir ve ne yapabilir? Kütüphane ödünç kayıtları örneğinde soru somutlaşır. Ödünç masasındaki uygulamanın ödünç kaydı açması gerekir; üye kaydını silmesi gerekmez. Rapor aracının ödünç sayılarını okuması gerekir; hiçbir satırı değiştirmesi gerekmez. Bu ayrımların yapılmadığı bir kurulumda sistem yıllarca sorunsuz çalışabilir; tek bir hatalı sorgu ya da tek bir ele geçirilmiş uygulama anahtarı, ayrımın yapılmamış olmasının bedelini bir defada ödetir.

Kimlik Doğrulama ve Yetkilendirme

İki soru birbirine karışır. Kimlik doğrulama (authentication) “sen kimsin” sorusudur; İnternet Nasıl Çalışır kursunda HTTPS bağlamında tanıtılmıştı. Yetkilendirme (authorization) ise “kim olduğun belli, ne yapabilirsin” sorusudur. Veritabanı motorları ikisini ayrı katmanlarda tutar: bağlantı kurulurken kimlik doğrulanır, her deyimde yetki denetlenir.

SQL Temelleri kursunda GRANT ve REVOKE deyimleriyle nesne düzeyi izinler tanıtılmıştı. O ders dili anlattı; bu ders, aynı deyimlerin işletimde nasıl düzenleneceğini anlatır. Aradaki fark ölçektir: on tablo ve iki kullanıcı için izinleri tek tek vermek işler, yüz tablo ve otuz hesap için işlemez. Ölçeklendiren yapı rol (role) kavramıdır.

Rol Tabanlı Erişim Denetimi

Rol tabanlı erişim denetimi (role-based access control), izinleri kişilere değil görevlere bağlar. Önce görev tanımlanır — okuyucu, ödünç görevlisi, katalogcu — ve izinler o göreve verilir. Kişi ya da uygulama hesabı sonradan role atanır.

Bunun işletimdeki karşılığı şudur: bir çalışan görev değiştirdiğinde ya da bir uygulama kaldırıldığında değiştirilecek tek şey rol ataması olur. İzinler dağınık biçimde hesaplara yazılmışsa, ayrılan bir çalışanın erişimini kapatmak bir arama işine dönüşür ve o aramanın eksik kalması olağandır.

Rollerin ikinci özelliği rol devralması (role inheritance) — bir rolün başka bir rolün izinlerini kapsamasıdır. Katalogcu, okuyucunun her şeyini yapabilsin diye okuyucu rolünü devralır. Devralma yazımı kısaltır, ama bir yan etkisi vardır: etkin izin kümesi artık yazıldığı yerde görünmez, hesaplanması gerekir. Bir hesabın gerçekte neye erişebildiğini görmek için devralma zincirinin kapanışını almak gerekir.

Fazla Yetkinin Hesaplanması

Aşağıdaki betik bir yetki çizelgesini modeller: roller, rollerin devraldığı roller, hesapların rol atamaları ve her hesabın işini yapabilmesi için gerçekten gereken izinler. Betik, devralmayı izleyerek etkin izin kümesini üretir ve gerekenden fazlasını çıkarır.

Bu bir modeldir; gerçek bir motorun yetki çizelgesi değildir. Modellenen şey devralmanın kapanışı ve fark hesabıdır — motor hangisi olursa olsun bu iki adım aynıdır.

cat > yetki.mjs <<'EOF'
// Rol -> dogrudan verilmis izinler. Izin bicimi: "eylem:nesne".
const ROL_IZIN = {
  okuyucu:   ["select:kitap", "select:sube"],
  gorevli:   ["select:uye", "select:odunc", "insert:odunc", "update:odunc"],
  katalogcu: ["insert:kitap", "update:kitap", "delete:kitap"],
  yonetici:  ["delete:uye", "delete:odunc", "alter:*"],
};

// Rol -> devraldigi roller.
const ROL_DEVRAL = {
  okuyucu:   [],
  gorevli:   ["okuyucu"],
  katalogcu: ["okuyucu"],
  yonetici:  ["gorevli", "katalogcu"],
};

// Hesap -> atanmis roller.
const HESAP_ROL = {
  odunc_masasi:  ["gorevli"],
  katalog_ekibi: ["katalogcu"],
  rapor_araci:   ["gorevli"],
  bakim_hesabi:  ["yonetici"],
};

// Hesabin isini yapabilmesi icin gercekten gereken izinler.
const GEREKEN = {
  odunc_masasi:  ["select:kitap", "select:uye", "select:odunc", "insert:odunc", "update:odunc"],
  katalog_ekibi: ["select:kitap", "insert:kitap", "update:kitap"],
  rapor_araci:   ["select:kitap", "select:odunc"],
  bakim_hesabi:  ["select:kitap", "select:uye", "select:odunc", "alter:*"],
};

function etkinIzinler(rol, gorulen = new Set()) {
  if (gorulen.has(rol)) return new Set();          // devralma dongusune karsi
  gorulen.add(rol);
  const kume = new Set(ROL_IZIN[rol] ?? []);
  for (const ust of ROL_DEVRAL[rol] ?? []) {
    for (const izin of etkinIzinler(ust, gorulen)) kume.add(izin);
  }
  return kume;
}

function hesapIzinleri(hesap) {
  const kume = new Set();
  for (const rol of HESAP_ROL[hesap]) {
    for (const izin of etkinIzinler(rol)) kume.add(izin);
  }
  return kume;
}

const yaziciMi = (izin) => !izin.startsWith("select:");

console.log("hesap           | etkin | gereken | fazla | fazla yazici izin");
console.log("----------------|-------|---------|-------|------------------");
for (const hesap of Object.keys(HESAP_ROL)) {
  const etkin = hesapIzinleri(hesap);
  const gereken = new Set(GEREKEN[hesap]);
  const fazla = [...etkin].filter((i) => !gereken.has(i)).sort();
  console.log(
    hesap.padEnd(15) + " | " +
    String(etkin.size).padStart(5) + " | " +
    String(gereken.size).padStart(7) + " | " +
    String(fazla.length).padStart(5) + " | " +
    fazla.filter(yaziciMi).join(", ")
  );
}
EOF
node yetki.mjs
hesap           | etkin | gereken | fazla | fazla yazici izin
----------------|-------|---------|-------|------------------
odunc_masasi    |     6 |       5 |     1 | 
katalog_ekibi   |     5 |       3 |     2 | delete:kitap
rapor_araci     |     6 |       2 |     4 | insert:odunc, update:odunc
bakim_hesabi    |    12 |       4 |     8 | delete:kitap, delete:odunc, delete:uye, insert:kitap, insert:odunc, update:kitap, update:odunc

Tablo dört ayrı sorunu aynı anda gösterir.

odunc_masasi bir izin fazlaya sahip ve o izin bir okuma iznidir (select:sube). Bu, en az yetki ilkesinin ihlalidir ama etkisi sınırlıdır; devralmadan gelen kaçınılmaz artıktır.

katalog_ekibi kitap silme iznine sahip, oysa gerekenler arasında silme yok. Katalog düzeltmesi yapan bir ekibin yanlışlıkla kayıt silmesi, sonradan onarılması pahalı bir kazadır.

rapor_araci durumu en açık olanıdır. Yalnız okuma yapması beklenen bir hesap, gorevli rolü üzerinden ödünç kaydı ekleme ve güncelleme iznine sahip. Bu, “uygun bir rol vardı, onu verdik” kararının tipik sonucudur: rol adı işi anlatıyordu ama izin kümesi işten genişti.

bakim_hesabi on iki izne sahip, dördü gerekli. Bakım hesabının geniş olması beklenir; sorun genişliği değil, o hesabın gündelik iş için kullanılmasıdır.

Salt Okunur Bağlantı

Yetki çizelgesi tek savunma katmanı değildir. İkinci katman bağlantı düzeyi kısıtıdır: bağlantı, yazma yeteneği olmadan açılır. Rapor aracının hangi rolü taşıdığından bağımsız olarak, bağlantısı salt okunur açılmışsa yazma denemesi bağlantı katmanında reddedilir.

rm -f kutuphane.db
sqlite3 kutuphane.db <<'SQL'
CREATE TABLE sube(id INTEGER PRIMARY KEY, ad TEXT NOT NULL);
INSERT INTO sube VALUES (1,'Merkez'),(2,'Sahil');
SQL

echo "--- salt okunur baglantidan yazma ---"
sqlite3 -readonly kutuphane.db "INSERT INTO sube VALUES (3,'Yeni');"
echo "cikis kodu: $?"

echo "--- ayni baglantidan okuma ---"
sqlite3 -readonly -box kutuphane.db "SELECT * FROM sube ORDER BY id;"
rm -f kutuphane.db
--- salt okunur baglantidan yazma ---
Error: stepping, attempt to write a readonly database (8)
cikis kodu: 8
--- ayni baglantidan okuma ---
┌────┬────────┐
│ id │   ad   │
├────┼────────┤
│ 1  │ Merkez │
│ 2  │ Sahil  │
└────┴────────┘

Buradaki -readonly seçeneği ve hata iletisinin sözcükleri bu motora özgüdür; sunucu tabanlı motorlarda karşılığı bir bağlantı parametresi ya da oturum ayarı olur. Ortak olan düzenek şudur: yazma yeteneği bağlantı açılırken kapatıldığında, yetki çizelgesindeki bir yanlışlık tek başına veri kaybına dönüşemez. İki katman birlikte bulunur; biri diğerinin yerine geçmez.

Hesapların Ayrılması

İşletimde üç hesap sınıfı birbirinden ayrı tutulur.

Uygulama hesabı gündelik işi yapar. Yalnız uygulamanın dokunduğu tablolar üzerinde, yalnız yaptığı eylemler için izin taşır. Şema değiştirme izni taşımaz — uygulama kodunun çalışma anında tablo yapısını değiştirmesi beklenmez.

Rapor hesabı yalnız okur. Ayrı bir hesap olmasının nedeni yalnız güvenlik değildir: ayrı hesap, yavaş bir rapor sorgusunun kaynak tükettiğini izleme tarafında ayırt edilebilir kılar. Bu ayrımın izleme değeri onuncu derste tekrar karşımıza çıkacak.

Bakım hesabı şema değişikliği, yedek alma ve kurtarma için kullanılır. Bu hesabın geniş olması işin gereğidir; disiplini, gündelik bağlantılarda kullanılmamasıdır. Uygulamanın bağlantı dizgisinde bakım hesabı yazıyorsa, uygulamadaki her kusur şema kaybına dönüşme yeteneği kazanır.

Ayrımın sınanabilir bir sonucu vardır: uygulama hesabıyla açılmış bir bağlantıda tablo silme denemesi yetki hatasıyla dönmelidir. Bu denemeyi bir kez elle yapmak, “izinleri verdik” cümlesini “izinleri doğruladık” cümlesine çevirir.

Yetkinin Zaman İçindeki Kayması

Yetki çizelgesi kurulduğu gün doğrudur; sonraki her ay biraz daha yanlıştır. Bir raporun geçici olarak bir tabloya daha erişmesi gerekir, izin verilir, rapor kaldırılır, izin kalır. Bu birikmeye yetki sürünmesi (privilege creep) denir ve tek çaresi düzenli denetimdir.

Denetimin somut biçimi yukarıdaki betiğin yaptığı şeydir: hesabın etkin izin kümesi çıkarılır, işin gerektirdiği kümeyle karşılaştırılır, fark listelenir. Farkın sıfır olması gerekmez — devralmadan gelen artık izinler kabul edilebilir. Gerekli olan, farkın bilinmesi ve yazıcı izinlerin fark listesinde bulunmamasıdır.

İkinci denetim sorusu erişim yollarıyla ilgilidir: yetki çizelgesi bir tabloyu kapatırken, o tablonun sütunlarını gösteren bir görünüm açık kalmış olabilir. Görünümler SQL Temelleri kursunda tanıtılmıştı; işletim tarafında görünüm, izin denetiminin atlanabildiği bir yol hâline gelmemelidir. Denetim, tablo listesini değil erişilebilir nesnelerin tamamını kapsar.

Özet

  • Kimlik doğrulama “kimsin”, yetkilendirme “ne yapabilirsin” sorusudur; motorlar ikisini ayrı katmanlarda denetler.
  • Rol tabanlı erişim denetimi izinleri kişiye değil göreve bağlar; görev değişikliğinde değişen tek şey rol ataması olur.
  • Rol devralması etkin izin kümesini yazıldığı yerde görünmez kılar; etkin küme, devralma zincirinin kapanışı alınarak hesaplanır.
  • En az yetki denetimi, etkin izin kümesi ile işin gerektirdiği kümenin farkını çıkarmaktır; fark listesinde yazıcı izin bulunmamalıdır.
  • Salt okunur bağlantı, yetki çizelgesinden bağımsız ikinci bir savunma katmanıdır.
  • Uygulama, rapor ve bakım hesapları ayrı tutulur; yetki sürünmesi düzenli denetimle karşılanır.

Sonraki Adım

Bu dersteki izinlerin tamamı nesne düzeyindeydi: bir hesap bir tabloyu ya okuyabiliyordu ya okuyamıyordu. Kütüphane örneğinde bu ayrım yetmez — Sahil şubesinin görevlisi ödünç tablosunu okuyabilmeli, ama yalnız kendi şubesinin satırlarını. Aynı tabloda farklı hesaplara farklı satır kümesi göstermek nesne düzeyi izinle ifade edilemez. Sonraki ders, satırın hangi koşulla görüneceğini bir politika ifadesiyle tanımlayan satır düzeyi güvenliği ele alıyor ve bir politikanın sızdırdığı satırların nasıl sayılacağını gösteriyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat