Encabezados de solicitud de origen cruzado (CORS) con encabezados PHP

Resuelto asked hace 54 años • 11 respuestas

Tengo un script PHP simple y estoy intentando realizar una solicitud CORS entre dominios:

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

Sin embargo, sigo recibiendo el error:

El campo de encabezado de solicitud X-Requested-Withno está permitido porAccess-Control-Allow-Headers

¿Algo que me falta?

 avatar Jan 01 '70 08:01
Aceptado

Manejar las solicitudes CORS correctamente es un poco más complicado. Aquí hay una función que responderá de manera más completa (y adecuada).

/**
 *  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!";
}

Notas de seguridad

Verifique el encabezado HTTP_ORIGIN con una lista de orígenes aprobados.

Si el origen no se aprueba, entonces debes rechazar la solicitud.

Por favor lea las especificaciones.

TL;DR

Cuando un navegador quiere ejecutar una solicitud entre sitios, primero confirma que está bien con una solicitud "previa" a la URL. Al permitir CORS, le está indicando al navegador que las respuestas de esta URL se pueden compartir con otros dominios.

CORS no protege su servidor. CORS intenta proteger a sus usuarios diciéndoles a los navegadores cuáles deberían ser las restricciones para compartir respuestas con otros dominios. Normalmente, este tipo de intercambio está completamente prohibido, por lo que CORS es una forma de hacer un agujero en la política de seguridad normal del navegador. Estos agujeros deben ser lo más pequeños posible, así que siempre verifique HTTP_ORIGIN con algún tipo de lista interna.

Aquí existen algunos peligros , especialmente si los datos que proporciona la URL normalmente están protegidos. De hecho, está permitiendo que el contenido del navegador que se originó en algún otro servidor lea (y posiblemente manipule) datos en su servidor.

Si va a utilizar CORS, lea atentamente el protocolo (es bastante pequeño) e intente comprender lo que está haciendo. Para ello, en el ejemplo de código se proporciona una URL de referencia.

Seguridad del encabezado

Se ha observado que el encabezado HTTP_ORIGIN es inseguro y eso es cierto. De hecho, todos los encabezados HTTP son inseguros según los distintos significados del término. A menos que un encabezado incluya una firma/hmac verificable, o que toda la conversación esté autenticada a través de TLS, los encabezados son simplemente "algo que el navegador me ha dicho".

En este caso, el navegador dice "un objeto del dominio X quiere obtener una respuesta de esta URL. ¿Está bien?" El objetivo de CORS es poder responder "sí, lo permitiré".

slashingweapon avatar Mar 26 '2012 03:03 slashingweapon

Recibí el mismo error y lo solucioné con el siguiente PHP en mi script de back-end:

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

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

header("Access-Control-Allow-Headers: X-Requested-With");
Fiach Reid avatar Sep 04 '2014 09:09 Fiach Reid

Access-Control-Allow-Headersno permite *como valor aceptado, consulte la documentación de Mozilla aquí .

En lugar del asterisco, debes enviar los encabezados aceptados (primero X-Requested-Withcomo dice el error).

Actualizar:

*ahora se acepta es Access-Control-Allow-Headers.

Según MDN Web Docs 2021 :

El valor *solo cuenta como un valor comodín especial para solicitudes sin credenciales (solicitudes sin cookies HTTP o información de autenticación HTTP). En solicitudes con credenciales, se trata como el nombre del encabezado literal *sin semántica especial. Tenga en cuenta que el encabezado Autorización no puede tener comodines y siempre debe aparecer de forma explícita.

KARASZI István avatar Jan 03 '2012 22:01 KARASZI István