CSRF önleme belirteçlerini çerezlere koymak neden yaygındır?


284

CSRF ile ilgili tüm sorunu ve bunu önlemek için uygun yolları anlamaya çalışıyorum. (Okuduğum, anladığım ve kabul ettiğim kaynaklar: OWASP CSRF Önleme Hile Sayfası , CSRF hakkında sorular .)

Anladığım kadarıyla, CSRF çevresindeki güvenlik açığı, (web sunucusunun bakış açısından) gelen bir HTTP isteğindeki geçerli bir oturum çerezinin kimliği doğrulanmış bir kullanıcının isteklerini yansıttığı varsayımı ile ortaya çıkar. Ancak, kaynak etki alanı için tüm çerezler tarayıcı tarafından isteğe sihirli bir şekilde eklenir, bu nedenle gerçekten tüm sunucu, bir istekte geçerli bir oturum çerezi varlığından çıkarım yapabilir, isteğin kimliği doğrulanmış bir oturumu olan bir tarayıcıdan gelmesi; kod hakkında başka bir şey üstlenemeztarayıcıda çalıştığını veya kullanıcının isteklerini gerçekten yansıtıp yansıtmadığını gösterir. Bunu önlemenin yolu, tarayıcıya otomatik çerez işleme dışında bazı yollarla taşınan isteğe ek kimlik doğrulama bilgilerini ("CSRF jetonu") dahil etmektir. Daha sonra, oturum çerezi kullanıcının / tarayıcının kimliğini ve CSRF jetonu tarayıcıda çalışan kodu doğrular.

Özetle, web uygulamanızdaki kullanıcıların kimliğini doğrulamak için bir oturum çerezi kullanıyorsanız, her yanıta bir CSRF jetonu eklemeniz ve her (mutasyona uğrayan) istekte eşleşen bir CSRF jetonu eklemeniz gerekir. CSRF jetonu daha sonra sunucudan tarayıcıya sunucuya geri dönüş yapar ve sunucuya istekte bulunan sayfanın o sunucu tarafından onaylandığını (hatta oluşturduğunu) kanıtlar.

Benim sorum, hangi gidiş-dönüş o CSRF jetonu için kullanılan belirli taşıma yöntemi hakkında.

CSRF jetonunu sunucudan istemciye bir çerez olarak (yani bir Set-Cookie başlığında) göndermek ve istemcide Javascript'in çerezden kazıması ve eklemek için yaygın (ör. AngularJS , Django , Rails ) ayrı bir XSRF-TOKEN üstbilgisi olarak sunucuya geri göndermek için.

(Alternatif bir yöntem, örneğin Express tarafından önerilen yöntemdir , burada sunucu tarafından oluşturulan CSRF belirteci, sunucuya geri gönderecek koda / biçimlendirmeye doğrudan eklenmiş olan sunucu tarafı şablon genişletme yoluyla yanıt gövdesine eklenir; Bu örnek, bir şeyler yapmanın daha web 1.0-ish yoludur, ancak daha fazla JS-ağır bir istemciye genelleme yapar.)

Set-Cookie'yi CSRF jetonu için aşağı yönlü taşıma olarak kullanmak neden bu kadar yaygındır / bu neden iyi bir fikirdir? Tüm bu çerçevelerin yazarlarının seçeneklerini dikkatlice düşündüklerini ve bunu yanlış anlamadıklarını düşünüyorum. Ancak ilk bakışta, tanımlama bilgilerini temel olarak tanımlamalardaki tasarım sınırlamasının ne olduğunu bulmak için çerezleri kullanmak oldukça zordur. Aslında, gidiş-dönüş aktarımı olarak çerezleri kullandıysanız (sunucunun tarayıcıya CSRF jetonunu bildirmesi için Set-Cookie: başlık akış aşağısı ve tarayıcının sunucuya döndürmesi için yukarı yönlü Cookie: başlık) düzeltmeye çalışıyorlar.

Yukarıdaki çerçevelerin CSRF jetonu için tüm gidiş-dönüş için çerezleri kullanmadığının farkındayım; akış aşağısında Set-Cookie kullanırlar, daha sonra başka bir şey (örneğin, bir X-CSRF-Token başlığı) kullanırlar ve bu, güvenlik açığını kapatır. Ancak Set-Cookie'yi aşağı akım taşımacılığı olarak kullanmak bile yanıltıcı ve tehlikelidir; tarayıcı artık CSRF jetonunu orijinal kötü amaçlı XSRF istekleri dahil olmak üzere her isteğe ekleyecektir; en iyisi, isteği olması gerekenden daha büyük yapar ve en kötüsü de bazı iyi niyetli ama yanlış yönlendirilmiş bir sunucu kodu parçası gerçekten çok kötü olurdu. Ayrıca, CSRF jetonunun gerçek amaçlanan alıcısı istemci tarafı Javascript olduğundan, bu çerez sadece http ile korunamaz demektir.


Doğru yere çarpmak harika bir soru.
kta

Yanıtlar:


263

Bir çeşit dokunduğunuzun iyi bir nedeni, CSRF çerezi alındıktan sonra, hem normal formlarda hem de AJAX POST'larında kullanılmak üzere istemci komut dosyasında uygulama boyunca kullanıma hazır olmasıdır. Bu, AngularJS tarafından kullanılan gibi JavaScript ağır bir uygulamada anlamlı olacaktır (AngularJS kullanmak uygulamanın tek sayfa uygulaması olmasını gerektirmez, bu nedenle durumun CSRF değerinin olduğu farklı sayfa istekleri arasında akması gerektiğinde yararlı olacaktır tarayıcıda normal olarak devam edemez).

Tanımladığınız her yaklaşımın bazı artıları ve eksileri için tipik bir uygulamada aşağıdaki senaryoları ve süreçleri göz önünde bulundurun. Bunlar Senkronize Edici Jetonu Desenini temel alır .

Beden Yaklaşımı İste

  1. Kullanıcı başarıyla giriş yapıyor.
  2. Sunucu kimlik doğrulama çerezi yayınlar.
  3. Kullanıcı bir forma gitmek için tıklar.
  4. Bu oturum için henüz oluşturulmamışsa, sunucu CSRF jetonu oluşturur, kullanıcı oturumunda saklar ve gizli bir alana gönderir.
  5. Kullanıcı formu gönderir.
  6. Sunucu, gizli alanı oturum saklanan belirteciyle eşleştirir.

Avantajları:

  • Uygulaması basit.
  • AJAX ile çalışır.
  • Formlarla çalışır.
  • Çerez aslında sadece HTTP olabilir .

Dezavantajları:

  • Tüm formlar gizli alanın HTML biçiminde çıktısını almalıdır.
  • Herhangi bir AJAX POST değeri de değeri içermelidir.
  • Sayfa önceden CSRF jetonunu gerektirdiğini bilmelidir, böylece sayfa içeriğine ekleyebilir, böylece tüm sayfalar bir yerde jeton değerini içermelidir, bu da büyük bir siteye uygulanması zaman alıcı olabilir.

Özel HTTP Üstbilgisi (akış aşağı)

  1. Kullanıcı başarıyla giriş yapıyor.
  2. Sunucu kimlik doğrulama çerezi yayınlar.
  3. Kullanıcı bir forma gitmek için tıklar.
  4. Sayfa tarayıcıya yüklenir, ardından CSRF jetonunu almak için bir AJAX isteği yapılır.
  5. Sunucu (oturum için önceden oluşturulmamışsa) CSRF jetonu oluşturur, kullanıcı oturumunda saklar ve bir üstbilgiye gönderir.
  6. Kullanıcı formu gönderir (jeton gizli alan aracılığıyla gönderilir).
  7. Sunucu, gizli alanı oturum saklanan belirteciyle eşleştirir.

Avantajları:

Dezavantajları:

  • Başlık değerini almak için AJAX isteği olmadan çalışmaz.
  • Tüm formlar, HTML'sine dinamik olarak eklenen değere sahip olmalıdır.
  • Herhangi bir AJAX POST değeri de değeri içermelidir.
  • Sayfa, önce CSRF jetonunu almak için bir AJAX isteği yapmalıdır, bu nedenle her seferinde ekstra bir gidiş dönüş anlamına gelecektir.
  • Ayrıca, jetonu ekstra isteği kaydedecek olan sayfaya çıktı vermiş olabilir.

Özel HTTP Üstbilgisi (yukarı akış)

  1. Kullanıcı başarıyla giriş yapıyor.
  2. Sunucu kimlik doğrulama çerezi yayınlar.
  3. Kullanıcı bir forma gitmek için tıklar.
  4. Bu oturum için henüz oluşturulmamışsa, sunucu CSRF jetonu oluşturur, kullanıcı oturumunda saklar ve bir yerde sayfa içeriğinde çıkarır.
  5. Kullanıcı formu AJAX aracılığıyla gönderir (simge başlık üzerinden gönderilir).
  6. Sunucu, özel üstbilgi oturum depolanmış belirteciyle eşleşir.

Avantajları:

Dezavantajları:

  • Formlarla çalışmaz.
  • Tüm AJAX POST'ları başlık içermelidir.

Özel HTTP Üstbilgisi (akış yukarı ve akış aşağı)

  1. Kullanıcı başarıyla giriş yapıyor.
  2. Sunucu kimlik doğrulama çerezi yayınlar.
  3. Kullanıcı bir forma gitmek için tıklar.
  4. Sayfa tarayıcıya yüklenir, ardından CSRF jetonunu almak için bir AJAX isteği yapılır.
  5. Sunucu (oturum için önceden oluşturulmamışsa) CSRF jetonu oluşturur, kullanıcı oturumunda saklar ve bir üstbilgiye gönderir.
  6. Kullanıcı formu AJAX aracılığıyla gönderir (simge başlık üzerinden gönderilir).
  7. Sunucu, özel üstbilgi oturum depolanmış belirteciyle eşleşir.

Avantajları:

Dezavantajları:

  • Formlarla çalışmaz.
  • Tüm AJAX POST'ları da değeri içermelidir.
  • CRSF jetonunu almak için sayfa önce bir AJAX isteğinde bulunmalıdır, bu nedenle her seferinde ekstra bir gidiş dönüş anlamına gelir.

Set-Cookie

  1. Kullanıcı başarıyla giriş yapıyor.
  2. Sunucu kimlik doğrulama çerezi yayınlar.
  3. Kullanıcı bir forma gitmek için tıklar.
  4. Sunucu CSRF jetonu oluşturur, kullanıcı oturumunda saklar ve bir çereze çıkarır.
  5. Kullanıcı AJAX veya HTML formu aracılığıyla form gönderir.
  6. Sunucu, özel üstbilginin (veya gizli form alanının) oturum saklanan belirteciyle eşleşip eşleşmediğini denetler.
  7. Çerez tarayıcıda CSRF jetonunu almak için sunucuya ek talepler olmadan ek AJAX ve form isteklerinde kullanılabilir.

Avantajları:

  • Uygulaması basit.
  • AJAX ile çalışır.
  • Formlarla çalışır.
  • Çerez değerini almak için mutlaka AJAX isteği gerektirmez. Herhangi bir HTTP isteği isteği alabilir ve JavaScript aracılığıyla tüm formlara / AJAX isteklerine eklenebilir.
  • CSRF jetonu alındıktan sonra, bir çerezde saklandığından, değer ek istekler olmadan yeniden kullanılabilir.

Dezavantajları:

  • Tüm formlar, HTML'sine dinamik olarak eklenen değere sahip olmalıdır.
  • Herhangi bir AJAX POST değeri de değeri içermelidir.
  • Çerez, istek boyutunu artıran her istek (yani, CSRF sürecine dahil olmayan görüntüler, CSS, JS vb. İçin tüm GET'ler) için gönderilir.
  • Çerez Yalnızca HTTP olamaz .

Bu nedenle, çerez yaklaşımı, çerez değerini (herhangi bir HTTP isteği) almak ve kullanmak için kolay bir yol sunan oldukça dinamiktir (JS, değeri herhangi bir forma otomatik olarak ekleyebilir ve AJAX isteklerinde üstbilgi veya form değeri). Oturum için CSRF jetonu alındıktan sonra, CSRF sömürüsü kullanan bir saldırganın bu jetonu almak için bir yöntemi olmadığından, onu yeniden oluşturmaya gerek yoktur. Kötü amaçlı bir kullanıcı, yukarıdaki yöntemlerden herhangi birinde kullanıcının CSRF jetonunu okumaya çalışırsa, aynı Kaynak İlkesi tarafından engellenir . Kötü amaçlı bir kullanıcı CSRF belirteci sunucu tarafını almaya çalışırsa (ör.curl) bu belirteç, kurbanın kimlik doğrulama oturumu çerezi istekte bulunmayacağı için aynı kullanıcı hesabıyla ilişkilendirilmez (saldırgan olur - bu nedenle sunucu tarafı kurbanın oturumuyla ilişkilendirilmez).

Yanı sıra Synchronizer Jetonu Kalıbı da var Çift Gönder KurabiyeElbette bir tür CSRF jetonunu saklamak için çerezleri kullanan CSRF önleme yöntemi. CSRF jetonu için herhangi bir sunucu tarafı durumu gerektirmediği için bu uygulama daha kolaydır. CSRF jetonu aslında bu yöntemi kullanırken standart kimlik doğrulama çerezi olabilir ve bu değer istekle her zamanki gibi çerezler aracılığıyla gönderilir, ancak değer aynı zamanda bir saldırganın ilk etapta değeri okuyamazlar. Bununla birlikte, kimlik doğrulama çerezinin HttpOnly olarak işaretlenerek güvence altına alınabilmesi için kimlik doğrulama çerezinden başka bir çerez seçilmesi önerilir. Bu, çerez tabanlı bir yöntem kullanarak CSRF önleme yönteminin bulunmasının bir başka yaygın nedenidir.


7
Ben nasıl "CSRF belirteci almak için AJAX isteği yapıldığını" emin değilim (her iki "özel başlık: aşağı akış" bölümlerinde adım 4) güvenli bir şekilde yapılabilir; bu ayrı bir istek olduğundan, sunucu kimden geldiğini bilmez; CSRF jetonunu ifşa etmenin güvenli olduğunu nasıl bilebilir? Jetonu ilk sayfa yükünden çıkaramazsanız kaybedersiniz (maalesef özel aşağı akış yanıt başlığını bir başlangıç ​​yapmaz).
metamatt

6
Çünkü sahtecinin oturum çerezi olmayacak. Kendi oturum tanımlama bilgilerine sahip olabilirler, ancak CSRF jetonu bir oturumla ilişkili olduğundan, CSRF jetonları kurbanınkilerle eşleşmez.
SilverlightFox

32
CSRF saldırısı anlayışıma olarak, sahtekâr var benim oturum tanımlama. Aslında, çerezi göremiyorlar , ancak sahte isteklerinde sunabiliyorlar, çünkü istekler tarayıcımdan geliyor ve tarayıcım oturum çerezimi sağlıyor. Dolayısıyla, sunucunun bakış açısından, oturum çerezi meşru bir talebi sahte bir istekten ayırt edemez. Bu aslında önlemeye çalıştığımız saldırı. BTW, özellikle bu konuda kafam karışırsa, bu konudaki konuşmadaki sabrınız için teşekkür ederiz.
metamatt

8
Kimlik doğrulama çerezini sağlama yeteneğine sahiptirler, ancak CSRF jetonunu içeren yanıtı okuyamazlar.
SilverlightFox

8
@metamatt Nekro için özür dilerim, ama bunu dolaşan insanlar için yapacağım. Anladığım kadarıyla saldırganın genellikle yanıta erişimi yok. CSRF, doğrudan veri toplamak yerine , öncelikle yan etkilere neden olmak için kullanılır . Örneğin, bir CSRF saldırı komut dosyası, ayrıcalıklı bir kullanıcıyı saldırganın ayrıcalıklarını artırmaya, bir güvenlik ayarını devre dışı bırakmaya veya oturum açmış bir paypal kullanıcısını belirli bir e-posta adresine aktarım göndermeye zorlayabilir. Bu durumların hiçbirinde, saldırgan hala mağdurun tarayıcısına gönderilen yanıtı önemsemez; sadece saldırının sonucu.
jonathanbruder

61

CSRF jetonunu istemciye sağlamak için çerez kullanmak başarılı bir saldırıya izin vermez çünkü saldırgan çerezin değerini okuyamaz ve bu nedenle sunucu tarafı CSRF doğrulamasının gerektirdiği yere koyamaz.

Saldırgan, istek üstbilgilerinde hem kimlik doğrulama çerezi hem de CSRF çerezi olan bir istekte bulunabilecektir. Ancak sunucu, CSRF jetonunu istek başlıklarında bir çerez olarak aramıyor, isteğin yükünü arıyor. Saldırgan, CSRF jetonunu yüke nereye koyacağını bilse bile, oraya koymak için değerini okuması gerekir. Ancak tarayıcının çapraz kaynak politikası, hedef web sitesinden herhangi bir çerez değerinin okunmasını engeller.

Aynı mantık kimlik doğrulama çerezi için geçerli değildir, çünkü sunucu istek başlıklarında bekler ve saldırgan oraya koymak için özel bir şey yapmak zorunda değildir.


Elbette, bir saldırganın ilk önce çerezi okumasına gerek yoktur. src='bank.com/transfer?to=hacker&amount=1000Tarayıcının isteyeceği saldırıya uğramış siteye, o siteyle ilişkili çerezlerle birlikte bir resim ekleyebilirler ( bank.com)?
developius

2
CSRF, kullanıcıyı istemci tarafında doğrulamak içindir ve siteyi önerdiğiniz gibi genellikle sunucu tarafı güvenliğinden korumak için değildir.
17'de Tongfa

2
@developius çerez gönderme CSRF korumasını karşılamak için yeterli değildir. Çerez, sunucu tarafından gönderilen csrf jetonunu içerir. Meşru müşteri, çerezden csrf jetonunu okumalı ve daha sonra istekte başlık veya yük gibi bir yere iletmelidir. CSRF koruması, çerezdeki değerin istekteki değerle eşleşip eşleşmediğini denetler, aksi takdirde istek reddedilir. Bu nedenle, saldırganın çerezi okuması gerekir.
Will

1
Bu cevap asıl posterin sorusu için çok önemliydi ve çok açıktı. +1 Teşekkürler.
java-addict301

@Tongfa - teşekkürler, bu daha iyi anlamama yardımcı oldu. CSRF Jetonunun başlığa yerleştirilmemesi gerektiğini varsayabilir miyim? vücudun bir yerinde olmalı?
zerohedge

10

Cevapla ilgili en iyi tahminim: CSRF jetonunu sunucudan tarayıcıya nasıl indireceğinizi öğrenmek için bu 3 seçeneği göz önünde bulundurun.

  1. İstek gövdesinde (HTTP üstbilgisi değil).
  2. Özel bir HTTP başlığında, Set-Cookie değil.
  3. Bir çerez olarak, bir Set-Cookie başlığında.

Bence birincisi, istek gövdesi ( soruya bağladığım Express öğreticisi tarafından gösterilmiş olsa da ), çok çeşitli durumlar için taşınabilir değildir; herkes her HTTP yanıtını dinamik olarak üretmez; jetonu oluşturulan yanıta koymanız gerektiğinde (gizli bir form girişinde; JS kodunun bir parçasında veya diğer JS kodu tarafından erişilebilen bir değişkende; belki de bir URL'de bile, genellikle kötü bir yer gibi görünebilir) CSRF jetonları koymak için). Bu nedenle, bazı özelleştirmelerle uygulanabilir olsa da, # 1, tek bedene uyan bir yaklaşım yapmak için zor bir yerdir.

İkincisi, özel üstbilgi çekici ancak aslında çalışmıyor, çünkü JS çağrılan bir XHR için üstbilgileri alabilirken, yüklendiği sayfanın üstbilgilerini alamaz .

Bu, her durumda kullanımı kolay bir yaklaşım olarak Set-Cookie başlığı tarafından taşınan bir çerez olan üçüncü olanı bırakır (herkesin sunucusu istek başına çerez başlıklarını ayarlayabilecektir ve ne tür veriler istek gövdesindedir). Dezavantajlarına rağmen, çerçevelerin yaygın olarak uygulanması en kolay yöntemdi.


7
Açıkça belirtiyor olabilirim, bu çerez httponly doğru olamaz anlamına mı geliyor?
Foton

1
yalnızca ajax istekleri için (burada JS ikinci kanaldaki bir sonraki istekte (form verisi veya başlık olarak) yeniden göndermek için csrf çerezinin değerini bilmelidir). Oturum çerezi zaten HttpOnly ise (XSS'ye karşı korumak için) csrf jetonunun HttpOnly olmasını zorunlu kılmak için hiçbir neden yoktur çünkü csrf jetonu ilişkili oturum olmadan tek başına değerli değildir.
cowbert

2

(Bu bir tür standart olan) oturum çerezinin yanı sıra, ekstra çerezler kullanmak istemiyorum.

Birçok AJAX isteği ile Tek Sayfa Web Uygulaması (SPA) oluştururken benim için çalışan bir çözüm buldum. Not: Sunucu tarafı Java ve istemci tarafı JQuery kullanıyorum, ancak sihirli şeyler yok, bu yüzden bu ilkenin tüm popüler programlama dillerinde uygulanabileceğini düşünüyorum.

Fazladan çerez içermeyen çözümüm basit:

Müşteri Tarafı

Başarılı bir girişten sonra sunucu tarafından döndürülen CSRF jetonunu global bir değişkende saklayın (eğer elbette küresel bir web yerine web depolamasını kullanmak istiyorsanız). JQuery'ye her AJAX çağrısında bir X-CSRF-TOKEN başlığı sağlaması talimatını verin.

Ana "dizin" sayfası bu JavaScript snippet'ini içerir:

// Intialize global variable CSRF_TOKEN to empty sting. 
// This variable is set after a succesful login
window.CSRF_TOKEN = '';

// the supplied callback to .ajaxSend() is called before an Ajax request is sent
$( document ).ajaxSend( function( event, jqXHR ) {
    jqXHR.setRequestHeader('X-CSRF-TOKEN', window.CSRF_TOKEN);
}); 

Sunucu Tarafı

Başarılı bir girişte rastgele (ve yeterince uzun) bir CSRF jetonu oluşturun, bunu sunucu tarafı oturumunda saklayın ve istemciye geri gönderin. X-CSRF-TOKEN başlık değerini oturumda depolanan değerle karşılaştırarak belirli (hassas) gelen istekleri filtreleyin: bunlar eşleşmelidir.

Hassas AJAX çağrıları (POST form verileri ve GET JSON verileri) ve onları yakalayan sunucu tarafı filtresi / dataservice / * yolu altındadır. Giriş istekleri filtreye ulaşmamalı, bu yüzden bunlar başka bir yolda. HTML, CSS, JS ve resim kaynaklarına yönelik istekler de / dataservice / * yolunda bulunmaz, bu nedenle filtrelenmez. Bunlar gizli bir şey içermez ve zarar veremez, bu yüzden bu iyi.

@WebFilter(urlPatterns = {"/dataservice/*"})
...
String sessionCSRFToken = req.getSession().getAttribute("CSRFToken") != null ? (String) req.getSession().getAttribute("CSRFToken") : null;
if (sessionCSRFToken == null || req.getHeader("X-CSRF-TOKEN") == null || !req.getHeader("X-CSRF-TOKEN").equals(sessionCSRFToken)) {
    resp.sendError(401);
} else
    chain.doFilter(request, response);
}   

Bence bir giriş talebinde CSRF isteyeceksiniz. CSRF belirtecini aynı zamanda bir oturum oturumu belirteci olarak da kullanıyorsunuz. Ayrıca, ayrı jetonlar olarak çalışmak için çalışır ve daha sonra, kullanıcı oturum açmış olsun veya olmasın, herhangi bir uç noktada CSRF kullanabilirsiniz.
Tongfa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.