İçeriğe geç

CORS — Postman'de Çalışıyor, Tarayıcıda Neden Hata?

Orta 9 dk Çok sık karşılaşılır

Ö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.

  1. Bayt: Havale API'si hazır. Postman'de denedim, mükemmel çalışıyor.

  2. Sen: Web uygulamasından çağırınca ne oluyor?

  3. Bayt: Konsolda kırmızı bir 'CORS error'. Ama sunucu loglarında istek görünüyor!

  4. 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.

Hızlı kontrolBaşlangıç

Hangisi https://app.bank.example ile aynı origin'dir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aynı istek Postman'de çalışıyor, tarayıcıda 'CORS error' veriyor. Neden?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

İ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.

Karar sunucunun listesinde, uygulayan tarayıcı.
Adım adım oku
  1. Mektup gitti, cevap geldi: liste izin veriyor.
  2. Listede adın yoksa görevli cevabı sana vermez; ama mektup gitmişti.
  3. Olağandışı bir mektup için görevli önce telefonla sorar.
  4. 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.

Hızlı kontrolOrta

Sunucu hiçbir CORS başlığı göndermiyor. Sayfa başka origin'e basit bir GET yaptı. Ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Content-Type: application/json ile bir POST gönderiliyor. Tarayıcı önce ne yapar?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

app.bank.example → api.bank.example

Tohum 697101

Oynat ya da adımla.

Hız
Adım 0

Ş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.

  1. Varsayılanla oynat. İstek sunucuya ulaştı, cevap JavaScript’ten saklandı.
  2. İstemciyi curl yap. Aynı istek, cevap okundu: curl CORS bilmez.
  3. JSON POST seç, sunucuyu “yalnızca Allow-Origin” yap. Ön kontrolde takıldı, asıl istek gitmedi.
  4. Çerezli isteği joker ayarla dene. * çerezle birlikte kabul edilmez.
  5. Sunucuyu “origin, metotlar, başlıklar” yap. Üç istek de geçer.
Hızlı kontrolOrta

Ön kontrol cevabında Allow-Origin var ama Allow-Headers'ta Content-Type yok. JSON POST'a ne olur?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Çerezli bir istekte (credentials: include) sunucu Access-Control-Allow-Origin: * gönderiyor. Sonuç?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

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.

Hızlı kontrolOrta

CORS bir sunucuyu kötü niyetli isteklerden korur mu?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

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
Proje dosyaları

src/main/java/com/bank/web/ SecurityConfig.java Spring Security: CORS filtre zincirinde, kimlik doğrulamadan önce ön kontrolü cevaplıyor.

src/main/java/com/bank/web/SecurityConfig.java
@Configuration
class SecurityConfig {
@Bean
SecurityFilterChain api(HttpSecurity http) throws Exception {
return http
.cors(Customizer.withDefaults()) // uses the CorsConfigurationSource bean below
.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
.build();
}
}

src/main/java/com/bank/web/ CorsConfig.java İzin listesi: tek origin, gereken metotlar ve başlıklar, çerez için credentials.

src/main/java/com/bank/web/CorsConfig.java
@Configuration
class CorsConfig {
@Bean
CorsConfigurationSource corsConfigurationSource(@Value("${app.allowed-origins}") List<String> origins) {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(origins); // an explicit list, never "*"
config.setAllowedMethods(List.of("GET", "POST"));
config.setAllowedHeaders(List.of("Content-Type", "Idempotency-Key"));
config.setAllowCredentials(true); // the session cookie travels
config.setMaxAge(Duration.ofMinutes(30)); // fewer preflights
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/api/**", config);
return source;
}
}

src/main/resources/ application.yml Yerel geliştirme: ayrı bir profil, üretim listesine dokunmuyor.

src/main/resources/application.yml
app:
allowed-origins: https://app.bank.example
---
spring:
config:
activate:
on-profile: local
app:
allowed-origins: http://localhost:5173

src/features/transfer/ api.ts İstemci: çerezli istek credentials: include ile gönderiliyor.

src/features/transfer/api.ts
export async function listAccounts(): Promise<Account[]> {
const response = await fetch('https://api.bank.example/api/accounts', {
credentials: 'include', // send the session cookie across origins
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}

Kendini sına

Şimşek turu1/4

CORS kuralını curl ve Postman de uygular.

Soru 1/3İleri

Sunucu gelen her isteğin Origin başlığını Access-Control-Allow-Origin'e aynen yazıyor ve credentials'a izin veriyor. Risk nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Aklında kalacak üç şey

  1. 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. 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. 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.
Sonraki kapı Ekran canlı güncellensin istiyorsun. Her iki saniyede bir sormak neden kötü bir fikir? Canlı Veri — Polling, SSE ve WebSocket · 9 dk

4 kart sonraki derste seni bekliyor

0/4 kart bu dersten toplandı