CORS — Postman'de Çalışıyor, Tarayıcıda Neden Hata?
Önce şunu oku: Form Gönderimi — Bir Tıkla İki Havale Nasıl Olur?
30 saniyede özet
Tarayıcı, bir sayfanın başka bir adrese yaptığı isteğin cevabını ancak sunucu izin verirse sayfaya verir. CORS bu izni anlatır. Kuralı yalnızca tarayıcı uygular; isteğin kendisi çoğu zaman sunucuya ulaşır.
Büyük bir binada çalışıyorsun ve gelen postaların hepsi önce danışmadaki görevliden geçiyor. Görevli, başka bir şirketten gelen cevabı ancak o şirket “bu cevap şu kişiye verilebilir” diye yazmışsa sana uzatıyor. Binanın dışındaki biri ise aynı mektubu doğrudan açıp okuyabiliyor.
-
Bayt: Havale API'si hazır. Postman'de denedim, mükemmel çalışıyor.
-
Sen: Web uygulamasından çağırınca ne oluyor?
-
Bayt: Konsolda kırmızı bir 'CORS error'. Ama sunucu loglarında istek görünüyor!
-
Bayt: İstek gitmiş, cevap sayfaya gelmemiş. Arada biri karar veriyor: tarayıcı.
Origin ve izin
Bir sayfanın originBir adresin şema, alan adı ve port üçlüsü. Tarayıcı, başka bir origin'den gelen cevabı sunucu izin vermedikçe sayfaya vermez (same-origin policy).Sözlükte gör →’i şema, alan adı ve porttan oluşur: https://app.bank.example ile https://api.bank.example iki ayrı origin’dir. Tarayıcı, sayfanın kendi origin’i dışındaki bir adresten gelen cevabı varsayılan olarak sayfaya vermez.
CORSCross-Origin Resource Sharing: sunucunun, başka bir origin'deki sayfaya cevabını okuma izni vermesi. Access-Control-* başlıklarıyla yapılır; kuralı tarayıcı uygular.Sözlükte gör →, sunucunun bu izni vermesinin yoludur. Cevaba Access-Control-Allow-Origin: https://app.bank.example yazarsa tarayıcı cevabı sayfadaki koda verir.
Kafam karıştı, daha basit anlat
Farklı adres, farklı origin. Tarayıcı, sunucu “bu sayfaya izin var” demedikçe cevabı sayfaya vermez.
Hangisi https://app.bank.example ile aynı origin'dir?
Aynı istek Postman'de çalışıyor, tarayıcıda 'CORS error' veriyor. Neden?
İstek gider mi?
Sayfa başka bir origin'e basit bir GET isteği yaptı. Sunucu hiçbir CORS başlığı göndermiyor. İstek sunucuya ulaşır ve işlenir mi? Cevabı göster
Evet. Basit bir istek gönderilir ve sunucu onu işler. Tarayıcı yalnızca gelen cevabı sayfadaki JavaScript’ten saklar ve konsola “CORS error” yazar.
Adım adım oku
- Mektup gitti, cevap geldi: liste izin veriyor.
- Listede adın yoksa görevli cevabı sana vermez; ama mektup gitmişti.
- Olağandışı bir mektup için görevli önce telefonla sorar.
- Karar sunucunun listesinde; uygulayan tarayıcı.
JSON gövdeli bir POST ya da özel bir başlık taşıyan istek basit değildir. Tarayıcı önce bir OPTIONS preflightBasit olmayan bir istekten önce tarayıcının gönderdiği OPTIONS isteği. Sunucu metot ve başlıklara izin vermezse asıl istek hiç gönderilmez.Sözlükte gör → gönderir; sunucu metodu ve başlığı izinli saymazsa asıl istek hiç gönderilmez.
Çerezli isteklerde sunucu * diyemez: origin’i açıkça yazmalı ve Access-Control-Allow-Credentials: true göndermelidir.
Kafam karıştı, daha basit anlat
Basit istek gider, cevap saklanabilir. Basit olmayan istek önce izin sorar; izin yoksa hiç gitmez.
Sunucu hiçbir CORS başlığı göndermiyor. Sayfa başka origin'e basit bir GET yaptı. Ne olur?
Content-Type: application/json ile bir POST gönderiliyor. Tarayıcı önce ne yapar?
Kendin gör
app.bank.example → api.bank.example
Tohum 697101Oynat ya da adımla.
Şu an ne oldu?
GET /accounts (basit istek)
CORS ayarı yok · tarayıcı
Görevler0/3
İsteği sunucuya ulaştır ama cevabını JavaScript'ten saklaaçık
İpucu
Varsayılan ayarlar yeter.
Asıl isteğin hiç gönderilmediği bir durum yarataçık
İpucu
JSON gövdeli bir istek dene.
Jokerin çerezli istekte işe yaramadığını göraçık
İpucu
Çerezli istek ve * ayarı.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. İstek sunucuya ulaştı, cevap JavaScript’ten saklandı.
- İstemciyi curl yap. Aynı istek, cevap okundu: curl CORS bilmez.
- JSON POST seç, sunucuyu “yalnızca Allow-Origin” yap. Ön kontrolde takıldı, asıl istek gitmedi.
- Çerezli isteği joker ayarla dene. * çerezle birlikte kabul edilmez.
- Sunucuyu “origin, metotlar, başlıklar” yap. Üç istek de geçer.
Ön kontrol cevabında Allow-Origin var ama Allow-Headers'ta Content-Type yok. JSON POST'a ne olur?
Çerezli bir istekte (credentials: include) sunucu Access-Control-Allow-Origin: * gönderiyor. Sonuç?
Tuzaklar
CORS’u güvenlik sanmak. CORS sunucuyu korumaz; kullanıcının tarayıcısının, başka bir sitenin onun adına okuma yapmasını engeller. Sunucuya gelen her istek yine kimlik doğrulama, yetki ve CSRFTarayıcının isteğe otomatik eklediği kimlik bilgilerini başka bir sitenin sömürmesi. Token elle eklenen bir başlıktaysa bu saldırı yüzeyi yoktur; cookie'deyse vardır.Sözlükte gör → kontrolünden geçmeli.
Her şeye joker. * ile hata kaybolur ama bütün sitelere okuma izni verilir. İzin listesini açıkça yaz.
Origin’i olduğu gibi yansıtmak. Gelen her Origin başlığını cevaba geri yazmak, jokerden de geniş bir izindir, üstelik çerezlerle birlikte. Origin’i bir listeyle karşılaştır.
Kafam karıştı, daha basit anlat
CORS sunucunun kilidi değil. Joker ve yansıtma yerine açık bir izin listesi kullan.
CORS bir sunucuyu kötü niyetli isteklerden korur mu?
Aşağıdaki örnek bir bankanın havale API’sinden: yalnızca kendi web uygulamasına, gereken metot ve başlıklarla, çerezli izin.
Derinleş · Havale API'si: açık bir CORS izin listesi 4 dosya · ~44 satır · ilk okumada atlayabilirsin
Kendini sına
CORS kuralını curl ve Postman de uygular.
Sunucu gelen her isteğin Origin başlığını Access-Control-Allow-Origin'e aynen yazıyor ve credentials'a izin veriyor. Risk nedir?
Aklında kalacak üç şey
- 1 Origin, şema, alan adı ve porttan oluşur. Farklı bir origin'e yapılan isteğin cevabını tarayıcı, sunucu Access-Control-Allow-Origin ile izin vermedikçe sayfaya vermez.
- 2 Basit bir istek sunucuya gider ve işlenir; tarayıcı yalnızca cevabı saklar. JSON gövdeli gibi basit olmayan istekler önce OPTIONS ön kontrolüyle izin ister; izin yoksa asıl istek hiç gönderilmez.
- 3 CORS tarayıcının kuralıdır, sunucunun koruması değil. curl ve Postman onu uygulamaz; yetkilendirme ve CSRF koruması sunucuda ayrıca gerekir.
4 kart sonraki derste seni bekliyor