CORS w Pythonie - jak naprawić błędy i zabezpieczyć API

Tymoteusz Kowalski 6 września 2026
Fetch API bez błędów CORS dzięki Corsfix. Przykład kodu pokazuje, jak pobrać dane z dowolnego URL-a.

Spis treści

Przeglądarka blokuje odczyt danych z obcego serwera, choć samo API działa poprawnie? Najczęściej odpowiada za to CORS, czyli mechanizm, który pozwala serwerowi określić, z jakich źródeł aplikacja może bezpiecznie odczytywać odpowiedzi. Wyjaśniam, jak działa, czym różni się zwykłe żądanie od preflightu, jak skonfigurować CORS w Pythonie i dlaczego zbyt szerokie reguły mogą osłabić bezpieczeństwo.

CORS określa, które aplikacje mogą czytać odpowiedzi API

  • Mechanizm przeglądarki kontroluje dostęp między różnymi źródłami.
  • Na źródło składają się schemat, host i port.
  • Przy bardziej złożonych żądaniach przeglądarka wysyła wcześniej żądanie OPTIONS preflight.
  • Najważniejszy nagłówek to Access-Control-Allow-Origin.
  • Gwiazdka nie pasuje do żądań z ciasteczkami lub innymi poświadczeniami.
  • CORS nie zastępuje autoryzacji ani ochrony przed CSRF.

Czym jest CORS i skąd bierze się problem

CORS oznacza Cross-Origin Resource Sharing, czyli współdzielenie zasobów między różnymi źródłami. To zestaw reguł opartych na nagłówkach HTTP, dzięki którym serwer informuje przeglądarkę, czy kod JavaScript może odczytać zwrócone dane.

Domyślnie działa tutaj zasada same-origin policy. Ogranicza ona skrypty uruchomione na jednej stronie, aby nie mogły swobodnie czytać danych z innych aplikacji. Trudno uznać to za zbędną przeszkodę. Bez takiej ochrony przypadkowa strona mogłaby próbować odczytywać informacje z panelu bankowego lub firmowego systemu otwartego w tej samej przeglądarce.

Origin to nie tylko domena

Źródło, nazywane też originem, tworzą trzy elementy: schemat, host i port. Z tego powodu aplikacje działające na `http://localhost:3000` i `http://localhost:8000` mają różne źródła, mimo że korzystają z tego samego komputera.

Przykład Czy to to samo źródło Powód
http://localhost:3000 i http://localhost:8000 Nie Inny port
http://app.example i https://app.example Nie Inny schemat
https://app.example i https://api.example Nie Inny host
https://app.example i https://app.example Tak Identyczny origin

CORS nie jest zaporą dla całego internetu

Reguły CORS egzekwuje przede wszystkim przeglądarka. Narzędzia takie jak klient HTTP, skrypt backendowy czy polecenie wysyłające żądanie bezpośrednio do API zwykle nie stosują tych ograniczeń. Dlatego fakt, że żądanie działa w Postmanie, nie oznacza jeszcze, że zadziała w kodzie JavaScript.

CORS kontroluje możliwość odczytania odpowiedzi przez skrypt. Nie jest systemem logowania i nie decyduje samodzielnie, czy użytkownik ma prawo wykonać operację. To rozróżnienie ma ogromne znaczenie przy projektowaniu bezpiecznego API.

Diagram wyjaśnia, cors co to: klient pobiera zasoby z serwera origin, a serwer zezwala na dostęp z innej domeny.

Jak przeglądarka sprawdza zgodę serwera

Przeglądarka dołącza do żądania nagłówek Origin. Serwer powinien odpowiedzieć nagłówkiem określającym, czy dane źródło jest dozwolone. Jeśli odpowiedź nie zawiera właściwej zgody, kod JavaScript zobaczy błąd CORS zamiast danych.

Żądanie proste

Niektóre żądania mogą zostać wysłane od razu. Dotyczy to między innymi wybranych żądań GET, HEAD i POST, które używają dozwolonych nagłówków oraz typów danych. Przeglądarka nadal sprawdza odpowiedź, ale nie musi wcześniej pytać serwera o pozwolenie.

Preflight, czyli kontrola przed właściwym żądaniem

Jeśli żądanie używa na przykład metody PUT, PATCH lub DELETE, nagłówka Authorization albo typu application/json, przeglądarka może najpierw wysłać żądanie OPTIONS. Ten etap nazywa się preflightem.

  1. Przeglądarka wysyła OPTIONS z informacją o źródle, metodzie i planowanych nagłówkach.
  2. Serwer odpowiada, jakie źródła, metody i nagłówki akceptuje.
  3. Dopiero po pozytywnej odpowiedzi przeglądarka wysyła właściwe żądanie.
  4. Jeśli preflight się nie powiedzie, kod aplikacji nie otrzyma normalnej odpowiedzi.

Przykładowe żądanie kontrolne może zawierać Access-Control-Request-Method: POST oraz Access-Control-Request-Headers: Content-Type, Authorization. Serwer musi wtedy wyraźnie dopuścić te elementy, inaczej przeglądarka zatrzyma dalszy etap.

W praktyce wiele problemów wynika z pominięcia obsługi metody OPTIONS. Backend zwraca wtedy kod 404 lub 405, chociaż właściwy endpoint POST działa bez zarzutu. To jeden z pierwszych elementów, które sprawdzam podczas diagnozowania błędu.

Najważniejsze nagłówki CORS bez zbędnej magii

Konfiguracja opiera się na kilku nagłówkach odpowiedzi. Nie trzeba stosować wszystkich w każdym projekcie. Najbezpieczniej ustawić tylko te, które są potrzebne do konkretnego scenariusza.

Nagłówek Do czego służy Praktyczna wskazówka
Access-Control-Allow-Origin Wskazuje dozwolone źródło Użyj konkretnego originu, gdy API nie jest publiczne
Access-Control-Allow-Methods Określa akceptowane metody Dodaj tylko metody faktycznie używane
Access-Control-Allow-Headers Dopuszcza niestandardowe nagłówki żądania Często potrzebny dla Content-Type i Authorization
Access-Control-Allow-Credentials Pozwala udostępnić odpowiedź przy poświadczeniach Wartość musi wynosić true
Access-Control-Expose-Headers Udostępnia JavaScriptowi wybrane nagłówki odpowiedzi Przydatny na przykład dla własnego nagłówka z identyfikatorem
Access-Control-Max-Age Określa czas zapamiętania wyniku preflightu Zmniejsza liczbę dodatkowych żądań OPTIONS

Najprostsza odpowiedź dla publicznego API bez ciasteczek może wyglądać tak:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Content-Type

Gwiazdka oznacza dowolne źródło, ale ma sens głównie przy publicznych danych bez poświadczeń. Gdy aplikacja wysyła ciasteczka lub korzysta z uwierzytelniania sesyjnego, trzeba podać konkretny origin. Połączenie Access-Control-Allow-Origin: * z Access-Control-Allow-Credentials: true zostanie odrzucone przez przeglądarkę.

Jeśli serwer dynamicznie wybiera dozwolone źródło z listy, powinien zwykle dodać także Vary: Origin. Informuje to pamięć podręczną, że odpowiedź może być różna zależnie od nagłówka Origin. Bez tego można otrzymać nieprawidłową wersję odpowiedzi z cache.

Konfiguracja CORS w aplikacji Python

W Pythonie najwygodniej korzystać z middleware dostarczanego przez framework. Kluczowa zasada pozostaje jednak taka sama: lista zaufanych źródeł powinna być jawna, a nie tworzona przez bezrefleksyjne odbijanie wartości z nagłówka Origin.

FastAPI

W FastAPI konfigurację dodaje się zwykle na poziomie aplikacji. Przykład dopuszcza panel działający pod jednym, konkretnym adresem:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

trusted_origins = [
    "https://panel.example"
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=trusted_origins,
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Content-Type", "Authorization"],
)

Jeśli logowanie odbywa się tokenem przesyłanym w nagłówku, Authorization musi znaleźć się na liście dozwolonych nagłówków. Przy sesji opartej na ciasteczkach potrzebne jest również allow_credentials=True oraz poprawne ustawienia ciasteczka, między innymi SameSite i .

Flask

We Flasku popularnym rozwiązaniem jest rozszerzenie konfigurujące nagłówki automatycznie:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)

CORS(
    app,
    resources={
        r"/api/*": {
            "origins": ["https://panel.example"]
        }
    },
    supports_credentials=True
)

Ograniczenie reguły do ścieżki /api/* jest rozsądniejsze niż otwarcie CORS dla całej aplikacji. Endpoint zwracający dane publiczne może mieć inną politykę niż panel administracyjny, dlatego konfigurację dobrze dopasować do konkretnego zasobu.

Najczęstsze błędy i szybka diagnostyka

Brak nagłówka po stronie serwera

Komunikat o braku Access-Control-Allow-Origin oznacza najczęściej, że serwer nie dodał zgody do odpowiedzi albo dodał ją tylko dla właściwego żądania, pomijając OPTIONS. Sprawdź odpowiedź w zakładce Network i zobacz, czy nagłówek występuje zarówno przy preflighcie, jak i przy właściwym żądaniu.

Źródło różni się drobnym szczegółem

Origin musi pasować dokładnie. Różnicę robi port, schemat, końcowy zapis hosta lub środowisko. Adres deweloperski z portem 3000 nie jest tym samym co wersja produkcyjna działająca bez tego portu. Warto też pamiętać, że `http` i `https` nie są wymienne.

Gwiazdka przy ciasteczkach

To bardzo częsta pomyłka. Jeśli frontend wysyła żądanie z credentials: "include", serwer musi zwrócić konkretny origin oraz Access-Control-Allow-Credentials: true. Samo ustawienie opcji po stronie frontendu nie wystarczy.

Próba naprawy przez no-cors

Ustawienie mode: "no-cors" zwykle nie rozwiązuje problemu. Odpowiedź staje się wtedy nieprzejrzysta, czyli kod JavaScript nie może odczytać jej treści ani statusu w normalny sposób. Ta opcja nadaje się tylko do wąskich scenariuszy, w których nie potrzebujesz analizować odpowiedzi.

Przeczytaj również: React Virtual DOM - Jak działa i kiedy naprawdę pomaga UX?

Prosta kolejność sprawdzania

  1. Porównaj origin frontendu z listą dozwolonych źródeł na backendzie.
  2. Sprawdź, czy preflight OPTIONS otrzymuje kod sukcesu, zwykle 200 lub 204.
  3. Porównaj metodę i nagłówki żądania z wartościami w odpowiedzi serwera.
  4. Zweryfikuj ustawienia credentials po obu stronach.
  5. Sprawdź, czy proxy, load balancer albo serwer produkcyjny nie usuwa nagłówków CORS.

Nie próbuję zgadywać na podstawie samego komunikatu w konsoli. Najwięcej informacji daje porównanie dwóch konkretnych żądań w narzędziach deweloperskich, zwłaszcza nagłówków Origin, Access-Control-Request-Method i Access-Control-Allow-Origin.

Dlaczego CORS nie zastępuje autoryzacji

CORS ogranicza to, co przeglądarka udostępni skryptowi, ale nie zastępuje kontroli dostępu na serwerze. Złośliwa strona może w niektórych scenariuszach doprowadzić do wysłania żądania zmieniającego dane, nawet jeśli później nie otrzyma możliwości odczytania odpowiedzi.

Dlatego przy operacjach takich jak zmiana hasła, przelew czy usunięcie konta potrzebna jest osobna ochrona CSRF, poprawna autoryzacja i walidacja danych po stronie backendu. CORS nie powinien być traktowany jako jedyna bariera bezpieczeństwa.

Najmniej ryzykowna konfiguracja wygląda zwykle tak:

  • dla publicznych danych bez logowania można użyć ściśle kontrolowanego dostępu publicznego,
  • dla panelu użytkownika należy wskazać konkretne originy,
  • dla żądań z ciasteczkami trzeba skonfigurować credentials i ochronę CSRF,
  • metody oraz nagłówki powinny być ograniczone do rzeczywiście potrzebnych,
  • nie należy automatycznie akceptować każdego originu przesłanego przez klienta.

Odbijanie nagłówka Origin bez sprawdzenia go na allowliście wygląda wygodnie, ale może otworzyć dostęp dowolnej stronie. W systemach przetwarzających dane użytkowników taki skrót jest zwykle złym kompromisem.

Najpierw zaufane źródła, potem otwieranie API

CORS można sprowadzić do jednej praktycznej decyzji: które aplikacje naprawdę muszą czytać odpowiedzi tego API? Gdy odpowiesz na to pytanie, ustaw konkretną listę originów, obsłuż OPTIONS, dopasuj metody i nagłówki oraz osobno zadbaj o uwierzytelnianie i CSRF.

Sam błąd CORS nie świadczy jeszcze o awarii API. Często oznacza, że przeglądarka prawidłowo zatrzymała odczyt odpowiedzi, bo serwer nie wyraził wystarczająco precyzyjnej zgody. Dobra konfiguracja nie polega na wyłączeniu zabezpieczenia, tylko na udostępnieniu dokładnie tego, co jest potrzebne.

FAQ - Najczęstsze pytania

Postman i skrypty backendowe zwykle nie stosują ograniczeń CORS, które egzekwuje przeglądarka. Przeglądarka sprawdza nagłówek Origin oraz zgodę serwera w Access-Control-Allow-Origin, dlatego poprawnie działające API może być niedostępne dla kodu JavaScript.

Preflight może pojawić się przy żądaniach używających metod takich jak PUT, PATCH i DELETE, nagłówka Authorization albo typu application/json. Serwer musi odpowiedzieć, jakie źródła, metody i nagłówki dopuszcza, inaczej właściwe żądanie nie zostanie wysłane.

Gwiazdka oznacza dowolne źródło i nadaje się głównie do publicznych danych bez poświadczeń. Przy żądaniach z ciasteczkami trzeba wskazać konkretny origin oraz zwrócić Access-Control-Allow-Credentials: true; połączenie gwiazdki z credentials zostanie odrzucone przez przeglądarkę.

W FastAPI można użyć CORSMiddleware z jawną listą zaufanych originów, dozwolonych metod i nagłówków, takich jak Content-Type oraz Authorization. We Flasku popularnym rozwiązaniem jest flask-cors, a regułę warto ograniczyć do zasobów /api/*. CORS nie zastępuje autoryzacji ani ochrony CSRF.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

preflight
flask
csrf
fastapi
cors
Autor Tymoteusz Kowalski
Tymoteusz Kowalski
Nazywam się Tymoteusz Kowalski i od 7 lat zajmuję się programowaniem, ze szczególnym uwzględnieniem Pythona oraz nowoczesnych technologii. Moja przygoda z programowaniem zaczęła się od fascynacji możliwościami, jakie daje kod, a z czasem przerodziła się w pasję do dzielenia się wiedzą i pomagania innym w zrozumieniu złożonych zagadnień. Interesuje mnie, jak można uprościć trudne tematy, aby były bardziej przystępne dla każdego, niezależnie od poziomu zaawansowania. W moich tekstach staram się dostarczać rzetelne, aktualne i zrozumiałe informacje, a także porównywać różne źródła, aby zapewnić czytelnikom szeroki kontekst. Piszę o praktycznych zastosowaniach Pythona, nowinkach technologicznych oraz najlepszych praktykach programistycznych. Moim celem jest nie tylko przedstawienie teorii, ale także pokazanie, jak można ją zastosować w praktyce, co mam nadzieję, uczyni moją twórczość użyteczną dla każdego, kto pragnie rozwijać swoje umiejętności w programowaniu.

Udostępnij artykuł

Napisz komentarz