# Cross Origin Resource Sharing

<figure><img src="https://10693534-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpHJ8OuTO6xpfwqkn7vmg%2Fuploads%2Fgit-blob-944f5ffaa4e255a693ea845a5ad9298088c8268b%2FCORS.png?alt=media" alt="CORS" width="563"><figcaption></figcaption></figure>

## Giriş

Herkese selam :)

**CORS** yani **Cross Origin Resource Sharing**, web uygulamaları üzerinde güvenlik önlemi açısından yaygın olarak kullanılan bir mekanizmadır. Temel olarak, bir web uygulamasının kaynaklarına başka bir port veya domainden erişilip erişilemeyeceğini kontrol eder. **Frontend Development** üzerine uğraşmış ancak client-server mimarisine pek hakim olmayan geliştiricilerin en az bir kere karşılaştığı bu hatadan bahsedeceğim bugün. Keyifli okumalar dilerim :)

***

## CORS'un Ortaya Çıkma Süreci

İnternetin erken dönemlerinde, tarayıcılar herhangi bir güvenlik politikası uygulamıyor ve web sayfaları farklı originlerden gelen kaynaklara erişebiliyordu. Bu durum web güvenliği için ciddi bir tehdit oluşturuyordu.

Özellikle **JavaScript** gibi dinamik içeriklerin yaygın olarak kullanıldığı modern web uygulamalarında, bir web sayfasının bir kaynağına erişim yetkisi, diğer kaynaklara erişim yetkisi anlamına geliyordu. Bu durum, kötü niyetli aktörlerin kullanıcıların bilgilerine ve tarayıcılarında saklanan çerezlere erişim kazanabilecekleri güvenlik açıklarını ortaya çıkarıyordu.

Bu nedenle, tarayıcı geliştiricileri ve web standartları kuruluşları, bu güvenlik riskini azaltmak için yeni bir mekanizma geliştirmeye başladılar. Bu mekanizma, farklı kökenlerden gelen kaynaklara erişim izni sağlayacak, ancak güvenlik açıklarını kapatmaya yardımcı olacak şekilde tasarlanmalıydı.

2004 yılında, **Microsoft**, **Internet Explorer** tarayıcısına özel bir özellik olarak ekledi. Ancak, daha sonraki yıllarda diğer tarayıcılar da bu özelliği benimsedi. 2014 yılında, **W3C (World Wide Web Consortium)**, **CORS**'u resmi bir standart olarak kabul etti ve bu, tüm modern tarayıcıların **CORS**'u desteklemesiyle sonuçlandı.

**CORS**'un ortaya çıkışıyla birlikte, web geliştiricileri farklı originlerden gelen kaynaklara erişim izni vermek ve aynı zamanda güvenlik açıklarını en aza indirmek için standart bir yönteme sahip oldular. Bu, web uygulamalarının daha güvenli ve etkili bir şekilde çalışmasına olanak tanıdı.

***

## SOP (Same Origin Policy)

**CORS** üzerine konuşmadan önce **SOP**'un ne olduğu hakkında biraz konuşalım.

Gelişen web teknolojileri ile birlikte güvenlik açıklarının da artması ile tarayıcılar **SOP (Same Origin Policy)** adı verdiğimiz bir politikayı da öne sürdü. **SOP**'a göre tarayıcılar, kullanıcıları korumak üzere, kullanıcı bir sitede gezinti yaparken ilgili uygulamanın başka bir uygulamaya istek atmasına sınırlama getirir. Bu, aynı **origin**'e sahip olmayan sistemler arasında kaynak paylaşımını kısıtlayan bir yapıdır.

**SOP** politikasına göre, yüklenen her bir kaynak

* Şema/Protokol,
* Domain (alan adı),
* Port (bağlantı noktası)

birleşimi ile origin olarak tanımlanır ve sadece aynı origin'e sahip olan kaynaklar birbirleri ile paylaşıma geçebilirler.

Örnek olarak **`https://yavuzlarygb/ornek/deneme.html`** şeklinde bir origin'imiz olsun. Bu origin'e göre

* **`https://yavuzlarygb/ornek2/index.html`** origininden gelen istekler kabul edilir. Çünkü yalnızca dosya yolu farklıdır.
* **`http://yavuzlarygb/ornek/deneme.html`** origininden gelen istekler *kabul edilmez* çünkü protokol farklıdır.
* **`https://www.yavuzlarygb/ornek/deneme.html`** origininden gelen istekler *kabul edilmez* çünkü domain farklıdır.
* **`https://yavuzlarygb:8080/ornek/deneme.html`** origininden gelen istekler *kabul edilmez* çünkü port numarası farklıdır.

{% hint style="info" %}
**Internet Explorer** tarayıcısında **SOP** için özel bir durum vardır: **IE**, port (bağlantı noktası) origin kontrolünde politikaya dahil edilmez.
{% endhint %}

Ek olarak **SOP** farklı originler arasında istek atılmasını ortadan kaldırmaz, farklı bir originden dönen cevabın okunmasını engeller. **SOP** kısıtlaması olmasaydı, zararlı bir siteye girdiğimizde, o an oturumumuzun açık olduğu bir uygulamadaki bilgilerimiz kolayca okunabilir halde kalacaktı. **SOP** mimarisini kafanızda şekillendirebildiğinizi düşünüyorum bu yüzden burada **SOP**'u noktalıyorum.

***

## CORS (Cross Origin Resource Sharing)

**SOP** nedeniyle dönen cevapların okunamaması geliştiriciler için bir süre sonra sorun olmaya başladı. JSONP (JSON Padding) ile bu sorun ortadan kaldırılabilse de *yazma işlemi yapılamadığından* tarayıcılar, **Cross Origin Resource Sharing** kullanmaya başladılar. **CORS** sayesinde, **SOP** ile gelen katı kurallar kontrollü bir şekilde esnetilmiş ve **SOP**'un net kırmızı çizgileri ortadan kalkmış oldu. Kısaca modern web uygulamalarının sıkça ihtiyaç duyduğu kaynak paylaşımı sorununu ortadan kaldırmak için **CORS** geliştirildi.

Aşağıda **CORS** tarafından esneklik sağlanmamış bir origin'e istek atılması sonucunda, tarayıcının **SOP** kısıtlamalarından dolayı isteğe cevap veremediği bir durumun, tarayıcıdaki *developer console* üzerindeki hata mesajını görüyorsunuz.

<figure><img src="https://10693534-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FpHJ8OuTO6xpfwqkn7vmg%2Fuploads%2Fgit-blob-bef09d9bb55e71009df122dc706dd463a035584e%2FCORS-error.png?alt=media" alt="cors-error-messsage-example" width="563"><figcaption></figcaption></figure>

Örnek olarak bir **React** uygulaması, farklı sunucuda bulunan bir API üzerinden veri almak istediğinde, bu sunucu üzerinde **CORS** ayarlarının yapılandırılması gerekir. Aksi halde API'ımızdan veri okunması pek de olası değildir.

***

### CORS'da Yaygın Olarak Kontrol Edilen Başlıklar

**CORS** ayarları, sunucu tarafında yapılır. Kontrolü sağlanan veriler ise **HTTP Başlıkları** tarafından iletilir. Yaygın olarak kontrol edilen başlıklarda ise **Access-Control-Allow-Origin**, **Access-Control-Allow-Methods** ve **Access-Control-Allow-Headers** başlıkları bulunur. Bu başlıklar sırasıyla şu işlevleri yerine getirirler:

* **Access-Control-Allow-Origin:** bu başlık hangi domainlere ve hangi portlara izin verildiğinin kontrolünden sorumludur. Örnek olarak *"Access-Control-Allow-Origin: yavuzlar.org"* olarak verilen bir başlık, sadece bu domain üzerinden gelen isteklere izin verir. Farklı domainler veya portlar eklemek için virgül ile ayrılmış bir liste verilebilir veya tüm domain ve portlara *yıldız (\*)* karakteri ile izin verilebilir.
* **Access-Control-Allow-Methods:** bu başlıkta hangi **HTTP Request Metotları** kabul edildiği kontrol edilir. Örnek olarak *"Access-Control-Allow-Methods: GET, POST"* olarak verilen bir başlık, sadece **HTTP Get** ve **HTTP Post** isteklerine yanıt verir.
* **Access-Control-Allow-Headers:** bu başlık ise hangi **HTTP Header**'larına izin verildiğini kontrol eder. Örnek olarak *"Access-Control-Allow-Headers: Content-Type"* şeklinde verilen başlık, sadece **content-type** başlığına izin verir.

Bunlara ek olarak bir de bizim gönderdiğimiz **HTTP Request**'in header bilgileri kontrol edilir. Tarayıcıdan kaynağa yapılan bir istekte bu header, isteğin *origin başlığında hangi kökten geldiğini* kontrol eder.

***

### CORS'da Simple Requests (Basit İstekler)

*Ön kontrol isteğine gerek kalmadan yapılan isteklerdir.* Ön kontrol'ün ne demek olduğunu bir sonraki başlık altında açıklayacağım ancak bu isteklerde tek koşul ön kontrolün olmaması değil. Aynı zamanda **metot olarak GET, HEAD ya da POST** metotlarından birisi ile yapılması gerekmektedir. Ayrıca yalnızca *basit istek başlıkları* içermelidir *(''Accept', 'Accept-Language', 'Content-Language', 'Content-Type' gibi).*

### CORS'da Preflighted Requests (Ön İstekler)

**Simple Request**'lerin aksine, asıl istek gönderilmeden bir *ön kontrol isteği* gönderilmesi bu türde temel motivasyondur. Bu istek **OPTIONS** metodu ile yapılır. Yapılan istek sonucunda alınacak olan aksiyonun izinli olup olmadığı kontrol edilir. İzin verilirse asıl istek gönderilir, izin verilmeyen istekler tarayıcı tarafından engellenir.

**Metot olarak GET, HEAD, POST** dışında **PUT, DELETE** gibi metotlara da yer verilebilir. Ek olarak *yalnızca basit başlıklar içermek zorunda değildir.*

### CORS'da Credentialed Requests (Kimlik Doğrulamalı İstekler)

Diğer metotlara nazaran daha az bilinen bir diğer yöntem ise **Credentialed Request**'lerdir. Bu isteklerde tarayıcı isteği gönderirken, kaynaklara kimlik doğrulaması gönderilip gönderilmeyeceği bilgisini iletir. Ayrıca bu isteklerde *"Access-Control-Allow-Credentials: true"* başlığı olmalıdır.

***

## CORS'dan Kaynaklanan Zafiyetler

* Giriş kısmında ve yazının ilk paragraflarında da bahsettiğim **SOP** politikasını esneten bir yapı olduğundan dolayı **CORS**, bazı güvenlik açıklarını da beraberinde getirmektedir. **CORS**'un givensiz yapılandırılması sıkça karşılaşılan durumlar arasındadır.
* İlk olarak yapılandırma yapılırken unutulmamalıdır ki, ***CORS, CSRF (Cross-site Request Forgery) gibi saldırılara karşı koruma sağlayan bir yapı değildir.***
* Bir diğer konu, gönderilen origin bilgisinin *"Access-Control-Allow-Origin"* başlık bilgisinin içerisinde yer alması durumudur. Origin'in kontrol edilmemesi ve *“Access-Control-Allow-Credentials”* ile kimliği doğrulanabilir içeriklerin erişilebilir olması, hedeflenen origin'in **rastgele originlere güvenmesi** sonucunda response'un kimliği doğrulanmış kişinin oturumunda yorumlanması ile sonuçlanabilir.
* Origin bilgisinin hatalı bir şekilde kontrol edilmesi durumunda -ki bu URL öneki, URL soneki ya da regex ile yapılır- *farkında olmadan* istenilmeyen originlerin erişimine izin verilmiş olabilir.
* Sıkça karşılaşılan bir diğer durum, **CORS** hatası alındıktan sonra origin kontrolüne gerekli hassasiyetin sağlanmayıp *wildcard (\*)* parametresi ile tüm originlere izin verilmesi durumudur. Wildcard kullanılan bir durumda *Access-Control-Allow-Credentials: true* olsa bile credential'lar requeste eklenmeden gönderilmektedir. Saldırganın doğrudan erişim sağlayamadığı bir senaryoda ise hedef kişinin tarayıcısı bir **proxy** olarak kullanılabilir.
* **XSS (Cross Site Scripting)** zafiyeti içeren bir site içeren senaryoda, **CORS** doğru yapılandırılmış olsa bile, saldırgan **XSS** üzerinden yazdığı payload'ı sisteme enjekte ederek **CORS**'un güvendiği origin'den hassas bilgileri okuyabilir.

***

## Korunma Yöntemleri

* **Preflighted** istekleri kullanın.
* **HTTP metotlarını ve başlıkları sınırlandırın**. Yalnızca ihtiyacınız dahilinde erişmeniz gereken başlıklara ve metotlara izin verin.
* Geliştirdiğiniz uygulama hassas veriler içeriyosa *yerel ağlarda da dahil olmak üzere* kesinlikle **wildcard (\*)** kullanmaktan kaçının.
* *Access-Control-Allow-Origin* başlığı **NULL** değerini alabilmektedir ancak whitelist'inizde null ifadesi kullanmayın.
* CORS'un tarayıcı tarafında çalışan bir mekanizma olduğunu unutmayın. Bu, ***CORS** sunucu tarafında hassas bilgileri koruyamaz* demenin bir başka yolu.
* Son olarak sunucularınızdaki **CORS** politikalarını düzenli olarak izleyin, inceleyin, ve güncelleyin. Yeni güvenlik tehditlerine karşı duyarlı kalın.

***

## Kapanış

Yazının son kısmında neden bu yazıyı seçtiğimden biraz bahsedeyim :)

**Frontend** alanında neredeyse hiç tecrübem yokken **Frontend Developer Intern** olarak staja kabul edilmiştim. Stajın daha ilk günlerinde tanıştığım bu hatanın **CORS** olduğunu saatler sonra anlayacaktım (hatayı okumamıştım ve benden kaynaklandığını düşünüp çözmeye çalışmıştım) :) Bir zamanlar okuma alışkanlığım olduğunu pek söyleyemem ve benim gibi olan dostlarımın aynı hatayı yapmasını istemediğimden dolayı böyle bir konu seçtim.

Yukarda bahsettiğim dostlarım buraya kadar okumayacaktır muhtemelen ancak şans eseri gören *"frontendci"* arkadaşlar, **CORS** diye bir hata alırsanız yüksek ihtimalle sizden kaynaklanmıyor :)

{% embed url="<https://github.com/emrearikann>" fullWidth="false" %}
Bu yazı Emre Arıkan tarafından hazırlanmıştır.
{% endembed %}
