CORS (Cross-Origin Resource Sharing) Nedir?

CORS (Kökler Arası Kaynak Paylaşımı), bir web sayfası veya web uygulaması üzerinden sunulan kaynaklara (medya, css ve js dosyaları, fontlar, vb.) kaynağın sunulduğu alan adının (hostname) dışından gerçekleştirilen isteklerin yönetimini sağlayan bir işlemdir. Örneğin, web sayfanızdaki bir içeriğin tamamen ya da bu içerik içerisindeki bir görselin bir başke web sayfaına kopyaladığını varsayalım. Bu durumda, o sayfa görüntülendiğinde sizin sunucunuzdaki görsel çağırılacak ve o sayfayı görüntüleyen ziuaretçiye sunulacaktır. Dolayısıyla, bir kaynak paylaşımı söz konusu olacaktır. Bu gibi durumlar için, CORS ile kaynak sunucunun nasıl davranması gerektiği belirtilebilir. Örneğin, sizin sunucunuzdaki kaynakların başka bir alan adı altında sunulmasını (alanlar arası iskekleri) engelleyebilirsiniz. Özetlemek gerekirse; CORS, kökler arası isteklerin güvenli olup olmadığına karar vermek için tarayıcı ve sunucu arasında bir etkileşimin nasıl yapılacağını tanımlar. W3C tarafından da önerilen bir standarttır1 2 3.

Elbette konu sadece medya dosyaları, fontlar, vb. ile sınırlı değil. Örneğin, Ajax işlemleri gerçekleştirdiğinizde farklı bir kaynaktan veri geçmek ya da veri göndermek istediğinizde CORS hataları almanız oldukça muhtemeldir4. Çünkü Ajax istekleri, Same-origin policy (SOP) nedeniyle varsayılan olarak yasaklanmıştır5 6. Yani, aksi belirtilmediği sürece (başlıklar düzenlenmemişse) ajax istekleri sadece kendi alan adı bağlamındaki kaynaklara doğrudan erişim sağlayabilir. Ancak şu konunun altını çizmekte fayda var; CORS bir güvenlik çözümü değildir. CORS pek çok tarayıcı üzerinden kolayca devre dışı bırakılabilmektedir. Genel amacı içerik sahipliğinin korunmak ve sunucu kaynaklarının daha efektif yönetilmesini sağlamaktır7.

Çalışma Biçimi

CORS standardı HTTP başlıkları aracılığı ile tanımlanır ve pek çok HTTP istek türü de desteklemektedir. Bu başlıkların ve isteklerin kontrolü genelde tarayıcıların sorumluluğundadır. CORS aracılığı ile paylaşılan kaynakların origin'i (protokol, host ve port bilgileri) değerlendirilerek istekler yönetilebilir. Bu sayede, same-origin policy tarafından oluşturulan sınırlandırmaları CORS ile esnetebiliriz 8.

CORS (Cross-Origin Resource Sharing)

Yukarıdaki görseli örnek olarak değerlendirebiliriz. Bir web sayfasını tarayıcımız aracılığıyla görüntülemek istediğimizda o web sayfasındaki kaynaklar (medya dosyaları, fontlar, sayfanın kendisi, css ve js dosyaları, vb.) için istek gönderilir. Bu istekler sunucuya iletildiğinde sunucu isteği değerlendirir ve uygun biçimde dönüş sağlar. Bu görselde ifade edilen A senaryosudur.

Şimdi fontlar farklı bir sunucudan çağırıldığını varsayalım. Örnek olarak birgün Google Fonts'un sadece *.google.com alan adı ile gelen isteklere cevap verdiğini düşünebiliriz. Bu durumda, fontlara erişim sağlanamayacak ve tarayıcının console alanında CORS hatası görüntülenecektir. Bu durum da görsel içerisinde yer alan B senaryosu ile ifade edilebilir.

Aşağıdaki hata kaydını örnek olarak değerlendirebilirsiniz.

CORS Error

Bu tür hataları önlemek adına, gerçekleştirilen isteklerle ilgili kontrollerin doğru şekilde yönetilebilmesi gerekir. Bu nedenle preflight ifadesini açıklamakta fayda var.

Preflight (ön kontrol isteği), CORS protokolünün sunucu tarafından anlaşılıp anlaşılmadığının ve kullanılan method ve header ifadelerinin farkında olup olmadığının kontrolünü sağlar9 3.

Basit İstekler (Simple Requests)

Basit istekler ön kontrol isteğini (preflight) tetiklemeden, tek bir HTTP isteği halinde gönderilirler. Şu özelliklerden herhangi birine sahip olmaları yeterlidir:

  • GET, HEAD ve POST metodu kullanılır;
    • Fetch izinli başlıkları içermesi
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (istisnalar içeriyor)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
    • Content-Type için izin verilen şu tanımlara sahip olması;
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Örneğin10;

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

Yukarıdaki istek herhangi bir ön kontrol gerektirmeksizin sunucundan şu cevabı alır;

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML Data…]

Bu cevap içerisinde yer alan Access-Control-Allow-Origin: * en temel erişim kontrol protokolüdür (access control protocol) ve * kaynak için tanımlı bir alan adı olmadığını ifade eder. Ancak, istenirse bu tanım Access-Control-Allow-Origin: https://foo.example şeklinde sadece belirli istemci kaynakları ile sınırlandırılabilir10 2.

Preflight Gerektiren İstekler

Yukarıda da özet bir şekilde ifade ettiğim üzere, preflight sürecinde orjinal isteğin öncesinde istemci otomatik olarak sunucuya OPTIONS ile bir preflight tanımı iletir. Bu sayede gerçekleştirilecek asıl isteğin sunucu doğrulaması yapılmış olur11. Gerçekleştirilecek bir isteğk aşağıdaki özelliklerden herhangi birine sahipse preflight ile doğrulanması gerekir:

  • PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH metodu kullanılır;
    • Fetch yasaklı başlıkları içermesi12
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type (istisnalar içeriyor)
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
    • Content-Type için izin verilenler dışındaki tanımlar

Örneğin9;

OPTIONS /resource/foo
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://foo.bar.org

Eğer sunucu yukarıdaki isteği doğrularsa ilgili Access-Control-Request-Method içeriği ile birlikte şu cevabı alır;

HTTP/1.1 204 No Content
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

CORS Gereksinimleri

Sıklıkla karşılaşılan durumlar temel alındığında, şu istek türleri için CORS ayarlaması yapmanın uygun olacağını söyleyebiliriz.

  • Ajax istekleri (XMLHttpRequest ve fetch())
  • Web font kullanımları (@font-face ile yapılan istekler)13
  • WebGL doku işlemleri14
  • drawImage() ile gerçekleştirilen canvas işlemleri15
  • CSS shape işlemleri16