CORS Nedir? Nasıl Konfigüre Edilmelidir?

Daha Geriye Gidelim: SOP

Kökler Arası Kaynak Paylaşımı(Cross-Origin Resource Sharing - CORS) nedir, ne değildir bahsetmeden önce Aynı Kök Politikasından (Same Origin Policy - SOP) bahsetmekte fayda oalcaktır. Web teknolojilerinin gelişimine baktığımızda, her yeni bir özellikle birlikte yeni atak yüzeyleri meydana çıkar. 90’lı yıllara gidersek; HTTP protokolüne cookie özelliğinin eklenmesi, HTML’in yeterli kalmayıp dinamik bir dil olan Javascriptin geliştirilmesi ve DOM API’ın kullanılmaya başlaması, beraberinde yeni saldırı alanları getirmiştir. Kötü niyetli bir saldırgan oluşturduğu site aracılığıyla -örneğin iframe kullanarak, oturum bilgilerine erişip istek atarak- başka bir siteyi manipüle ederek yetkisiz erişim sağlayabilir hale gelmiştir. Burada SOP devreye girmektedir. SOP, kaynak ve istemci aynı köke (origin) sahip değilse kaynağa erişimi kısıtlar. Bu sayede bahsettiğimiz saldırılardan korunmuş oluruz. Aynı kök, kullanılan protokol, URL ve port bilgisinin birleşiminden oluşur. Aşağıda senaryoları ele alan bir tablo bulunmaktadır.

Untitled

SOP’nin bazı istisnaları vardır. Örneğin, eski sitelerin çalışma sisteminin kırmamak için HTML formları ile gelen isteklere izin vermektedir. Bunları engellemek için CSRF saldırısına karşı alınan önlemlerden biri olan CSRF Token kullanılabilir.

CORS

SOP ve CORS’un açılımlarından anlaşılacağı üzere; CORS, SOP üzerine yapılmış bir genişletmedir. Çünkü daha önceden söylediğimiz gibi, web teknolojileri geliştikçe, ihtiyaçlar değiştikçe yeni yaklaşımlar gerekmektedir. Sitelerin oldukça dinamikleşmesi, kaynak paylaşımları, farklı servislerin SOP ile karşılanmaması ile CORS karşımıza çıkmıştır (CORS’tan önce de JSONP yöntemiyle atlatılabilmekteydi ancak bu genel kabul görmüş bir çözüm değildi). CORS ile bir kök (origin), kendisine istek atabilecek kökleri kaynağına, tipine vs göre belirleyebiliriz. Yani SOP kısıtlamasına istisna getirmektedir. Ancak düzgün konfigüre edilmediğinde ilgili sitenin kullanıcıları bazı saldırılara maruz kalabilmektedir.

Öncelikle yaygın olarak bilinen bir yanlışa yorum getirmekte fayda vardır. CORS, CSRF (Cross Site Request Forgery) saldırılarına karşı alınan bir önlem değildir. Sadece, doğru yapılandırıldığında sadece belirli köklerden istekler gelmesini sağlayarak saldırganların hazırladığı kötü niyetli sitelerden istek gelmesini engeller. Bu yanlış bilgiyi düzelttiğimize göre CORS header’larını ve çalışma mantığını inceleyebiliriz.

Access-Control-Allow-Origin başlığı (header) ile sunucu, tarayıcıya hangi köklerden gelen isteklere izin verdiğini belirtir. Tarayıcı bu bilgiler vasıtasıyla gerektiğinde isteği engeller.

  • Eğer sunucu tarafında bu değer * olarak ayarlanmışsa, bütün köklere izin verildiği anlamına gelir.
  • Bu değer * olmadığında bir adet site olarak ayarlanabiliyor. Bunu genişletmek için de beyaz liste (white list) oluşturulup başlık ayarlanıp yansıtılıyor (reflected). Bunu yaparken regex olarak bilinen düzenli ifadeler ya da mantık düzgün kurgulanmazsa, saldırgan bunları atlatabiliyor. Örneğin, mysite.com sitesi alt domainlere izin vermek istesin. Eğer mantığı, kökün sonu mysite.com ile bitsin şeklinde yaparsa saldırgan bunu atlatabilir (evilmysite.com gibi bir domain alıp bu kök üzerinden istek gönderir).
  • Bu değer null olarak ayarlanabiliyor. Böyle durumlarda, yerelde çalışan pdf dosyaları, mobil uygulamalar ve sandboxed iframe’lere izin vermiş olunuyor. Direk beyaz listeye null eklemek çok mantıklı bir davranış değildir.

Access-Control-Allow-Credentials ile istekte kimlik bilgisi (credentials) taşınıp taşınamayacağı, Access-Control-Allow-Methods ile hangi HTTP metotlarına izin verilip verilmediği vs ayarlanabilmektedir. Bunların dışında başka başlıklar da mevcuttur. CORS tabanlı saldırıları engellemek için; sadece güvenilen sitelere izin verilmeli, beyaz liste kontrolleri iyice test edilmeli, izin verilen kök değerini null ayarlamaktan kaçınılmalıdır. Ayrıca, sitemiz XSS gibi bazı zafiyetler içeriyorsa, CORS düzgün konfigüre edilse bile atlatılabilmektedir, daha doğrusu enjekte edilen JS kodu CORS’ı hassas veriye ulaşmak için kullanabilmektedir. Bu yüzden uygulamalara SAST ve DAST araçlarıyla periyodik olarak test yapmak oldukça önemlidir.

Invicti ile CORS Yanlış Konfigürasyon Tespiti

Şimdi biraz pratik yapalım. CORS başlıkları yanlış, olması gerektiğinden fazla izin veren bir şekilde tanımlanmış bir web uygulaması ve bir de bu uygulamaya istek atan ön yüz (frontend) uygulamasına ihtiyacımız var. Sonrasında bir Dinamik Uygulama Güvenliği Testi (Dynamic Application Security Testing - DAST) aracı olan Invicti ile CORS için tarama yapacağız. Uygulamaları oluştururken Express.js ve React kullandım. Sunucuda iki farklı adres var. Biri, ön yüz (frontend) uygulamasının köküne izin verirken, diğeri tüm köklere izin veriyor.

Untitled

Aşağıda ön yüz uygulama arayüzünü görmektesiniz.

Untitled

Şimdi Invicti arayüzden sadece CORS zafiyeti için tarama yapan bir politika (policy) oluşturalım (zamandan kazanmak için). Bunu, Policies > New Scan Policy diyerek de yapabiliriz, var olan bir politikayı özelleştirmek istiyorsak Policies > Scan Policies diyip ilgili politikanın yanındaki Clone butonuna basarak da yapabiliriz. Ben ikinci adımı tercih ettim. Politikayı oluştururken Security Checks sekmesinde sadece CORS’u seçmeliyiz. Aşağıda görüleceği üzere Invicti ile tarama politikası oluştururken birçok seçenek arasından istediğimiz güvenlik kontrolünü seçerek oldukça özelleşmiş politikalar oluşturabiliyoruz.

Untitled

Şimdi taramayı başlatalım. Web sitemiz oldukça basit olduğu ve sadece CORS için tarandığından dolayı tarama oldukça kısa sürecektir ve sadece CORS ile ilgili bulgu bulacaktır. Tarama sonucuna baktığımızda aşağıdaki sonucu görüyoruz.

Untitled

Evet, tarama sonucu beklediğimiz gibi geldi. Bir adres için CORS başlıklarından Access-Control-Allow-Origin başlığını * olarak ayarladığımız için bize misconfigured uyarısı verdi. Az önce bahsettiğimiz üzere, sadece güvendiğimiz sitelere izin vermeliyiz.