CORS nedir ve ne işe yarar?

Bu flood’da ön yüz geliştirmesi ile uğraşmış herkesin muhakkak en az bir kere tarayıcıdan hata alarak karşılaştığı CORS (Cross Origin Request Sharing) konseptini anlatacağım.

Tarayıcılar kullanıcıyı korumak üzere kullanıcı bir sitede gezinti yaparken ilgili sitenin başka bir siteye web isteği yapmasına sınırlama getirir. Bu sınırlama Same Origin Policy - SOP olarak adlandırılır.

SOP ile tarayıcılar, kötü niyetli xyz․com'un kullanıcının aynı tarayıcı ile açtığı diğer sitelerdeki bilgileri oturum çerezleri üzerinden çalmasını engellenmiş olur. CORS işte tam bu noktada SOP tarafından getirilen sınırlamaları esnetmek üzere ortaya konmuştur.

Aşağıda CORS Policy tarafından esnetilmediğinde farklı bir origin'e yapılmaya çalışılan istek sonucu tarayıcının SOP kısıtlamalarından dolayı isteğe izin vermeyip, geliştirici konsoluna bastığı hataya bir örnek verilmiştir.

CORS öncesinde başka bir origin'e istek yapabilmek yani SOP'u aşabilmek için JSONP adı verilen yöntem kullanmak gerekirdi. Aslında bir hack olan bu yöntem ile orijini farklı olan siteye genellikle Ajax ile kullanılan ve XHR olarak kısaltılan XMLHttpRequest isteği atmak yerine, tarayıcı tarafında kaynak olarak uzak sunucuda bulunan URL'in ve callback'in verildiği bir <script> tag'i oluşturulur, ilgili kod bloğu uzak sunucuda çalıştırılır ve sonuç verilen callback'e iletilir. Böylece SOP aşılmış olur.

CORS sayesinde bir orijin kendisine XHR atabilecek diğer orijinleri, HTTP başlık ve istek tiplerini (DELETE, PUT, vb) granüler olarak belirleyebilir. Bu sayede tarayıcılar tarafından uygulanan katı SOP kuralları legal kullanımlar için esnetilmiş olur.

Yine ön yüz geliştirmesi ile uğraşan herkesin dikkatini çektiği gibi başka bir orijine atılan isteklerden önce tarayıcı OPTIONS isteğini atmakta ve karşı tarafın yapılmak istenen isteğe izin verip vermediğini anlamaya çalışmaktadır. Aşağıda bir OPTIONS örneği verilmiştir.

Yukarıda, tarayıcı OPTIONS ile sunucuya istemcinin Content-Type başlığı ile bir POST isteği atmak için izni olup olmadığını sormuştur. Sunucu cevabında istemcinin sahip olduğu hakları listeyip OK cevabı vermiştir. Sonrasında sunucuya aşağıda verilen asıl istek atılmıştır.

Bütün web sunucu ve istemcilerin bir anda CORS desteği kazanabileceği ideal bir dünyada yaşıyor olsaydık yukarıda örneği verilen ve preflight request olarak adlandırılan OPTIONS isteğine aslında hiç ihtiyaç duymayacaktık.

OPTIONS legacy web sunucuların CORS geçişini güvenlik riski oluşturmadan yapabilmelerini sağlamıştır. preflight request ile daha önce SOP sayesinde farklı bir orijinden belirli istekleri almayacağı varsayımı ile çalışan web uygulamaları bu varsayımı sürdürebilmişlerdir.

Tarayıcılar bütün farklı orijinlere yapılan bütün XHR istekleri için preflight kontrolü yapmazlar. Simple Request olarak adlandırılan GET ve bazı POST istekleri OPTIONS olmadan direkt sunucuya gönderilir. Bunun sebebi de yine mevcut uygulamaları bozmamak içindir. CORS öncesinde de farklı domain'ler arasında form göndermek mümkün olduğu için başlığında Content-Type olarak application/x-www-form-urlencoded ve multipart/form-data bulunan POST istekleri için OPTIONS gönderilmez ve böylece mevcut fonksiyonalite kırılmamış olur.

Karşı taraftaki sunucunun CORS destekli olması durumunda tarayıcı preflight request göndermemiş olsa bile sunucu GET ve POST isteklerinde orijin kontrolü yapabilir ve eğer isteği yapan orijin izin verdiği listede değilse istekleri direkt olarak reddedebilir.

Son olarak cURL veya benzeri komut satırı istemcilerin OPTIONS isteği olmadan da sunucuya POST isteği gönderilebileceğinin altını çizmek gerekir çünkü CORS ile asıl amaç son kullanıcıyı tehlikelerden koruyarak web uygulamalarının işbirliğine izin vermektir.

Bir sonraki flood’da CORS'a daha pratik ve pragmatik bir bakış atarak kullanım alanları ile farklı ortamlarda CORS'u aşma yöntemlerini ele alacağız.