CSRF jetonu nedir? Önemi nedir ve nasıl çalışır?


628

Bir uygulama yazıyorum (Django, öyle oluyor) ve ben sadece bir "CSRF token" nedir ve nasıl veri korumak hakkında bir fikir istiyorum. CSRF jetonlarını kullanmıyorsanız gönderi verileri güvenli değil mi?


13
Siteler Arası İstek Sahte'lerini önlemek için tüm form gönderimlerinde ve yan etki URL'lerinde gizli, kullanıcıya özgü bir belirteçtir. Daha fazla bilgi için: en.wikipedia.org/wiki/Cross-site_request_forgery
Robert Harvey

1
bir soruyu korumak ve çok geniş olduğu için yasaklamak arasında ince bir çizgi var gibi görünüyor : D
anton1980

2
Gönderen OWASP xsrf (CSRF) Önleme Cheat Sheet : " siteler arası komut dosyası çalışmaya CSRF'e için gerekli değildir Ancak, herhangi bir siteler arası komut dosyası güvenlik açığı tüm CSRF hafifletme teknikleri yenmek için kullanılabilir [...].. Bunun nedeni, bir XSS yükünün, XMLHttpRequest [...] kullanarak sitedeki herhangi bir sayfayı okuyabilmesidir [...]. CSRF savunmalarının
atlanamamasını

Yanıtlar:


1497

Siteler Arası İstek Sahteciliği (CSRF) basit kelimelerle

  • Şu anda adresinden çevrimiçi bankacılığınıza giriş yaptığınızı varsayın www.mybank.com
  • Para transferinin mybank.com(form olarak) (kavramsal olarak) bir talep ile sonuçlanacağını varsayın http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (Giriş bilgilerinizde ima edildiği için hesap numaranıza gerek yoktur.)
  • www.cute-cat-pictures.orgKötü amaçlı bir site olduğunu bilmeden ziyaret edersiniz .
  • Bu sitenin sahibi yukarıdaki isteğin biçimini biliyorsa (kolay!) Ve giriş yaptığınızı doğru bir şekilde tahmin ederse mybank.com(biraz şans gerektirir!), Sayfalarına aşağıdaki gibi bir istek ekleyebilir http://www.mybank.com/transfer?to=123456;amount=10000( 123456Cayman Adaları hesaplarının sayısı nerede) ve 10000daha önce sen sandım o bir miktardır memnun ) sahip olmak.
  • Sen o alınan www.cute-cat-pictures.orgbu yüzden, sayfa sizin tarayıcı bu isteği yapacaktır.
  • Bankanız isteğin bu kaynağını tanıyamıyor: Web tarayıcınız isteği www.mybank.comçerezinizle birlikte gönderecek ve tamamen meşru görünecektir. Paran gidiyor!

Bu, CSRF belirteçleri olmayan dünya .

Şimdi CSRF tokenleri ile daha iyisi için :

  • Aktarım isteği üçüncü argüman ile genişletilmiştir: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • Bu simge, mybank.comsize hizmet ettiklerinde kendi web sayfalarında yer alacak büyük, tahmin edilmesi imkansız rastgele bir sayıdır . Öyle farklı onlar kimseye bir sayfasına yönlendirir her zaman.
  • Saldırgan, (... tarayıcı düzgün çalışıp çalışmadığını) bunlardan vazgeçmek web tarayıcınızı ikna edebilmek değildir ve saldırgan yüzden olacak belirteci tahmin etmek mümkün değildir değil , geçerli bir istek yaratmak mümkün olan istekleri nedeniyle yanlış belirteç (veya belirteç yok) tarafından reddedilecek www.mybank.com.

Sonuç: 10000Para birimlerinizi tutarsınız . Bunlardan bazılarını Wikipedia'ya bağışlamanızı öneririm.

(Kilometreniz değişebilir.)

Okumaya değer yorumdan DÜZENLE:

www.cute-cat-pictures.orgNormalde bulunan komut dosyasının www.mybank.comHTTP erişim kontrolü nedeniyle CSRF karşıtı simgenize erişimi olmadığını unutmayın . Bu not, Access-Control-Allow-Origin: *ne olduğunu bilmeden her web sitesi yanıtı için makul olmayan bir şekilde başlık gönderen bazı kişiler için önemlidir , çünkü API'yi başka bir web sitesinden kullanamazlar.


36
Ve açık bir şekilde jeton ideal olarak anti- CSRF jetonu olarak adlandırılacaktı , ancak isim muhtemelen olduğu gibi karmaşık.
Lutz Prechelt

3
@ LutzPrechelt teşekkür ederim. javascript neden tarayıcıdan herhangi bir özgünlük jetonu alamıyor?
BKSpurgeon

72
www.cute-cat-pictures.orgNormalde bulunan komut dosyasının www.mybank.comHTTP erişim kontrolü nedeniyle CSRF karşıtı simgenize erişimi olmadığını unutmayın . Bu not, Access-Control-Allow-Origin: *ne olduğunu bilmeden her web sitesi yanıtı için makul olmayan bir şekilde başlık gönderen bazı kişiler için önemlidir , çünkü API'yi başka bir web sitesinden kullanamazlar.
SOFe

9
@AugustinRiedinger Saldırgan, web sayfasını bilgisayarında açarsa - oturum açan kullanıcının çerezi olmadığından - karşılık gelen csrf jetonunu almazlar (her csrf jetonu yalnızca belirli kullanıcı oturumu için geçerli olmalıdır). Saldırgan, jetonu içeren web sayfasını kullanıcının bilgisayarına, sevimli kedi resimleri web sitesine yerleştirilmiş bir komut dosyası ile yüklemeye çalışırsa, tarayıcı nedeniyle www.mybank.com (ve jetonu) aynı köken politikası.
Marcel

13
@LutzPrechelt Simgenin her zaman farklı olması yeterli olmadığını, bir oturumla eşleştirilmesi ve sunucunun aldığı simgenin sunucunun alınan çerez tarafından tanımladığı bir oturum için oluşturulduğunu kontrol etmesi gerektiğini düşünüyorum. Aksi takdirde, bilgisayar korsanı mybank'ı ziyaret edebilir ve geçerli bir jeton alabilir. Bu nedenle, her formla yeni bir simge kullanırsanız, bunu sunucudaki oturum kimliği ile eşleştirmeniz gerekir. Oturum başına aynı belirteci kullanmak muhtemelen daha kolaydır.
Marcel

222

Evet, gönderi verileri güvenlidir. Ancak bu verinin kaynağı değildir. Bu şekilde, bir kullanıcı saldırganın web sayfasına göz atarken, JS ile kullanıcıyı sitenize giriş yapması için kandırır.

Bunu önlemek için, django hem çerezde hem de form verilerinde rastgele bir anahtar gönderir. Daha sonra, kullanıcılar POST'lar yaptığında, iki anahtarın aynı olup olmadığını kontrol eder. Kullanıcının kandırılması durumunda, 3. taraf web sitesi sitenizin çerezlerini alamaz ve bu nedenle kimlik doğrulama hatasına neden olur.


@DmitryShevchenko Merhaba, bu çerez + form-giriş yönteminin sadece sunucu tarafında yönlendireni doğrulamaktan nasıl farklı olduğunu anlamaya çalışıyorum? Bulduğum tüm örnekler, kullanıcıyı sitesinden gerçek siteye yayınlamak için kandıran bir hacker ile ilgilidir.
Ethan

Tamam, yönlendirenin neden kullanılmadığını öğrendim. Bazen hassas bilgileri sakladığı düşünülen birçok durumda engellenir. Şirketler ve vekilleri genellikle bunu yapar. Bununla birlikte, HTTPS kullanılırsa, engellenmeyeceği olasılığı daha yüksektir.
Ethan

4
Yönlendireni değiştirmek kolaydır, bunun güvenilir bir bilgi parçası olduğunu söyleyemem. Bununla birlikte, CSRF jetonu sunucu gizli anahtarı kullanılarak oluşturulur ve genellikle kullanıcıya bağlanır
Dmitry Shevchenko

1
Bunun neden bir güvenlik tehdidi olduğunu gerçekten anlamıyorum. Kullanıcı başka bir siteye giriş yapacak ... ancak orijinal sitenin bu bilgiyi almanın hiçbir yolu olmayacak. Sağ?
Aakil Fernandes

6
Diyelim ki Facebook.com'da " bank.com/transfer?from=x&to=y " kötü amaçlı bir iframe enjekte ettiğimi varsayalım . Bank.com müşterisiyseniz ve Facebook'a gidiyorsanız, bu iframe, çerezlerinizle birlikte banka sayfasını yükler (çünkü tarayıcı bunları bilinen bir alana gönderir) ve para transferi yapar. Hiçbir şey bilmeden.
Dmitry Shevchenko

74

Site, form sayfası oluştururken benzersiz bir simge oluşturur. Verileri sunucuya geri göndermek / almak için bu belirteç gereklidir.

Simge siteniz tarafından oluşturulduğundan ve yalnızca form içeren sayfa oluşturulduğunda sağlandığından, başka bir site formlarınızı taklit edemez - jetona sahip olmaz ve bu nedenle sitenize gönderemez.


10
Bir kullanıcı kaynak içindeki jeton çıktısını alabilir, kendilerine gönderilen çerezi ve ardından bir 3. taraf sitesi gönderisinden alabilir mi?
Jack Marchetti

9
@JackMarchetti evet. ancak formu üçüncü taraf bir siteden her göndermek istediğinizde sayfayı yüklemeniz ve jetonu ayrıştırmanız gerektiğinden maliyetli olacaktır. Bu saldırı vektörü ile ilgileniyorsanız CSRF jetonları diğer güvenlik biçimleriyle ideal bir şekilde eşleştirilmelidir
tkone

4
@JackMarchetti ile aynı soru var, ne açık değil - CSRF jetonu her girişte değişirse. Aynı kalırsa, bir saldırganın önce oturum açmasını, istek jetonunu yakalamasını ve ardından bu jetonu saldırıya eklemesini ne engeller?
Paul Preibisch

7
@PaulPreibisch her girişte değil, her sayfa yükünde değişmelidir. Bu şekilde, saldırganın formu her göndermek istediğinde sayfayı istemesi gerekir. Çok daha zor hale getirir.
tkone

9
@tkone, Gerçekten çok daha zor hale getirmiyor. Sadece çaba ve zamanı iki katına çıkarırsanız. Herhangi bir engelleyici işlem eklemez. Hile ayrıca CSRF belirtecini etki alanına özgü bir çerezle ilişkilendirir ve bu çerezi formla birlikte gönderir. Hem çerez hem de form sonrası verilerinin POST isteği üzerine sunucuya gönderilmesi gerekir. Bu şekilde, meşru bir isteği taklit edebilmek için bir Çerez Kaçırma saldırısı gerekir.
Pedro Cordeiro

55

Cloud Under blogunda CSRF tokenlerinin iyi bir açıklaması var.

A.com'da barındırılan basitleştirilmiş bir Twitter gibi bir web siteniz olduğunu düşünün. Oturum açan kullanıcılar, sunucuya POST isteği olarak gönderilen ve gönder düğmesine bastıklarında yayınlanan bir forma bazı metinler (tweet) girebilir. Sunucuda kullanıcı, benzersiz oturum kimliğini içeren bir çerezle tanımlanır, böylece sunucunuz Tweet'i kimin yayınladığını bilir.

Form bu kadar basit olabilir:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

Şimdi hayal edin, kötü bir adam bu formu kötü amaçlı web sitesine kopyalayıp yapıştırır, diyelim ki b.com. Form hala işe yarayacaktı. Bir kullanıcı Twitter hesabınızda oturum açtığı sürece (ör. A.com için geçerli bir oturum çerezi varsa), http://a.com/tweetkullanıcı gönder düğmesini tıkladığında POST isteği her zamanki gibi gönderilir ve işlenir.

Şimdiye kadar, kullanıcı formun tam olarak ne yaptığından haberdar olduğu sürece büyük bir sorun değil, ama kötü adamımız formu bu şekilde değiştirirse:

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

Şimdi, kullanıcılarınızdan biri kötü adamın web sitesine girerse ve "Kazanmak için tıklayın!" düğmesini tıkladığınızda, form web sitenize gönderilir, kullanıcı çerezdeki oturum kimliği tarafından doğru şekilde tanımlanır ve gizli Tweet yayınlanır.

Kötü adamımız daha da kötüyse, masum kullanıcının web sayfasını JavaScript kullanarak açar açmaz bu formu göndermesini sağlayabilirdi, belki de görünmez bir iframe'de tamamen gizlenmişti. Bu temelde siteler arası istek sahtekarlığıdır.

Bir form her yerden her yere kolayca gönderilebilir. Genellikle bu ortak bir özelliktir, ancak yalnızca ait olduğu etki alanından bir form gönderilmesine izin vermenin önemli olduğu daha birçok durum vardır.

Web uygulamanız POST ve GET isteklerini birbirinden ayırt etmezse daha da kötüdür (örneğin PHP'de $ _POST yerine $ _REQUEST kullanarak). Yapma bunu! Veri değiştirme talepleri olabildiğince kolay gönderilebilir<img src="http://a.com/tweet?tweet=This+is+really+bad"> , kötü amaçlı bir web sitesine veya hatta bir e-postaya gömülü .

Bir formun yalnızca kendi web sitemden gönderilebildiğinden nasıl emin olabilirim? CSRF jetonu devreye giriyor. CSRF jetonu rastgele, tahmin edilmesi zor bir dizedir. Korumak istediğiniz forma sahip bir sayfada, sunucu rastgele bir dize, CSRF jetonu oluşturur, forma gizli bir alan olarak ekler ve ayrıca oturumda depolayarak veya bir çerez ayarlayarak bir şekilde hatırlar değeri içeren. Şimdi form şöyle görünecektir:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

Kullanıcı formu gönderdiğinde, sunucunun gönderilen csrf-token alanının (adın önemi yoktur) sunucu tarafından hatırlanan CSRF jetonunun değerini karşılaştırması yeterlidir. Her iki dize eşitse, sunucu formu işlemeye devam edebilir. Aksi takdirde, sunucu formu işlemeyi derhal durdurmalı ve bir hatayla yanıt vermelidir.

Bu neden işe yarıyor? Yukarıdaki örneğimizdeki kötü adamın CSRF jetonunu alamamasının birkaç nedeni vardır:

Gizli alanın değeri her kullanıcıyla değiştiğinden, statik kaynak kodunun sayfamızdan farklı bir web sitesine kopyalanması işe yaramaz. Kötü kullanıcının web sitesi geçerli kullanıcının CSRF jetonunu bilmeden sunucunuz her zaman POST isteğini reddeder.

Kötü adamın kötü amaçlı sayfası, kullanıcınızın tarayıcısı tarafından farklı bir alandan (a.com yerine b.com) yüklendiğinden, kötü adamın içeriği yükleyen bir JavaScript kodlama şansı yoktur, bu nedenle içeriği yükler ve dolayısıyla kullanıcının mevcut CSRF jetonunu Senin internet siten. Bunun nedeni, web tarayıcılarının varsayılan olarak web alanları arası AJAX isteklerine izin vermemesidir.

Kötü adam da alanınız eşleşmediği için sunucunuz tarafından ayarlanan çereze erişemez.

Siteler arası istek sahteciliğine karşı ne zaman korunmalıyım? Yukarıda açıklandığı şekilde GET, POST ve diğer istek yöntemlerini karıştırmamanızı sağlayabiliyorsanız, varsayılan olarak tüm POST isteklerini korumak iyi bir başlangıç ​​olacaktır.

PUT ve DELETE isteklerini korumanız gerekmez, çünkü yukarıda açıklandığı gibi bir tarayıcı tarafından standart bir HTML formu bu yöntemler kullanılarak gönderilemez.

Öte yandan JavaScript gerçekten de başka tür isteklerde bulunabilir, örneğin jQuery's $ .ajax () işlevini kullanmak, ancak AJAX isteklerinin çalışması için etki alanlarının eşleşmesi gerekir (web sunucunuzu açıkça yapılandırmadıkça) .

Bu, genellikle POST istekleri olsalar bile, AJAX isteklerine bir CSRF jetonu eklemenize gerek olmadığı anlamına gelir, ancak POST isteği aslında bir AJAX isteği. Bunu, AJAX isteklerinin genellikle içerdiği X-Requested-With gibi bir başlığın varlığını arayarak yapabilirsiniz. Ayrıca başka bir özel başlık ayarlayabilir ve sunucu tarafında olup olmadığını kontrol edebilirsiniz. Bu güvenlidir, çünkü tarayıcı normal bir HTML form gönderimine özel başlıklar eklemeyecektir (yukarıya bakın), bu yüzden Bay Bad Guy'ın bu davranışı bir formla simüle etme şansı yoktur.

AJAX istekleri hakkında şüpheniz varsa, X-Requested With gibi bir üstbilgiyi kontrol edemediğiniz için, oluşturulan CSRF jetonunu JavaScript'inize iletin ve jetonu AJAX isteğine ekleyin. Bunu yapmanın çeşitli yolları var; normal bir HTML formunda olduğu gibi bunu yüke ekleyin veya AJAX isteğine özel bir üstbilgi ekleyin. Sunucunuz gelen bir istekte onu nerede arayacağını bildiği ve bunu oturumdan veya çerezden hatırladığı orijinal değerle karşılaştırabildiği sürece sıralanırsınız.


Ayrıntılı bilgi için teşekkürler. Gönderme isteği sırasında, sitenin sunucuya csrf jetonu göndermesi gerekir, bu nedenle istemci bu csrf jetonunu ne zaman sunucuya gönderir? Ön kontrol seçenekleri talebi yapılır mı? Lütfen bu kısımda elablorat ..
Sm Srikanth

@Dan b.com başka bir sitenin çerezlerine nasıl erişebilir?
zakir

8

Her şeyin kökü, isteklerin sitenin gerçek kullanıcılarından geldiğinden emin olmaktır. Formlar için bir csrf belirteci oluşturulur ve kullanıcının oturumlarına bağlanmalıdır. Jetonun bunları doğruladığı sunucuya istek göndermek için kullanılır. Bu, csrf'ye karşı korumanın bir yoludur, başka bir yönlendirme başlığını kontrol etmek olacaktır.


7
Referans başlığına güvenmeyin, kolayca taklit edilebilir.
Çağ

3
Bu doğru cevap! Simge sunucudaki bir oturuma bağlı OLMALIDIR. Çerez + Form verilerinin en çok oylanan cevap gibi karşılaştırılması tamamen yanlıştır. Bu bileşenlerin her ikisi de, istemcinin oluşturduğu isteğin bir parçasını oluşturur.
Lee Davis

3
Aslında hayır. Belirteç, Sunucuya yapılan her İSTEK'e bağlı OLMALIDIR. Yalnızca oturuma bağlarsanız, oturumun belirtecini çalma ve bu belirteciyle istekte bulunma riskiyle karşı karşıya kalırsınız. Dolayısıyla maksimum güvenlik için jeton her http isteğine bağlı olmalıdır.
chrisl08
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.