İş ortaklarının yalnızca bize kaydettirdikleri alanlarda kullanabilecekleri bir API sunuyoruz. İçeriği kısmen herkese açıktır (ancak tercihen yalnızca bildiğimiz alanlarda gösterilebilir), ancak çoğunlukla kullanıcılarımıza özeldir. Yani:
Neyin gösterildiğini belirlemek için , kullanıcımızın bizimle oturum açması gerekir, ancak bu ayrı olarak ele alınır.
Verilerin nerede gösterildiğini belirlemek için, bildiğimiz alanlara erişimi sınırlamak ve her şeyden önce özel kullanıcı verilerinin CSRF'ye karşı savunmasız olmasını sağlamak için genel bir API anahtarı kullanılır .
Bu API anahtarı gerçekten herkes tarafından görülebilir, ortağımızın kimliğini başka hiçbir şekilde doğrulamıyoruz ve REFERER'a ihtiyacımız yok . Yine de güvenlidir:
Bizim get-csrf-token.js?apiKey=abc123
talep edildiğinde:
abc123
Veritabanında anahtarı arayın ve bu anahtar için geçerli etki alanlarının bir listesini alın.
CSRF doğrulama çerezini arayın. Mevcut değilse, güvenli bir rastgele değer oluşturun ve bunu yalnızca HTTP oturum tanımlama bilgisine koyun . Tanımlama bilgisi mevcutsa, mevcut rastgele değeri alın.
API anahtarından ve çerezden rastgele değerden bir CSRF jetonu oluşturun ve imzalayın . (Sunucuda bir jeton listesi tutmak yerine, değerleri imzalıyoruz. Her iki değer de imzalı jetonda okunabilir, sorun değil.)
Yanıtı önbelleğe alınmayacak şekilde ayarlayın, çerezi ekleyin ve aşağıdaki gibi bir komut dosyası döndür:
var apiConfig = apiConfig || {};
if(document.domain === 'expected-domain.com'
|| document.domain === 'www.expected-domain.com') {
apiConfig.csrfToken = 'API key, random value, signature';
if(typeof apiConfig.fnInit !== 'undefined') {
apiConfig.fnInit();
}
} else {
alert('This site is not authorised for this API key.');
}
Notlar:
Yukarıda bir istek taklit gelen bir sunucu tarafı komut dosyası engellemez, ancak yalnızca etki alanı maçları sağlar eğer bir tarayıcı tarafından istedi.
JavaScript için aynı kökenli ilke Bir tarayıcı yüklemek ve daha sonra JavaScript kaynağını incelemek için XHR (Ajax) kullanamazsınız sağlar. Bunun yerine, normal bir tarayıcı onu yalnızca <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(veya dinamik bir eşdeğeri) kullanarak yükleyebilir ve ardından kodu çalıştırır. Tabii ki, sunucu gerekir değil desteklemek Çapraz Kökenli Kaynak Paylaşımı oluşturulan JavaScript ne de JSONP.
Bir tarayıcı komut dosyası document.domain
, yukarıdaki komut dosyasını yüklemeden önce değerini değiştirebilir . Ancak aynı kökenli ilke yalnızca tarafından domain kısaltılması sağlar çıkarmadan yeniden gibi, önekleri subdomain.example.com
sadece etmek example.com
ya myblog.wordpress.com
kadar wordpress.com
, hatta bazı tarayıcılarda bbc.co.uk
için co.uk
.
JavaScript dosyası bazı sunucu tarafı komut dosyaları kullanılarak getirilirse, sunucu da çerezi alır. Ancak, üçüncü taraf bir sunucu, bir kullanıcının tarayıcısının bu çerezi bizim etki alanımızla ilişkilendirmesini sağlayamaz. Bu nedenle, bir sunucu tarafı komut dosyası kullanılarak getirilen bir CSRF belirteci ve doğrulama çerezi, bir tarayıcıda değil, yalnızca sonraki sunucu tarafı çağrıları tarafından kullanılabilir. Ancak, bu tür sunucu tarafı aramaları hiçbir zaman kullanıcı çerezini içermez ve bu nedenle yalnızca herkese açık verileri getirebilir. Bu, bir sunucu tarafı komut dosyasının doğrudan ortağın web sitesinden alabileceği verilerle aynıdır.
Bir kullanıcı oturum açtığında, istediğiniz şekilde bazı kullanıcı çerezleri ayarlayın. (Kullanıcı, JavaScript talep edilmeden önce zaten oturum açmış olabilir.)
Sunucuya yapılan sonraki tüm API istekleri (GET ve JSONP istekleri dahil), CSRF belirtecini, CSRF doğrulama çerezini ve (oturum açılmışsa) kullanıcı çerezini içermelidir. Sunucu artık isteğin güvenilir olup olmadığını belirleyebilir:
JavaScript, beklenen etki alanından yüklendi teminat altın jeton geçerli CSRF'e varlığı halinde bir tarayıcı tarafından yüklendi.
Doğrulama çerezi olmadan CSRF belirtecinin varlığı sahteciliği gösterir.
Hem CSRF belirtecinin hem de CSRF doğrulama çerezinin varlığı hiçbir şeyi garanti etmez: bu sahte bir sunucu tarafı isteği veya bir tarayıcıdan gelen geçerli bir istek olabilir. (Desteklenmeyen bir etki alanından yapılan bir tarayıcıdan istek olamaz.)
Kullanıcı çerezinin varlığı, kullanıcının oturum açmasını sağlar, ancak kullanıcının söz konusu ortağın bir üyesi olmasını veya kullanıcının doğru web sitesini görüntülediğini garanti etmez.
CSRF doğrulama çerezi olmadan kullanıcı çerezinin varlığı sahteciliği gösterir.
Kullanıcı tanımlama bilgisinin varlığı, mevcut isteğin bir tarayıcı aracılığıyla yapılmasını sağlar. (Bir kullanıcının kimlik bilgilerini bilinmeyen bir web sitesine girmeyeceğini varsayarsak ve bazı sunucu tarafı taleplerde bulunmak için kendi kimlik bilgilerini kullanmalarının umurumuzda olmadığını varsayarsak.) Ayrıca CSRF doğrulama tanımlama bilgisine sahipsek, o CSRF doğrulama tanımlama bilgisi ayrıca bir tarayıcı kullanılarak alındı. Sonra, eğer aynı zamanda geçerli bir imzaya sahip belirteci bir CSRF var, veCSRF doğrulama tanımlama bilgisindeki rastgele sayı, o CSRF belirtecindeki rasgele sayı ile eşleşir, ardından bu belirteç için JavaScript, CSRF tanımlama bilgisinin ayarlandığı aynı önceki istek sırasında, dolayısıyla bir tarayıcı kullanılarak da alındı. Bu daha sonra, yukarıdaki JavaScript kodunun belirteç ayarlanmadan önce yürütüldüğünü ve o sırada etki alanının verilen API anahtarı için geçerli olduğunu gösterir.
Yani: sunucu artık API anahtarını imzalı jetondan güvenle kullanabilir.
Herhangi bir noktada sunucu isteğe güvenmezse, 403 Yasak döndürülür. Widget, kullanıcıya bir uyarı göstererek buna yanıt verebilir.
İmzalı CSRF belirteciyle karşılaştırdığımız için CSRF doğrulama tanımlama bilgisini imzalamanıza gerek yoktur. Tanımlama bilgisini imzalamamak, her HTTP isteğini kısaltır ve sunucu doğrulamasını biraz daha hızlı yapar.
Oluşturulan CSRF belirteci süresiz olarak geçerlidir, ancak yalnızca doğrulama tanımlama bilgisiyle birlikte, yani tarayıcı kapatılana kadar etkilidir.
Belirtecin imzasının ömrünü sınırlayabiliriz. OWASP önerisini karşılamak için kullanıcı oturumu kapattığında CSRF doğrulama tanımlama bilgisini silebiliriz . Kullanıcı başına rastgele sayıyı birden çok ortak arasında paylaşmamak için, API anahtarı çerez adına eklenebilir. Ancak bu durumda bile, yeni bir belirteç istendiğinde CSRF doğrulama çerezi kolayca yenilenemez, çünkü kullanıcılar aynı siteye birden çok pencerede göz atıyor, tek bir çerez paylaşıyor olabilir (bu, yenilenirken tüm pencerelerde güncellenir ve ardından Diğer pencerelerdeki JavaScript simgesi artık bu tek çerezle eşleşmeyecektir).
OAuth kullananlar için JavaScript fikrini aldığım OAuth ve İstemci Tarafı Widget'larına da bakın . İçin sunucu tarafında biz alanını sınırlamak için JavaScript kodu güvenemez hangi API, kullanımı, biz gizli anahtarlar yerine genel API anahtarlarını kullanıyoruz.