---
title: 'Güvenlik Varsayılanları'
source: 'https://academia.sh/tr/kurslar/mvc-cercevesi/guvenlik-varsayilanlari'
course: 'Model–Görünüm–Denetleyici Çerçevesi'
language: tr
updated: '2026-10-21T05:03:41+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Sahtecilik belirtecinin kalışını ölçer ve oturumda tutulmasının nedenini gösterir'
    - 'Bir istemcinin belirtecinin başka bir istemcinin oturumunda geçersiz olduğunu gösterir'
    - 'Şablonda varsayılan kaçışlamayı ve aşırı atamaya karşı izin listesini küçük bir yardımcıyla ölçer'
    - 'Güvenli bir varsayılanın tek bir katmanda uygulanmasının, iki kez uygulanmasından farkını ölçer'
---

# Güvenlik Varsayılanları

Sahtecilik belirtecinin neden oturumda tutulduğunun, şablonda varsayılan kaçışlamanın ve aşırı atamaya karşı izin listesinin ölçümü; on üç dersin kalışlarının kapanış tablosu.

Önceki ders, testlerin birbirinden yalıtılmasını ölçtü. Bu ders kursun son uygulama hizmetini ele alır: bir uygulamanın kullanıcı adına hiçbir şey yapmadan da sunması gereken güvenlik varsayılanlarını. Üç tanesi seçildi: sahtecilik belirteci, şablonda kaçışlama ve aşırı atamaya karşı izin listesi. İlk ders sorusu, sahtecilik belirtecinin neden oturumda tutulduğudur.

Ölçü ekseni kursun başından beri aynıdır: **bu değer hangi isteğe kadar kalıyor?** Dört kalış: **bu istek**, **sonraki istek**, **oturum**, **kalıcı**. M12/K03'te sorulan soru başkaydı: bir sonucu kim değiştirebiliyor, sunucu, ortam, istemci ya da üçüncü taraf. Belirteç istemciye gider, formun içinde döner; ama bu sorunun cevabı belirtecin kalışını belirlemez. Kalışı oturumdur, çünkü yazıldığı yer oturumdur.

## Çekirdek

Ölçümler aynı küçük istek döngüsüne dayanır. Dosya kursun çekirdeğidir ve olduğu gibi verilir.

```ruby
# kalis.rb — kucuk bir istek dongusu ve bir degerin hangi istege kadar kaldigini siniflandiran yardimci

# Flash: bu istekte yazilan deger yalniz bir sonraki istege tasinir.
class Flash
  def initialize(gelen)
    @gelen = gelen
    @yeni = {}
  end

  def [](anahtar) = @yeni.fetch(anahtar) { @gelen[anahtar] }

  def []=(anahtar, deger)
    @yeni[anahtar] = deger
  end

  def birakilan = @yeni
end

# Her istek yeni bir baglam alir: params, flash ve istek deposu her istekte bostur.
class Baglam
  attr_reader :uygulama, :params, :oturum, :flash, :istek_deposu

  def initialize(uygulama, oturum)
    @uygulama = uygulama
    @params = {}
    @oturum = oturum
    @flash = Flash.new(oturum.delete(:flash) || {})
    @istek_deposu = {}
  end
end

# Uygulamanin deposu butun isteklerde ve butun istemcilerde aynidir;
# oturum istemciye gore secilir.
class Uygulama
  attr_reader :depo

  def initialize
    @oturumlar = Hash.new { |h, istemci| h[istemci] = {} }
    @depo = { urunler: {}, sema: { urunler: %i[ad fiyat] }, sablonlar: {},
              kuyruk: [], onbellek: {}, sayac: 0 }
  end

  def istek(istemci)
    baglam = Baglam.new(self, @oturumlar[istemci])
    sonuc = yield baglam
    baglam.oturum[:flash] = baglam.flash.birakilan unless baglam.flash.birakilan.empty?
    sonuc
  end
end

# Kural: istek 1'de (istemci A) deger yazilir; istek 2 ve 3 (A) ile istek 4 (B) okur.
# B goruyorsa kalici; A'nin ucuncu istegi goruyorsa oturum; yalniz ikinci istek
# goruyorsa sonraki; hicbiri gormuyorsa bu_istek.
def kalis(yaz, oku)
  uygulama = Uygulama.new
  ilk = uygulama.istek("A") { |b| yaz.call(b); oku.call(b) }
  raise ArgumentError, "deger yazildigi istekte okunamadi" if ilk.nil?

  gorulen = [["A", 2], ["A", 3], ["B", 4]].map do |istemci, sira|
    uygulama.istek(istemci) { |b| oku.call(b) }.nil? ? "--" : "#{istemci}#{sira}"
  end
  tur = if gorulen[2] != "--" then "kalici"
        elsif gorulen[1] != "--" then "oturum"
        elsif gorulen[0] != "--" then "sonraki"
        else "bu_istek"
        end
  [tur, ["A1", *gorulen].join(" "), ilk]
end
```

Bu blok kaynaktır; dosya diske yazılır ve `require_relative` ile çekilir. Çekirdek bir çerçeve değil, bir çerçevenin modelidir. Bir fark taşır: çekirdekteki `Urun.bul`, saklanan nesnenin kendisini döndürür; birçok eşleyicide her okuma, satırdan yeni bir nesne kurar. Bu dersteki ölçümler bu farka dayanmaz.

## Sahtecilik Belirteci

**Siteler arası istek sahteciliği (CSRF)**, başka bir sitenin, kullanıcının tarayıcısından kullanıcı adına bir istek göndermesidir. Savunma basittir: forma sunucunun ürettiği bir değer konur ve gönderilen değer sunucunun sakladığı değerle karşılaştırılır. Bu, **sahtecilik belirteci**dir. Bu derste ölçülen desende (senkronizasyon belirteci) karşılaştırmanın çalışması için sunucunun belirteci bir yerde saklaması gerekir; belirteci saklamayan durumsuz desenler de vardır, bu ders onları ölçmez. Nerede? Yazıldığı yer, belirtecin kalışını belirler. Kesit iki yardımcı ve bir sonuç satırı biçimi verir: belirteci üreten `csrf_belirteci`, metni kaçışlayan `kacisla` ve ölçüm satırını basan `goster`.

```ruby
# guvenlik.rb — belirtec, kacislama ve sonuc satiri
require_relative "kalis"

def kacisla(metin) = metin.to_s.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;").gsub('"', "&quot;")
def csrf_belirteci(b) = b.oturum[:csrf] ||= "belirtec-#{b.uygulama.depo[:sayac] += 1}"

def goster(ad, tur, kanit, deger)
  printf("%-16s%-14s%-13s%s\n", ad, tur, kanit, deger.inspect)
end
```

Bu blok da kaynaktır. `csrf_belirteci` oturumda bir değer varsa onu döndürür, yoksa üretip oturuma yazar. Ölçüm, belirteci ilk istekte üretir ve sonraki istekte oturumdan okur.

```ruby
# belirtec.rb — csrf belirteci hangi istege kadar kaliyor
require_relative "guvenlik"

yaz = ->(b) { csrf_belirteci(b) }
oku = ->(b) { b.oturum[:csrf] }
goster("csrf belirteci", *kalis(yaz, oku))
```
```
csrf belirteci  oturum        A1 A2 A3 --  "belirtec-1"
```

Belirteç A'nın üç isteğinde de göründü, B'nin isteğinde görünmedi. Bu **oturum** kalışıdır. Belirteç bir forma gider, ama sunucuda bir istemcinin oturumunda durur. Uygulamanın ortak deposunda olsaydı, kalıcı olurdu ve her istemci aynı değeri görürdü; o zaman bir istemcinin belirteci herkes için geçerli olurdu ve karşılaştırma bir şey kanıtlamazdı. **UY10.** Çekirdekte belirteç bir sayaçtan türer; gerçek bir belirteç tahmin edilemez olmalıdır. Bu ölçüm yalnız kalışı ölçer, üretimin güvenliğini değil.

Belirteç oturumla birlikte gider. Oturumdaki belirteç silinirse sonraki istek yeni bir belirteç üretir; eskisi artık sunucuda yoktur. Ölçümde A belirteç alır, oturumundaki belirteç silinir ve A yeniden belirteç ister; B de kendi belirtecini ister.

```ruby
# yenileme.rb — oturumdaki belirtec silinince ne olur
require_relative "guvenlik"

uygulama = Uygulama.new
ilk = uygulama.istek("A") { |b| csrf_belirteci(b) }
uygulama.istek("A") { |b| b.oturum.delete(:csrf) }
yeni = uygulama.istek("A") { |b| csrf_belirteci(b) }
baska = uygulama.istek("B") { |b| csrf_belirteci(b) }
p [ilk, yeni, baska]
```
```
["belirtec-1", "belirtec-2", "belirtec-3"]
```

Her yeni belirteç ayrı bir değer aldı ve sayaç istemciler arasında ortak olduğu için B'nin belirteci A'nınkilerden farklı çıktı. Belirteç oturumda durduğu sürece vardır; oturumdan silinen belirteç sunucuda yoktur, bu yüzden eski değerle gelen istek karşılaştırmada eşleşmez (bu ölçümde denenmedi).

## Bir İstemcinin Belirteci Ötekinde Geçer mi?

Kalışın sonucu, istemcilere göre ayrışmasıdır. Aynı uygulamada A, B ve yeniden A istek yapar; her biri kendi oturumundaki belirteci ister.

```ruby
# istemciler.rb — A, B, A sirasiyla belirtec
require_relative "guvenlik"

uygulama = Uygulama.new
a1 = uygulama.istek("A") { |b| csrf_belirteci(b) }
b1 = uygulama.istek("B") { |b| csrf_belirteci(b) }
a2 = uygulama.istek("A") { |b| csrf_belirteci(b) }
puts [a1, b1, a2].inspect
```
```
["belirtec-1", "belirtec-2", "belirtec-1"]
```

A'nın ikinci isteği ilk belirteci aldı; B ayrı bir tane. Şimdi karşılaştırmayı da ekleyelim: gönderilen değer, oturumdaki değerle eşleşiyorsa istek kabul edilir.

```ruby
# karsilastir.rb — gonderilen belirtec oturumdakiyle eslesiyor mu
require_relative "guvenlik"

def csrf_gecerli?(b, gonderilen) = !gonderilen.nil? && gonderilen == b.oturum[:csrf]

uygulama = Uygulama.new
formdaki = uygulama.istek("A") { |b| csrf_belirteci(b) }
uygulama.istek("B") { |b| csrf_belirteci(b) }
p uygulama.istek("A") { |b| csrf_gecerli?(b, formdaki) }
p uygulama.istek("B") { |b| csrf_gecerli?(b, formdaki) }
p uygulama.istek("A") { |b| csrf_gecerli?(b, nil) }
```
```
true
false
false
```

A'nın kendi belirteci A'nın oturumunda geçerli. Aynı değer B'nin oturumunda geçersiz, ve hiç belirteç göndermeyen istek de geçersiz. Başka bir sitenin forma koyabileceği geçerli bir değer yoktur: belirteç yalnız bu istemcinin oturumuna bağlıdır. **UY11.** Burada karşılaştırma düz eşitliktir; gerçek bir uygulama sabit sürede karşılaştırır ve belirteci her formda yenileyebilir. Bunlar ölçülmedi.

## Şablonda Varsayılan Kaçışlama

İkinci varsayılan Görünümler dersinde ölçüldü: şablon, yerel değerleri yerleştirirken `kacisla`'dan geçirir. Kullanıcının yazdığı metin sayfada işaretleme olarak değil, metin olarak görünür. Güvenli davranış varsayılandır; kaçışlamayı kapatmak ayrıca istenmelidir. Aynı yardımcıyı zararsız bir biçimlemeyle ölçelim.

```ruby
# kacislama.rb — varsayilan kacislama
require_relative "guvenlik"

p kacisla("Tom & Jerry")
p kacisla("<b>kalem</b>")
```
```
"Tom &amp; Jerry"
"&lt;b&gt;kalem&lt;/b&gt;"
```

Üç karakter karşılıklarına döndü. Bu ölçüm yalnız bu üç karakteri kapsar. Yardımcının tanımı çift tırnağı da çevirir; bu ölçüm onu göstermedi. Tek tırnak tanımda yer almaz. **UY12.** Gerçek bir görünüm katmanı başka bağlamları, örneğin bir bağlantının adresini ya da bir yazı dosyasının içini ayrıca ele alır; çekirdek bunları modellemez.

## Aşırı Atamaya Karşı İzin Listesi

Üçüncü varsayılan, bir formdan gelen alanların kayda doğrudan yazılmasını engeller. Formda yalnız `ad` ve `fiyat` varsa bile, istek fazladan bir alan taşıyabilir. Kayıt tüm alanları alırsa istemci, formda olmayan bir alanı da yazar. Buna **aşırı atama (mass assignment)** denir. Savunma bir **izin listesi**dir: yalnız adı listede olan alanlar geçer.

```ruby
# izin.rb — izin listesi
require_relative "guvenlik"

def izinli(params, *anahtarlar) = params.slice(*anahtarlar)

gelen = { ad: "kalem", fiyat: 12, yonetici: true }
p izinli(gelen, :ad, :fiyat)
```
```
{ad: "kalem", fiyat: 12}
```

`yonetici` alanı sonuca girmedi. İzin listesi bir yasak listesi değildir: listede olmayan her şey, yarın eklenen bir alan da dahil, otomatik olarak dışarıda kalır. **UY13.** Yardımcı yalnız tek düzeyli bir hash'i süzer; iç içe alanlar için ayrı bir kural gerekir ve bu derste yazılmadı.

Listede adı geçen bir alan istekte yoksa ne olur? Yardımcıyı `fiyat` alanı olmayan bir istekle çağıralım.

```ruby
# eksik.rb — listede olup istekte olmayan alan
require_relative "guvenlik"

def izinli(params, *anahtarlar) = params.slice(*anahtarlar)

p izinli({ ad: "kalem" }, :ad, :fiyat)
p izinli({ ad: "kalem" }, :ad, :fiyat).key?(:fiyat)
```
```
{ad: "kalem"}
false
```

Eksik alan sonuçta `nil` değeriyle değil, hiç bulunmayarak yer aldı. İzin listesi bir alanı zorunlu kılmaz; yalnız geçebilecek alanların sınırını çizer. Bir alanın bulunmasını gerektiren denetim ayrı bir kuraldır ve Veri Katmanı konusunda doğrulama olarak ölçüldü.

## Sınırlayıcı Ölçüm

Güvenli bir varsayılan yalnız bir kez ve doğru katmanda uygulanmalıdır. İki kez uygulanırsa güvenlik artmaz, çıktı bozulur. Aynı metin iki kez kaçışlanırsa ne olur?

```ruby
# cift.rb — iki kez kacislama
require_relative "guvenlik"

p kacisla("<")
p kacisla(kacisla("<"))
```
```
"&lt;"
"&amp;lt;"
```

İkinci kaçışlama ilk kaçışlamanın `&` karakterini de değiştirdi; sayfada `<` yerine `&lt;` görünür. Güvenlik varsayılanı bu yüzden tek katmanda durur: şablon kaçışlar, denetleyici kaçışlamaz, kayıt kaçışlanmış hâliyle saklanmaz. Bir değer hangi katmanda kaçışlanacaksa, o katmandan sonra bir daha dokunulmaz. Kısmi şablonlarda da aynı kural geçerlidir; Görünümler dersinde bu bozulma ölçülmüştü.

## Özet

- Sahtecilik belirteci istemciye gider ama kalışı **oturum**dur: aynı istemcinin üç isteğinde görünür, başka istemcide görünmez.
- A, B, A sırasıyla istek yapan istemciler `"belirtec-1"`, `"belirtec-2"`, `"belirtec-1"` aldı; bir istemcinin belirteci ötekinin oturumunda geçersizdir.
- Şablonda varsayılan kaçışlama, kullanıcı metnini sayfada metin olarak gösterir.
- İzin listesi, formda olmayan alanı kayda yazmaz.
- Aşırı atama izin listesiyle kapanır: eksik alan `nil` olarak değil, hiç bulunmaz; liste yasak listesi değildir, listede olmayan her alan dışarıda kalır.
- Güvenli bir varsayılan tek katmanda uygulanır: `kacisla(kacisla("<"))` `"&amp;lt;"` verir.

## Kurs Kapanışı

Kursun her dersi aynı soruyu sordu: bu değer hangi isteğe kadar kalıyor? On üç ölçüm, bu soruyu bir gözlemle yanıtladı. Aşağıdaki tablo hepsini kalışına göre toplar.

| Ders | Ölçülen değer | Kalış | Sınırlayıcı ölçüm |
| --- | --- | --- | --- |
| Yapılandırma Yerine Sözleşme | `sablon adi` | bu istek | ad üretilir, şablonun varlığı denetlenmez |
| Yönlendirme | `yol parametresi` | bu istek | değeri sonraki isteğe istemci taşır |
| Denetleyiciler ve Filtreler | `flash` | sonraki istek | her istekte yeniden yazılan flash oturumda görünür |
| Görünümler ve Şablonlar | `derlenen sablon` | kalıcı | ikinci derleme eskisini korur |
| Nesne–Tablo Bağlaması | `kayit` | kalıcı | model saklanan nesnenin kendisini döndürür |
| Göçler | `sema sutunu` | kalıcı | eski satırda yeni sütun yoktur |
| İlişkiler ve Doğrulamalar | `dogrulama hatasi` | bu istek | hata kayıtla saklanmaz |
| Sorgu Arayüzü ve N+1 Sorunu | `sorgu onbellegi` | bu istek | `nil` sonucu da saklanır |
| Kimlik Doğrulama ve Yetkilendirme | `kullanici kimligi` | oturum | yazıldığı istekte okunamayan değer `ArgumentError` verir |
| Arka Plan İşleri | `kuyruktaki is` | kalıcı | sonuç yazıldığı yere bağlıdır |
| Önbellekleme | `parca onbellegi` | kalıcı | anahtar değişmedikçe bayat kalır |
| Test | `denetleyici degiskeni` | bu istek | paylaşılan uygulama testler arası sızıntı yapar |
| Güvenlik Varsayılanları | `csrf belirteci` | oturum | `kacisla(kacisla("<"))` `"&amp;lt;"` verir |

Kalışların dağılımı: **5 bu istek · 1 sonraki istek · 2 oturum · 5 kalıcı**. Tablo kursun bir bulgusunu taşır: kalış bir değerin türüne değil, yazıldığı yere ve okuyan kodun davranışına bağlıdır. Aynı ad iki kalışı gizleyebilir: sorgu önbelleği bu istek, parça önbelleği kalıcı oldu; aynı flash her istekte yeniden yazılınca oturuma döndü.

İki çıkarım yapılabilir. Birincisi, kalıcı olan beş değerin hepsi uygulamanın ortak deposunda durur ve istemcileri ayırmaz; bu yüzden her biri bir sınır taşıdı. İkincisi, oturum ve sonraki istek kalışları istemciye bağlıdır; bunlar yazıldığı istemcinin dışında görünmez.

**UY14.** Tablo yalnız on üç ölçümün sınıflandırmasıdır; dağılım ölçülen değerlerin seçimini yansıtır, bir uygulamadaki bütün değerlerin dağılımını değil. Kalış hücreleri her dersin Özet bölümündeki ifadeden alındı.

Çekirdek model burada da bir gerçeği taşıdı: `Urun.bul` saklanan nesnenin kendisini döndürür, birçok eşleyicide her okuma, satırdan yeni bir nesne kurar. Tablo bu yüzden bir çerçevenin davranışı değil, çerçevenin modelinin davranışıdır.

Kurs burada kapanır. Sıradaki kurs, bir Ruby projesini oluşturan paketleri, bağımlılık yönetimini ve geliştirme araçlarını ele alır. Orada da aynı kural geçerli kalır: tahmin yürütülmez, ölçülür.
