190 votes

Cross-Origin Request Headers (CORS) avec les en-têtes PHP

J'ai un simple script PHP pour lequel je tente une requête CORS inter-domaine :

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
...

Pourtant, je reçois toujours l'erreur :

Champ d'en-tête de la demande X-Requested-With n'est pas autorisé par Access-Control-Allow-Headers

Il y a quelque chose que j'ai manqué ?

348voto

slashingweapon Points 5207

La gestion correcte des demandes CORS est un peu plus complexe. Voici une fonction qui répondra de manière plus complète (et correcte).

/**
 *  An example CORS-compliant method.  It will allow any GET, POST, or OPTIONS requests from any
 *  origin.
 *
 *  In a production environment, you probably want to be more restrictive, but this gives you
 *  the general idea of what is involved.  For the nitty-gritty low-down, read:
 *
 *  - https://developer.mozilla.org/en/HTTP_access_control
 *  - https://fetch.spec.whatwg.org/#http-cors-protocol
 *
 */
function cors() {

    // Allow from any origin
    if (isset($_SERVER['HTTP_ORIGIN'])) {
        // Decide if the origin in $_SERVER['HTTP_ORIGIN'] is one
        // you want to allow, and if so:
        header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Max-Age: 86400');    // cache for 1 day
    }

    // Access-Control headers are received during OPTIONS requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
            // may also be using PUT, PATCH, HEAD etc
            header("Access-Control-Allow-Methods: GET, POST, OPTIONS");         

        if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
            header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");

        exit(0);
    }

    echo "You have CORS!";
}

Notes de sécurité

Lorsqu'un navigateur veut exécuter une requête intersite, il confirme d'abord que cela est possible en envoyant une requête "pré-vol" à l'URL. En autorisant CORS, vous indiquez au navigateur que les réponses de cette URL peuvent être partagées avec d'autres domaines.

CORS ne protège pas votre serveur. CORS tente de protéger vos utilisateurs en indiquant aux navigateurs les restrictions à appliquer au partage des réponses avec d'autres domaines. Normalement, ce type de partage est totalement interdit. CORS est donc un moyen de percer un trou dans la politique de sécurité normale du navigateur. Ces trous doivent être aussi petits que possible, aussi vérifiez toujours le HTTP_ORIGIN par rapport à une liste interne.

Il y a quelques dangers ici surtout si les données que l'URL sert sont normalement protégées. Vous autorisez effectivement le contenu du navigateur provenant d'un autre serveur à lire (et éventuellement à manipuler) les données de votre serveur.

Si vous comptez utiliser CORS, lisez attentivement le protocole (il est assez petit) et essayez de comprendre ce que vous faites. Une URL de référence est donnée dans l'exemple de code à cette fin.

Sécurité de l'en-tête

Il a été observé que l'en-tête HTTP_ORIGIN n'est pas sûr, et c'est vrai. En fait, tous les en-têtes HTTP sont peu sûrs, dans des sens différents du terme. À moins qu'un en-tête n'inclue une signature/hmac vérifiable, ou que toute la conversation ne soit authentifiée via TLS, les en-têtes ne sont que "quelque chose que le navigateur m'a dit".

Dans ce cas, le navigateur dit "un objet du domaine X veut obtenir une réponse de cette URL. Est-ce que c'est correct ?" L'intérêt de CORS est de pouvoir répondre "oui, je l'autorise".

41 votes

Notez que le fait de renvoyer la valeur HTTP Origin comme origine autorisée permettra à n'importe qui de vous envoyer des requêtes avec des cookies, et donc de voler la session d'un utilisateur qui s'est connecté à votre site puis a consulté la page d'un attaquant. Vous voulez soit envoyer '*' (qui empêchera les cookies et donc le vol de session), soit les domaines spécifiques pour lesquels vous voulez que le site fonctionne.

1 votes

Je suis d'accord. Dans la pratique, vous n'autoriserez probablement pas n'importe quel domaine à utiliser votre service CORS, vous le restreindrez à un ensemble de domaines auxquels vous aurez décidé de faire confiance.

0 votes

Pour info, cette solution n'a fonctionné pour moi que dans un cas de Linux server en IIS pour une raison quelconque, ça n'a pas fonctionné, je ne sais pas si c'est mon hébergement ou si c'est juste qu'il n'est pas adapté à IIS

93voto

Fiach Reid Points 85

J'ai eu la même erreur, et je l'ai corrigée avec le PHP suivant dans mon script de back-end :

header('Access-Control-Allow-Origin: *');

header('Access-Control-Allow-Methods: GET, POST');

header("Access-Control-Allow-Headers: X-Requested-With");

69voto

KARASZI István Points 15162

Access-Control-Allow-Headers ne permet pas * comme valeur acceptée, voir la documentation Mozilla ici .

Au lieu de l'astérisque, vous devriez envoyer les en-têtes acceptés (premier X-Requested-With comme le dit l'erreur).

Mise à jour :

* est maintenant accepté est Access-Control-Allow-Headers .

Selon MDN Web Docs 2021 :

La valeur * n'est considéré comme un caractère générique spécial que pour les demandes sans justificatifs (demandes sans cookies HTTP ou informations d'authentification HTTP). Dans les requêtes avec informations d'identification, elle est traitée comme le nom d'en-tête littéral. * sans sémantique particulière. Notez que l'en-tête d'autorisation ne peut pas être remplacé par un caractère générique et qu'il doit toujours être mentionné explicitement.

4 votes

A partir de 2021, il semble que * est désormais accepté, conformément à la documentation du MDN.

45voto

Csongor Halmai Points 707

De nombreuses descriptions sur Internet ne mentionnent pas que le fait de spécifier Access-Control-Allow-Origin n'est pas suffisant. Voici un exemple complet qui fonctionne pour moi :

<?php
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: POST, GET, DELETE, PUT, PATCH, OPTIONS');
        header('Access-Control-Allow-Headers: token, Content-Type');
        header('Access-Control-Max-Age: 1728000');
        header('Content-Length: 0');
        header('Content-Type: text/plain');
        die();
    }

    header('Access-Control-Allow-Origin: *');
    header('Content-Type: application/json');

    $ret = [
        'result' => 'OK',
    ];
    print json_encode($ret);

2 votes

Veuillez expliquer pourquoi ce n'est pas suffisant et quel exemple minimal. es assez.

0 votes

Malheureusement, je ne me souviens pas exactement et je n'ai pas le temps maintenant de l'étudier à nouveau mais, autant que je m'en souvienne, il y avait quelques hypothèses de base du côté du serveur web/navigateur qui ne fonctionnaient pas. Voici le code minimal qui a fonctionné pour moi.

0 votes

Si l'hôte virtuel d'apache a déjà été envoyé, alors seul ce code fonctionne si ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { die() ; }

27voto

Fedeco Points 402

J'ai simplement réussi à faire fonctionner dropzone et d'autres plugins avec cette correction (angularjs + backend php).

 header('Access-Control-Allow-Origin: *'); 
    header("Access-Control-Allow-Credentials: true");
    header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
    header('Access-Control-Max-Age: 1000');
    header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

Ajoutez ceci dans votre upload.php ou à l'endroit où vous envoyez votre requête (par exemple si vous avez upload.html et que vous devez joindre les fichiers à upload.php, alors copiez et collez ces 4 lignes). De plus, si vous utilisez des plugins/addons CORS dans chrome/mozilla, assurez-vous de les activer plusieurs fois, afin que CORS soit activé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X