Ghid complet pentru rezolvarea problemei de netrimitere a cookie-urilor în cererile Cross-Origin (CORS)

Dacă v-ați confruntat cu un scenariu în care serverul setează corect cookie-ul (vizibil în răspunsul browserului), dar în cererile ulterioare, browserul nu returnează acel cookie către server, acest ghid este pentru dvs. Această problemă apare aproape întotdeauna atunci când frontend-ul și backend-ul proiectului dvs. se află pe două domenii sau porturi diferite — de exemplu, frontend-ul pe app.example.com și API-ul pe api.example.com.

De ce se întâmplă acest lucru?

Browser-ele moderne impun două politici de securitate stricte pentru a preveni atacurile CSRF și deturnarea sesiunii:

  1. Politica CORS: În mod implicit, browserul nu permite cererilor între domenii să includă credențiale (cum ar fi cookie-uri) decât dacă serverul permite în mod explicit acest lucru.
  2. Politica SameSite: Începând cu Chrome 80, cookie-urile sunt tratate în mod implicit cu comportamentul SameSite=Lax, ceea ce înseamnă că nu vor fi trimise în cererile între domenii decât dacă sunt definite în mod explicit cu SameSite=None.

Punctul important este că, pentru a rezolva această problemă, atât partea de client, cât și cea de server trebuie configurate corect. Modificarea doar a unei părți nu este suficientă.

Pasul 1: Configurarea corectă a serverului

Trei reguli de aur pe partea de server

Regula 1 — Activarea credențialelor: Antetul de răspuns al serverului trebuie să includă următoarea valoare:

Access-Control-Allow-Credentials: true

Regula 2 — Fără wildcard: Când credențialele sunt activate, nu puteți utiliza caracterul wildcard * în antetul Access-Control-Allow-Origin. Trebuie să specificați exact adresa completă de domeniu a frontend-ului:

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

Regula 3 — Atributele cookie-ului: Cookie-ul trebuie setat cu două atribute: SameSite=None și Secure. Fără aceste două atribute, browserul va stoca cookie-ul, dar nu îl va trimite niciodată în cererile între domenii.

Cod exemplu în Node.js (Express)

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

const app = express();

app.use(cors({
  origin: 'https://app.example.com', // Domeniul exact al frontend-ului, fără /
  credentials: true
}));

app.post('/login', (req, res) => {
  res.cookie('session_token', 'abc123', {
    httpOnly: true,   // Împiedică accesul JavaScript la cookie
    secure: true,     // Trimis doar prin HTTPS
    sameSite: 'none', // Permite trimiterea în cereri Cross-Origin
    maxAge: 24 * 60 * 60 * 1000
  });
  res.json({ message: 'Autentificare reușită' });
});

Cod exemplu în PHP

<?php
// Specificați domeniul exact al frontend-ului, nu *
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");

// Răspuns la cererea Preflight
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

// Setarea cookie-ului cu atributele necesare
setcookie('session_token', 'abc123', [
    'expires'  => time() + 86400,
    'path'     => '/',
    'secure'   => true,      // Obligatoriu
    'httponly' => true,
    'samesite' => 'None'     // Obligatoriu pentru Cross-Origin
]);

Notă: Dacă utilizați Laravel, setați supports_credentials la true în fișierul config/cors.php și adăugați domeniul frontend-ului în tabloul allowed_origins.

Pasul 2: Configurarea corectă a clientului (frontend)

Chiar și cu o configurare completă a serverului, browserul tot nu va trimite cookie-uri decât dacă declarați în mod explicit pe partea de client că această cerere este "cu credențiale".

Utilizarea Fetch API

fetch('https://api.example.com/user/profile', {
  method: 'GET',
  credentials: 'include'  // Această linie este cheia pentru rezolvarea problemei
})
  .then(res => res.json())
  .then(data => console.log(data));

Utilizarea Axios

// Pentru o cerere specifică
axios.get('https://api.example.com/user/profile', {
  withCredentials: true
});

// Sau global pentru întregul proiect
axios.defaults.withCredentials = true;

Listă de verificare pentru depanare

Dacă problema persistă după aplicarea celor de mai sus, verificați aceste elemente în ordine:

  • Ambele părți sunt pe HTTPS? Atributul Secure înseamnă că cookie-ul funcționează doar pe conexiuni criptate. Dacă site-ul dvs. este pe HTTP, browserul nu va accepta cookie-ul. (Excepție: mediul de dezvoltare pe localhost)
  • Adresa Origin este exactă? Adresa Access-Control-Allow-Origin trebuie să se potrivească exact cu URL-ul pe care îl vedeți în browser. Chiar și o diferență în www sau o bară oblică finală / va cauza eșec.
  • Cererea OPTIONS este reușită? În fila Network a instrumentelor de dezvoltare ale browserului, verificați cererea Preflight (cu metoda OPTIONS). Această cerere trebuie să fie răspunsă cu codul 200 sau 204 și antete CORS corecte.
  • Cookie-ul este stocat? În browser, accesați DevTools ← Application ← Cookies și asigurați-vă că cookie-ul este stocat cu atributele Secure și SameSite=None.
  • Aveți un proxy sau un firewall intermediar? Uneori, Cloudflare sau serverele web precum Nginx rescriu antetele. Verificați și configurația acestora.

Rezumat

Trimiterea cookie-urilor în cererile între domenii necesită coordonarea a trei factori: serverul cu Access-Control-Allow-Credentials: true și Origin exact, cookie-ul cu atributele SameSite=None; Secure și clientul cu activarea credentials: 'include' sau withCredentials: true. Urmând aceste trei puncte, problema va fi complet rezolvată.


Infrastructură fiabilă, liniște pentru dezvoltatori

Implementarea corectă a CORS și gestionarea cookie-urilor este doar o parte a poveștii; infrastructura pe care rulează proiectul dvs. joacă, de asemenea, un rol decisiv în stabilitatea și securitatea serviciului:

Radib Hosting — Găzduire web de mare viteză cu suport complet pentru SSL gratuit și configurare standard a antetelor; o alegere ideală pentru găzduirea frontend-ului și backend-ului proiectelor dvs.

Radib Virtual Server — Dacă proiectul dvs. necesită acces complet, resurse dedicate și libertate în configurarea serverului web (Nginx/Apache), serverele virtuale Radib cu hardware puternic și rețea stabilă sunt cea mai bună alegere pentru API-uri profesionale.

Radib Debugging and Security Services — Dacă vă confruntați cu erori complexe CORS, probleme de autentificare sau provocări de securitate, echipa tehnică Radib, cu experiență profundă în depanarea și securizarea aplicațiilor web, este aici pentru a vă ajuta să rezolvați problema din rădăcină.

 

Răspunsul a fost util? 112 utilizatori au considerat informația utilă (112 Voturi)