Ders 13 / 13
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.
Yayın Güncelleme
Bu derste
- 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
İçindekiler
Ö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.
# 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 belirtecidir. 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.
# guvenlik.rb — belirtec, kacislama ve sonuc satiri
require_relative "kalis"
def kacisla(metin) = metin.to_s.gsub("&", "&").gsub("<", "<").gsub(">", ">").gsub('"', """)
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.
# 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.
# 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.
# 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.
# 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.
# kacislama.rb — varsayilan kacislama
require_relative "guvenlik"
p kacisla("Tom & Jerry")
p kacisla("<b>kalem</b>")
"Tom & Jerry" "<b>kalem</b>"
Üç 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 listesidir: yalnız adı listede olan alanlar geçer.
# 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.
# 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?
# cift.rb — iki kez kacislama
require_relative "guvenlik"
p kacisla("<")
p kacisla(kacisla("<"))
"<" "&lt;"
İkinci kaçışlama ilk kaçışlamanın & karakterini de değiştirdi; sayfada < yerine < 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ışı oturumdur: 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
nilolarak 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("<"))"&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("<")) "&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.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.