Retour au Blog
Plateforme

Limites CORS : en-tetes, preflight, identifiants et cache

Diagnostiquer les requetes cross-origin sans confondre CORS avec le reseau, la CSP, Permissions Policy ou l autorisation serveur.

BotBrowser Team

Documentation

Vous voulez la documentation structurée pour Plateforme ?

Cet article fait partie de la bibliothèque éditoriale. Pour les étapes de configuration, la référence et les mises à jour continues, passez directement à la section docs.

Le navigateur separe accessibilite des reponses, partage CORS, identifiants et traitement applicatif

Cross-Origin Resource Sharing (CORS) est un protocole de partage de reponse controle par le navigateur. Il repond a une question precise : un script d une page peut-il lire la reponse d une requete vers une autre origine ? CORS ne rend pas une route joignable, n autorise pas un compte sur le serveur et ne rend pas une API tierce fiable. Un serveur peut renvoyer 200 tandis que JavaScript recoit une erreur CORS : l echange reseau a reussi, mais Fetch a masque la reponse. Enregistre separement URL, origine, statut, en-tetes, console et etat visible. Les references principales sont le [protocole CORS de Fetch](https://fetch.spec.whatwg.org/#http-cors-protocol) et le [guide CORS MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS). ## Origines et reponses simples Une origine comprend schema, hote et port. Deux sous-domaines sont donc cross-origin. Pour partager une reponse, le serveur renvoie habituellement `Access-Control-Allow-Origin: `. Le navigateur compare cette valeur a l origine de la page ; le script ne peut pas choisir librement `Origin`. Utilise une liste d origines autorisees et ne reflete jamais toute valeur entrante. Les requetes `GET`, `HEAD` ou `POST` avec en-tetes et types safelisted peuvent eviter le preflight. La reponse doit tout de meme contenir une politique compatible. `mode: 'no-cors'` donne une reponse opaque, pas un contournement ; `mode: 'same-origin'` refuse une destination cross-origin. ## Preflight Une requete avec `Authorization`, JSON, methode non simple ou en-tete non safelisted commence souvent par `OPTIONS` : ```http Origin: Access-Control-Request-Method: POST Access-Control-Request-Headers: authorization, content-type ``` La reponse doit autoriser explicitement origine, methode et en-tetes : ```http Access-Control-Allow-Origin: Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: authorization, content-type Access-Control-Max-Age: 300 Vary: Origin ``` Le navigateur valide cette reponse avant d envoyer la requete reelle. Un `OPTIONS` redirige, authentifie ou renvoyant 4xx peut donc bloquer le flux avant l API. `Access-Control-Allow-Methods` ne remplace jamais l autorisation d un utilisateur. Le cache de preflight peut aussi conserver une ancienne politique ; un contexte neuf aide a tester une configuration actuelle. ## Identifiants et caches Les cookies cross-origin exigent `credentials: 'include'`, un origin explicite et `Access-Control-Allow-Credentials: true`. Le joker `*` est incompatible avec une reponse lisible avec identifiants. `SameSite`, `Secure`, le domaine du cookie, l autorisation et la protection CSRF restent independants. Si la valeur Allow-Origin varie, ajoute `Vary: Origin` afin qu un CDN ne serve pas la reponse d un origin a un autre. Les caches navigateur, preflight, service worker, proxy et CDN peuvent tous modifier l observation. Un test deterministe utilise un BrowserContext neuf et capture les en-tetes recels. ## CORS, CSP et Permissions Policy | Controle | Question | Preuve | Ne prouve pas | | --- | --- | --- | --- | | Reseau/DNS | URL joignable ? | DNS, TLS, connexion | Reponse lisible ou autorisee | | CORS | JavaScript peut lire ? | `Access-Control-Allow-*`, Fetch | Autorisation serveur ou metier fini | | CSP | Quelles destinations sont permises ? | `connect-src`, rapports | Permission CORS | | Permissions Policy | Quelle fonction peut utiliser le document ? | Politique et `allow` iframe | Permission utilisateur ou CORS | [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) peut bloquer `connect-src` avant une reponse CORS. [Permissions Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Permissions_Policy) regit les fonctions dans un document ou une iframe ; elle ne partage pas le corps d une API. Ne baisse pas une politique pour masquer un autre diagnostic. ## Fixture control/candidate possede Expose une route de test `https://api.example.test/cors-fixture` et deux pages a `https://app.example.test/control` et `https://app.example.test/candidate`. Elles utilisent le meme corps et la meme route joignable. Seule control recoit `Access-Control-Allow-Origin: `; candidate l omet. Le bouton lance la requete, et un element de statut visible rend le resultat testable. ```js import { chromium } from 'playwright'; import http from 'node:http'; import assert from 'node:assert/strict';

let pageOrigin = ''; let apiOrigin = ''; const observations = []; const listen = server => new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); const close = server => new Promise(resolve => server.close(resolve)); const api = http.createServer((request, response) => { const name = request.url.slice(1); if (name === 'control') response.setHeader('Access-Control-Allow-Origin', pageOrigin); observations.push({ name, status: 200, allowOrigin: response.getHeader('Access-Control-Allow-Origin') || null }); response.writeHead(200, { 'Content-Type': 'application/json' }); response.end('{"fixture":true}'); }); const pageServer = http.createServer((request, response) => { const name = request.url.slice(1); response.end(<button>Run CORS check</button><output data-testid="cors-status"></output><script> document.querySelector('button').onclick = async () => { try { await fetch('${apiOrigin}/${name}'); document.querySelector('output').textContent = 'CORS_ALLOWED'; } catch { document.querySelector('output').textContent = 'FETCH_UNCLASSIFIED'; } };</script>); }); await listen(api); await listen(pageServer); const apiPort = api.address().port; const pagePort = pageServer.address().port; pageOrigin = http://127.0.0.1:${pagePort}; apiOrigin = http://127.0.0.1:${apiPort}; const browser = await chromium.launch(); const context = await browser.newContext(); context.setDefaultNavigationTimeout(8_000); async function runCase(name) { const page = await context.newPage(); try { await page.goto(${pageOrigin}/${name}); await page.getByRole('button', { name: 'Run CORS check' }).click(); await page.locator('[data-testid="cors-status"]').waitFor({ state: 'visible', timeout: 5_000 }); return await page.locator('[data-testid="cors-status"]').textContent(); } catch { return 'UNKNOWN'; } finally { await page.close(); } } try { const control = await runCase('control'); const candidate = await runCase('candidate'); assert.equal(control, 'CORS_ALLOWED'); assert.equal(candidate, 'FETCH_UNCLASSIFIED'); assert.deepEqual(observations.map(({ name, allowOrigin }) => ({ name, allowOrigin })), [ { name: 'control', allowOrigin: pageOrigin }, { name: 'candidate', allowOrigin: null } ]); } finally { await context.close(); await browser.close(); await close(pageServer); await close(api); }

Control doit afficher `CORS_ALLOWED` apres lecture du corps synthetique. Candidate affiche `FETCH_UNCLASSIFIED` apres le rejet Fetch; cet etat seul ne prouve pas CORS. Confirme `CORS_BLOCKED` seulement si le journal de l API possedee montre que les deux routes ont atteint l API et renvoye le meme corps avec 200, que candidate omet Allow-Origin, et que control a lu la reponse avec l origine exacte de la page.

Une erreur de navigation, statut ou serveur reste `UNKNOWN`; elle ne doit pas etre attribuee au reseau ni a CORS. La navigation est limitee a huit secondes et chaque page est fermee dans cleanup.

## Tableau de diagnostic

| Observation                        | Proprietaire initial | Verification                          | Conclusion prudente                 |
| ---------------------------------- | -------------------- | ------------------------------------- | ----------------------------------- |
| DNS, TLS ou connexion echoue       | Reseau               | Route, proxy, service                 | Aucune reponse CORS                 |
| Preflight 4xx/5xx                  | API                  | Route OPTIONS et en-tetes             | Echange prealable echoue            |
| 200 mais corps illisible           | API/navigateur       | Origin, identifiants, headers exposes | Partage refuse ou opaque            |
| Cookie absent                      | Auth/navigateur      | mode d identifiants, SameSite, Secure | CORS ne rend pas le cookie eligible |
| Origines avec resultats differents | API/cache            | Liste et `Vary: Origin`               | Politique ou cache differents       |
| Violation CSP                      | Securite web         | `connect-src`, rapports               | Blocage CSP                         |

Ce que BotBrowser etablit
Les BrowserContexts controles de BotBrowser peuvent executer des fixtures CORS autorises et possedes, isoler cookies et stockage synthetiques et comparer des resultats Fetch visibles sur un build declare. La [documentation d isolation multi-compte](https://botbrowser.io/docs/identity/multi-account-isolation/) explique cette limite.

Pour valider CORS, BotBrowser peut executer la comparaison control/candidate, mais ne peut pas configurer la reponse API ni contourner la regle de partage du navigateur.
BotBrowser ne redige ni ne deploie les en-tetes CORS, n accorde pas l autorisation serveur, ne repare pas une API tierce, ne change pas l origine et ne contourne pas l enforcement du navigateur. Il ne prouve pas non plus l achevement d une operation distante. Ces faits restent ceux du serveur, du CDN et de l application.
Checklist

1. Declare les deux origines, methode, en-tetes, mode d identifiants et resultat attendu.
2. Verifie reseau et route avant une erreur de politique.
3. Capture Origin, preflight, statut, en-tetes, `Vary` et cache.
4. Separe CORS, CSP, Permissions Policy, permission utilisateur et autorisation.
5. Utilise huit secondes pour la navigation et cinq pour le statut, puis nettoie.
6. Conserve les types reseau, timeout, preflight et CORS distincts.
   **Auteur :** BotBrowser Team
   Voir le [guide d isolation cross-origin](/fr/blog/cross-origin-isolation-and-shared-memory-requirements/) et le [guide Permissions Policy](/fr/blog/permissions-policy-for-embedded-browser-features/).

## Sources

- Fixture URL (example only): https://app.example.test`
- Fixture URL (example only): https://app.example.test/control`

- [Protocole CORS Fetch](https://fetch.spec.whatwg.org/#http-cors-protocol)
- [CORS sur MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
- [CSP sur MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [Permissions Policy sur MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Permissions_Policy)
#CORS#Requete Cross-Origin#Fetch#Securite Web

Faites passer BotBrowser de la recherche à la production

Utilisez ces guides pour comprendre le modèle, puis passez à la validation multi-plateforme, aux contextes isolés et au déploiement navigateur prêt pour l'échelle.