# CORP vs COEP, deux faces de la même isolation cross-origin (/fr/blog/corp-vs-coep)



Ces deux headers se ressemblent et on les confond sans arrêt, mais ils se tiennent
aux deux extrémités opposées de la même requête. Cross-Origin-Resource-Policy (CORP)
est quelque chose qu'une ressource envoie à propos d'elle-même.
Cross-Origin-Embedder-Policy (COEP) est quelque chose que la page qui embarque
envoie à propos de ce qu'elle acceptera. Une fois que vous savez de quel côté vous
êtes, la confusion se dissipe.

En bref : [CORP](/fr/docs/web-security/security-headers/cross-origin-resource-policy)
est un header de réponse qu'une ressource pose pour déclarer qui peut la charger.
[COEP](/fr/docs/web-security/policies/cross-origin-embedder-policy) est un header que
la page qui embarque pose pour déclarer qu'elle ne charge que des ressources qui ont
accepté. Ce sont deux moitiés du même mécanisme, pas des concurrents, et ils sont
conçus pour être utilisés ensemble.

## CORP vs COEP, la différence en une ligne [#corp-vs-coep-la-différence-en-une-ligne]

CORP est posé **par la ressource** et répond à « qui peut me charger ». COEP est posé
**par la page** et dit « je ne charge que des ressources qui ont accepté ».

Tout le reste en découle. Un CDN, un hébergeur d'images, un serveur de polices, chacun
d'eux est une ressource, donc c'est à lui d'envoyer CORP. La page qui tire ces
ressources est l'embarqueur, donc c'est à l'embarqueur d'envoyer COEP. La ressource
déclare sa propre accessibilité ; la page déclare sa propre règle d'admission.

## Cross-Origin-Resource-Policy, posé par la ressource [#cross-origin-resource-policy-posé-par-la-ressource]

CORP est un header de réponse que le navigateur lit quand une autre origine tente de
charger votre ressource via une requête no-cors (un simple `<img>`, `<script>`,
`<audio>`, ou une feuille de style sans `crossorigin`). Il a d'abord été proposé en
2012 sous la forme d'un header nommé `From-Origin`, puis relancé en 2018 après que
Spectre a fait des données cross-origin dans le mauvais processus une fuite bien
réelle. Il a exactement trois valeurs.

```http
Cross-Origin-Resource-Policy: same-origin
```

* `same-origin` : seule l'origine exactement identique (schéma, hôte et port) obtient
  la ressource. Le choix deny-par-défaut.
* `same-site` : le même domaine enregistrable, donc les sous-domaines sont autorisés.
  C'est ce dont a besoin un `cdn.example.com` qui sert `www.example.com` ;
  `same-origin` le casserait. Une réserve : `same-site` sur une ressource HTTPS
  n'admet pas une page en HTTP simple du même site, donc une configuration à schémas
  mixtes échoue quand même au contrôle.
* `cross-origin` : n'importe quelle origine peut la charger. Cela existe surtout pour
  que des assets réellement publics restent chargeables, y compris par des pages
  isolées par COEP.

Quand le header est absent, le navigateur se comporte comme si `cross-origin` était
posé, donc n'importe quel site peut embarquer votre asset. Poser une valeur, c'est se
**désengager** de cela. Si le navigateur voit une valeur plus stricte que ce que la
requête autorise, le chargement échoue en erreur réseau. Notez que la requête part
quand même et que le serveur répond quand même ; le navigateur jette le corps de la
réponse au lieu de le remettre à la page. Dans Chromium, l'échec apparaît dans les
DevTools comme `net::ERR_BLOCKED_BY_RESPONSE`.

CORP protège contre plusieurs choses distinctes. Il garde votre ressource hors du
processus d'une page attaquante, ce qui est la motivation de canal auxiliaire de type
[Spectre](https://spectreattack.com/) pour laquelle il a été relancé. Il bloque
l'inclusion de script cross-site (XSSI). Et dans les navigateurs qui l'appliquent,
soit la grande majorité, il empêche vos assets d'être affichés sur d'autres sites.
C'est un contrôle d'embarquement, pas une protection de bande passante : les octets
transitent quand même avant que le navigateur ne les écarte, et les clients
non-navigateurs ignorent complètement le header.

## Cross-Origin-Embedder-Policy, posé par la page [#cross-origin-embedder-policy-posé-par-la-page]

COEP est l'autre moitié. Une page envoie `require-corp` pour dire qu'elle ne chargera
une sous-ressource cross-origin que si cette ressource a explicitement accepté.

```http
Cross-Origin-Embedder-Policy: require-corp
```

Voici la partie qui piège les gens. Sous `require-corp`, un header CORP **manquant ou
malformé est traité comme `same-origin`.** Un asset cross-origin qui n'envoie aucun
CORP retombe par défaut sur same-origin du point de vue de l'embarqueur, donc la page
ne peut pas le charger. Ce défaut est exactement ce qui bloque les assets tiers non
étiquetés une fois que vous activez COEP. Chromium le suit même comme une raison de
blocage à part entière, distincte d'un simple décalage CORP : la console affiche
`ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep`. Une ressource
accepte soit en envoyant `Cross-Origin-Resource-Policy: cross-origin`, soit en étant
récupérée via une vraie requête CORS (l'attribut `crossorigin` sur la balise).

COEP s'applique aussi aux iframes, au-delà des simples sous-ressources. Sous
`require-corp`, un document cross-origin embarqué doit envoyer son propre header COEP
compatible, sinon le cadre est bloqué. CORP sur la réponse du cadre ne suffit pas ; le
document encadré doit énoncer sa propre politique d'embedder.

## Comment ils se combinent pour l'isolation cross-origin [#comment-ils-se-combinent-pour-lisolation-cross-origin]

La raison de se soucier des deux à la fois est l'isolation cross-origin. Quand une page
pose `Cross-Origin-Opener-Policy: same-origin` et `Cross-Origin-Embedder-Policy:
require-corp` ensemble, le navigateur la marque cross-origin isolée. Cet état, lisible
en JavaScript via `self.crossOriginIsolated`, est la porte d'accès à
`SharedArrayBuffer` et aux timers haute résolution non bridés. [COOP](/fr/docs/web-security/policies/cross-origin-opener-policy)
gère le côté fenêtre (il place la page dans son propre groupe de contextes de
navigation et coupe les liens `window.opener` vers les pages cross-origin), et COEP
gère le côté sous-ressources. Les deux sont requis.

Cette porte est aussi la raison pour laquelle la plupart des sites qui envoient CORP
ont commencé à le faire. Les navigateurs ont désactivé `SharedArrayBuffer` début 2018
après Spectre. Firefox l'a réintroduit en 2020, conditionné à l'isolation
cross-origin ; Chrome l'avait réactivé plus tôt sur desktop sans cette condition, puis
a exigé l'isolation sur toutes les plateformes en 2021.
Tout ce qui a besoin de mémoire partagée aujourd'hui (threads wasm, ffmpeg.wasm,
éditeurs vidéo dans le navigateur) doit envoyer COEP, et COEP force à son tour chaque
asset cross-origin chargé par la page à porter CORP ou à passer par CORS. Vous ne
pouvez pas atteindre l'état isolé si vos propres assets et votre CDN restent
silencieux. Le
[guide COOP et COEP de l'isolation cross-origin](/fr/blog/coop-coep-cross-origin-isolation)
parcourt la configuration complète.

### Le piège Access-Control-Allow-Origin [#le-piège-access-control-allow-origin]

Un correctif erroné courant consiste à ajouter `Access-Control-Allow-Origin` à une
ressource en s'attendant à satisfaire `require-corp`. Ce n'est pas le cas. Envoyer
`Access-Control-Allow-Origin` sur une réponse no-cors ne fait rien pour COEP. Pour
satisfaire `require-corp`, l'élément doit émettre une vraie requête CORS (l'attribut
`crossorigin`), ou la ressource doit envoyer un header CORP. Un header de réponse CORS
sur une requête qui n'a jamais été faite en mode CORS est ignoré.

### credentialless, l'option à moindre friction [#credentialless-loption-à-moindre-friction]

`Cross-Origin-Embedder-Policy: credentialless` est une alternative plus souple. Au lieu
d'exiger que chaque ressource cross-origin envoie CORP, elle retire les credentials
(pas de cookies, pas de certificats client) des requêtes de sous-ressources no-cors
cross-origin, de sorte que les réponses ne peuvent pas être des données personnalisées
dignes de protection. Elle atteint tout de même l'isolation cross-origin. Deux
limites : elle ne change que les sous-ressources no-cors, donc les requêtes en mode
CORS suivent les règles de `require-corp` et les iframes cross-origin ont toujours
besoin de leur propre header COEP. Et la prise en charge est partielle :
`credentialless` fonctionne dans les navigateurs Chromium et Firefox mais pas Safari,
donc `require-corp` reste le choix interopérable.

### Testez avec Report-Only avant de forcer [#testez-avec-report-only-avant-de-forcer]

COEP a un mode répétition. Envoyez `Cross-Origin-Embedder-Policy-Report-Only:
require-corp` avec un paramètre `report-to` pointant vers un endpoint
[`Reporting-Endpoints`](/fr/docs/web-security/reporting-api/headers/reporting-endpoints),
et le navigateur émet un [report `coep`](/fr/docs/web-security/reporting-api/reports/coep)
pour chaque chargement que le mode strict aurait bloqué, sans rien bloquer. Le corps du
report vous dit si l'échec venait d'un décalage `corp`, d'une `navigation` ou d'une
`worker initialization`, plus l'URL bloquée. Laissez-le tourner un moment, corrigez les
ressources signalées, puis basculez vers le header en mode strict. [CentralCSP ingère
ces reports](/platform/monitoring) aux côtés des violations CSP, donc vous
voyez chaque asset qui aurait été bloqué sur du trafic réel avant vos utilisateurs.

## CORP vs COEP côte à côte [#corp-vs-coep-côte-à-côte]

|                     | Cross-Origin-Resource-Policy                                                                                                      | Cross-Origin-Embedder-Policy                                     |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| Qui le pose         | La ressource (image, script, police, média)                                                                                       | La page qui embarque                                             |
| Ce qu'il déclare    | Qui peut me charger                                                                                                               | Je ne charge que des ressources qui ont accepté                  |
| Valeurs             | `same-origin`, `same-site`, `cross-origin`                                                                                        | `require-corp`, `credentialless`                                 |
| Défaut quand absent | Traité comme `cross-origin`, n'importe qui peut embarquer (mais bascule sur `same-origin` sous le `require-corp` d'un embarqueur) | Aucune politique, isolation cross-origin désactivée              |
| Mode d'échec        | Un chargement bloqué est une erreur réseau, le corps n'est jamais livré                                                           | Les sous-ressources et cadres qui n'ont pas accepté sont bloqués |

## Recommandation [#recommandation]

Traitez les deux ensemble. Posez CORP sur vos propres ressources au niveau dont elles
ont besoin : `same-origin` pour les assets privés, `same-site` là où des sous-domaines
les consomment, et `cross-origin` uniquement sur les assets réellement publics. La
cheat sheet OWASP sur les headers HTTP recommande `same-site` comme référence
générale, avec `require-corp` sur les pages. Quand vous activez `require-corp`,
assurez-vous que chaque asset que cette page charge, vos propres fichiers et ceux de
votre CDN, envoie un header CORP que l'embarqueur acceptera, ou est récupéré avec
`crossorigin`. Recourez à `credentialless` quand changer chaque tierce partie n'est
pas praticable et que vous n'avez pas besoin de Safari, et utilisez le header
Report-Only pour trouver la casse avant de forcer.

Un scanner est le moyen rapide de voir lesquelles de vos réponses portent réellement
CORP et quelles pages affirment COEP. Le [scanner de headers de sécurité](/tools/security-headers)
vérifie les deux sur tout votre site pour que vous repériez les manques avant qu'une
page isolée ne se mette à échouer à charger ses assets.

## FAQ [#faq]

### Ai-je besoin de CORP si j'ai déjà COEP ? [#ai-je-besoin-de-corp-si-jai-déjà-coep-]

Oui, ils couvrent des directions opposées. COEP sur votre page ne fait rien pour
protéger vos propres ressources contre le chargement par d'autres sites ; seul CORP
sur ces réponses le fait. Et dès que votre page envoie `COEP: require-corp`, chaque
asset cross-origin qu'elle charge, y compris votre propre sous-domaine CDN, doit
envoyer CORP ou être récupéré avec CORS, parce qu'un header CORP manquant est traité
comme `same-origin` et bloqué.

### COEP require-corp bloque-t-il les images ? [#coep-require-corp-bloque-t-il-les-images-]

Oui. Un simple `<img>` pointant vers un hôte cross-origin est un chargement no-cors,
et sous `require-corp` il est bloqué (Chromium affiche `net::ERR_BLOCKED_BY_RESPONSE`)
sauf si le serveur d'images envoie `Cross-Origin-Resource-Policy: cross-origin` (ou un
`same-site` correspondant), ou si la balise utilise `crossorigin` et que le serveur
répond avec des headers CORS valides. Si vous ne contrôlez ni l'un ni l'autre, faites
transiter l'image par votre propre origine ou utilisez `COEP: credentialless`.

### Quelle est la différence entre CORP et CORS ? [#quelle-est-la-différence-entre-corp-et-cors-]

Ils vont dans des directions opposées. CORS est un opt-in côté serveur qui accorde un
accès en lecture cross-origin aux réponses des requêtes faites en mode CORS. CORP est
une restriction côté serveur qui retire l'embarquabilité par défaut des chargements
no-cors (images, scripts, médias que n'importe quelle page pouvait historiquement
inclure). CORP n'affecte que les requêtes no-cors, et les headers CORS sur une réponse
no-cors sont ignorés, ce qui explique pourquoi `Access-Control-Allow-Origin` seul ne
satisfait jamais `require-corp`.

### Dois-je utiliser credentialless plutôt que require-corp ? [#dois-je-utiliser-credentialless-plutôt-que-require-corp-]

Une valeur COEP qui atteint l'isolation cross-origin sans exiger CORP de chaque tierce
partie. Les requêtes de sous-ressources no-cors cross-origin partent sans credentials
(pas de cookies, pas de certificats client), donc les réponses ne peuvent pas porter
de données personnalisées. Les requêtes en mode CORS suivent toujours les règles de
`require-corp`, et les iframes cross-origin ont toujours besoin de leur propre header
COEP. Elle fonctionne dans les navigateurs Chromium et Firefox mais pas Safari.

## Articles liés [#articles-liés]

* [COOP et COEP, l'isolation cross-origin expliquée](/fr/blog/coop-coep-cross-origin-isolation)
* [Référence Cross-Origin-Opener-Policy](/fr/docs/web-security/policies/cross-origin-opener-policy)
* [Référence Cross-Origin-Resource-Policy](/fr/docs/web-security/security-headers/cross-origin-resource-policy)
* [Référence Cross-Origin-Embedder-Policy](/fr/docs/web-security/policies/cross-origin-embedder-policy)
* [Le type de report coep](/fr/docs/web-security/reporting-api/reports/coep)

## Sources [#sources]

* [WHATWG Fetch, Cross-Origin-Resource-Policy header](https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header)
* [WICG, COEP credentialless specification](https://wicg.github.io/credentiallessness/)
* [Chromium, CORP enforcement source](https://github.com/chromium/chromium/blob/main/services/network/public/cpp/cross_origin_resource_policy.cc)
* [Chromium, blocked-by-response reasons](https://github.com/chromium/chromium/blob/main/services/network/public/mojom/blocked_by_response_reason.mojom)
* [MDN, Cross-Origin-Resource-Policy header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Resource-Policy)
* [MDN, Cross-Origin Resource Policy guide](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cross-Origin_Resource_Policy)
* [MDN, Cross-Origin-Embedder-Policy header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cross-Origin-Embedder-Policy)
* [MDN, SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer)
* [web.dev, Making your website cross-origin isolated](https://web.dev/articles/coop-coep)
* [Chrome developers, SharedArrayBuffer updates](https://developer.chrome.com/blog/enabling-shared-array-buffer)
* [OWASP, HTTP headers cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)
