Komplexní průvodce řešením problému neodesílání cookies v požadavcích mezi různými doménami (CORS)

Pokud jste se setkali se scénářem, kdy server správně nastaví cookie (viditelné v odpovědi prohlížeče), ale v následujících požadavcích prohlížeč tuto cookie serveru nevrátí, tento průvodce je pro vás. K tomuto problému dochází téměř vždy, když jsou frontend a backend vašeho projektu na dvou různých doménách nebo portech — například frontend na app.example.com a API na api.example.com.

Proč k tomu dochází?

Moderní prohlížeče zavádějí dvě přísné bezpečnostní politiky, aby zabránily CSRF útokům a krádeži relací:

  1. Politika CORS: Ve výchozím nastavení prohlížeč nepovoluje požadavkům mezi doménami zahrnovat přihlašovací údaje (například cookies), pokud to server výslovně nepovolí.
  2. Politika SameSite: Od Chrome 80 jsou cookies ve výchozím nastavení považovány za chování SameSite=Lax, což znamená, že nebudou odesílány v požadavcích mezi doménami, pokud nejsou výslovně definovány s SameSite=None.

Důležité je, že k vyřešení tohoto problému musí být správně nakonfigurována jak klientská, tak serverová strana. Úprava pouze jedné strany nestačí.

Krok 1: Správná konfigurace serveru

Tři zlatá pravidla na straně serveru

Pravidlo 1 — Povolení přihlašovacích údajů: Hlavička odpovědi serveru musí obsahovat následující hodnotu:

Access-Control-Allow-Credentials: true

Pravidlo 2 — Žádné zástupné znaky: Když jsou povoleny přihlašovací údaje, nemůžete v hlavičce Access-Control-Allow-Origin používat zástupný znak *. Musíte přesně zadat úplnou adresu domény frontendu:

Access-Control-Allow-Origin: https://app.example.com

Pravidlo 3 — Atributy cookie: Cookie musí být nastavena se dvěma atributy: SameSite=None a Secure. Bez těchto dvou atributů prohlížeč cookie uloží, ale nikdy ji neodešle v požadavcích mezi doménami.

Ukázkový kód v Node.js (Express)

const express = require('express');
const cors = require('cors');

const app = express();

app.use(cors({
  origin: 'https://app.example.com', // Přesná doména frontendu, bez /
  credentials: true
}));

app.post('/login', (req, res) => {
  res.cookie('session_token', 'abc123', {
    httpOnly: true,   // Zabraňuje přístupu JavaScriptu k cookie
    secure: true,     // Odesílá se pouze přes HTTPS
    sameSite: 'none', // Povoluje odesílání v požadavcích Cross-Origin
    maxAge: 24 * 60 * 60 * 1000
  });
  res.json({ message: 'Přihlášení bylo úspěšné' });
});

Ukázkový kód v PHP

<?php
// Zadejte přesnou doménu frontendu, ne *
header("Access-Control-Allow-Origin: https://app.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");

// Odpověď na Preflight požadavek
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

// Nastavení cookie s požadovanými atributy
setcookie('session_token', 'abc123', [
    'expires'  => time() + 86400,
    'path'     => '/',
    'secure'   => true,      // Povinné
    'httponly' => true,
    'samesite' => 'None'     // Povinné pro Cross-Origin
]);

Poznámka: Pokud používáte Laravel, nastavte supports_credentials na true v souboru config/cors.php a přidejte doménu frontendu do pole allowed_origins.

Krok 2: Správná konfigurace klienta (frontendu)

I při úplné konfiguraci serveru prohlížeč stále nebude odesílat cookies, pokud na klientské straně výslovně neprohlásíte, že tento požadavek je "s přihlašovacími údaji".

Použití Fetch API

fetch('https://api.example.com/user/profile', {
  method: 'GET',
  credentials: 'include'  // Tento řádek je klíčem k vyřešení problému
})
  .then(res => res.json())
  .then(data => console.log(data));

Použití Axios

// Pro konkrétní požadavek
axios.get('https://api.example.com/user/profile', {
  withCredentials: true
});

// Nebo globálně pro celý projekt
axios.defaults.withCredentials = true;

Kontrolní seznam pro odstraňování problémů

Pokud problém přetrvává i po použití výše uvedených kroků, zkontrolujte tyto položky v pořadí:

  • Jsou obě strany na HTTPS? Atribut Secure znamená, že cookie funguje pouze na šifrovaných připojeních. Pokud je váš web na HTTP, prohlížeč cookie nepřijme. (Výjimka: vývojové prostředí na localhost)
  • Je adresa Origin přesná? Adresa Access-Control-Allow-Origin se musí přesně shodovat s URL, kterou vidíte v prohlížeči. Dokonce i rozdíl v www nebo koncové lomítko / způsobí selhání.
  • Je požadavek OPTIONS úspěšný? Na kartě Network ve vývojářských nástrojích prohlížeče zkontrolujte Preflight požadavek (s metodou OPTIONS). Na tento požadavek musí být odpovězeno kódem 200 nebo 204 a správnými CORS hlavičkami.
  • Je cookie uložena? V prohlížeči přejděte na DevTools ← Application ← Cookies a ujistěte se, že je cookie uložena s atributy Secure a SameSite=None.
  • Máte proxy nebo zprostředkující firewall? Někdy Cloudflare nebo webové servery jako Nginx přepisují hlavičky. Zkontrolujte také jejich konfiguraci.

Shrnutí

Odesílání cookies v požadavcích mezi doménami vyžaduje koordinaci tří faktorů: server s Access-Control-Allow-Credentials: true a přesným Origin, cookie s atributy SameSite=None; Secure a klient s aktivací credentials: 'include' nebo withCredentials: true. Dodržením těchto tří bodů bude problém zcela vyřešen.


Spolehlivá infrastruktura, klid pro vývojáře

Správná implementace CORS a správa cookies je pouze částí příběhu; infrastruktura, na které váš projekt běží, hraje také rozhodující roli v stabilitě a zabezpečení služby:

Radib hosting — Rychlý webový hosting s plnou podporou bezplatného SSL a standardní konfigurací hlaviček; ideální volba pro hostování frontendu a backendu vašich projektů.

Radib virtuální server — Pokud váš projekt vyžaduje plný přístup, vyhrazené zdroje a svobodu v konfiguraci webového serveru (Nginx/Apache), Radib virtuální servery s výkonným hardwarem a stabilní sítí jsou nejlepší volbou pro profesionální API.

Radib služby ladění a zabezpečení — Pokud se potýkáte se složitými CORS chybami, problémy s autentizací nebo bezpečnostními výzvami, technický tým Radib s hlubokými zkušenostmi v odstraňování problémů a zabezpečování webových aplikací je tu, aby vám pomohl vyřešit problém od kořene.

 

Byla tato odpověď nápomocná? 112 Uživatelům pomohlo (112 Hlasů)