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?
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?
Yanıtlar:
www.mybank.com
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.org
Kötü amaçlı bir site olduğunu bilmeden ziyaret edersiniz .mybank.com
(biraz şans gerektirir!), Sayfalarına aşağıdaki gibi bir istek ekleyebilir http://www.mybank.com/transfer?to=123456;amount=10000
( 123456
Cayman Adaları hesaplarının sayısı nerede) ve 10000
daha önce sen sandım o bir miktardır memnun ) sahip olmak.www.cute-cat-pictures.org
bu yüzden, sayfa sizin tarayıcı bu isteği yapacaktır.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 :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
size 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.www.mybank.com
.Sonuç: 10000
Para 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.org
Normalde bulunan komut dosyasının www.mybank.com
HTTP 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.
www.cute-cat-pictures.org
Normalde bulunan komut dosyasının www.mybank.com
HTTP 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.
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.
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.
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/tweet
kullanı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.
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.