¿Se ignora el comodín CORS Access-Control-Allow-Headers?

118

Tengo problemas para que una solicitud CORS entre dominios funcione correctamente con Chrome.

Solicitar encabezados:

Accept:*/*
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:origin, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4

Encabezados de respuesta:

Access-Control-Allow-Headers:*
Access-Control-Allow-Origin:*
Allow:GET, POST, OPTIONS
Content-Length:0
Date:Tue, 30 Oct 2012 20:04:28 GMT
Server:BaseHTTP/0.3 Python/2.7.3

Error:

XMLHttpRequest cannot load domain. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.

Y el código Python que atiende la solicitud de opciones es:

self.send_response(200)
self.send_header('Allow', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Headers', '*')
self.send_header('Content-Length', '0')
self.end_headers()

¿Parece que Access-Control-Allow-Originse está ignorando el comodín?

Ben Reeves
fuente

Respuestas:

185

La compatibilidad con comodines en el Access-Control-Allow-Headersencabezado se agregó al estándar de vida solo en mayo de 2016, por lo que es posible que no sea compatible con todos los navegadores. En el navegador que aún no implementa esto, debe ser una coincidencia exacta: https://www.w3.org/TR/2014/REC-cors-20140116/#access-control-allow-headers-response-header

Si espera una gran cantidad de encabezados, puede leer el valor del Access-Control-Request-Headersencabezado y repetir ese valor en el Access-Control-Allow-Headersencabezado.

monsur
fuente
55
resp.setHeader ("Access-Control-Allow-Headers", req.getHeader ("Access-Control-Request-Headers")); // permitir encabezados
Sam Barnum
3
En ruby, "if request.headers ['Access-Control-Request-Headers'] then headers ['Access-Control-Allow-Headers'] = request.headers ['Access-Control-Request-Headers'] end" parece esta bien para mi.
Tsuneo Yoshioka
1
@monsur: esta respuesta señaló que ahora se permiten los comodines, al menos en teoría, así que actualicé su respuesta para reflejar esto. Si no te gusta mi estilo, puedes editarlo a tu gusto.
MvG
2
Una advertencia: puede tener problemas si confía en devolver el valor de Access-Control-Request-Headers si también permite que el navegador almacene en caché la respuesta de verificación previa (con Access-Control-Max-Age). No sabe que la primera solicitud enumera todos los encabezados de solicitudes consecutivas.
Simon Ejsing
2
@monokrome sería genial si nos pudiera decir cómo esto sería un problema de seguridad en la producción ..
prettyvoid
52

Esos encabezados CORS no se admiten *como valor, la única forma es reemplazarlos *con esto:

Accept, Accept-CH, Accept-Charset, Accept-Datetime, Accept-Encoding, Accept-Ext, Accept-Features, Accept-Language, Accept-Params, Accept-Ranges, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Access-Control-Expose-Headers, Access-Control-Max-Age, Access-Control-Request-Headers, Access-Control-Request-Method, Age, Allow, Alternates, Authentication-Info, Authorization, C-Ext, C-Man, C-Opt, C-PEP, C-PEP-Info, CONNECT, Cache-Control, Compliance, Connection, Content-Base, Content-Disposition, Content-Encoding, Content-ID, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Script-Type, Content-Security-Policy, Content-Style-Type, Content-Transfer-Encoding, Content-Type, Content-Version, Cookie, Cost, DAV, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, HTTP-date, Host, IM, If, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Keep-Alive, Label, Last-Event-ID, Last-Modified, Link, Location, Lock-Token, MIME-Version, Man, Max-Forwards, Media-Range, Message-ID, Meter, Negotiate, Non-Compliance, OPTION, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, Pep-Info, Permanent, Position, Pragma, ProfileObject, Protocol, Protocol-Query, Protocol-Request, Proxy-Authenticate, Proxy-Authentication-Info, Proxy-Authorization, Proxy-Features, Proxy-Instruction, Public, RWS, Range, Referer, Refresh, Resolution-Hint, Resolver-Location, Retry-After, Safe, Sec-Websocket-Extensions, Sec-Websocket-Key, Sec-Websocket-Origin, Sec-Websocket-Protocol, Sec-Websocket-Version, Security-Scheme, Server, Set-Cookie, Set-Cookie2, SetProfile, SoapAction, Status, Status-URI, Strict-Transport-Security, SubOK, Subst, Surrogate-Capability, Surrogate-Control, TCN, TE, TRACE, Timeout, Title, Trailer, Transfer-Encoding, UA-Color, UA-Media, UA-Pixels, UA-Resolution, UA-Windowpixels, URI, Upgrade, User-Agent, Variant-Vary, Vary, Version, Via, Viewport-Width, WWW-Authenticate, Want-Digest, Warning, Width, X-Content-Duration, X-Content-Security-Policy, X-Content-Type-Options, X-CustomHeader, X-DNSPrefetch-Control, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Frame-Options, X-Modified, X-OTHER, X-PING, X-PINGOTHER, X-Powered-By, X-Requested-With


.htaccess Ejemplo (CORS incluido):

<IfModule mod_headers.c>
  Header unset Connection
  Header unset Time-Zone
  Header unset Keep-Alive
  Header unset Access-Control-Allow-Origin
  Header unset Access-Control-Allow-Headers
  Header unset Access-Control-Expose-Headers
  Header unset Access-Control-Allow-Methods
  Header unset Access-Control-Allow-Credentials

  Header set   Connection                         keep-alive
  Header set   Time-Zone                          "Asia/Jerusalem"
  Header set   Keep-Alive                         timeout=100,max=500
  Header set   Access-Control-Allow-Origin        "*"
  Header set   Access-Control-Allow-Headers       "Accept, Accept-CH, Accept-Charset, Accept-Datetime, Accept-Encoding, Accept-Ext, Accept-Features, Accept-Language, Accept-Params, Accept-Ranges, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Access-Control-Expose-Headers, Access-Control-Max-Age, Access-Control-Request-Headers, Access-Control-Request-Method, Age, Allow, Alternates, Authentication-Info, Authorization, C-Ext, C-Man, C-Opt, C-PEP, C-PEP-Info, CONNECT, Cache-Control, Compliance, Connection, Content-Base, Content-Disposition, Content-Encoding, Content-ID, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Script-Type, Content-Security-Policy, Content-Style-Type, Content-Transfer-Encoding, Content-Type, Content-Version, Cookie, Cost, DAV, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, HTTP-date, Host, IM, If, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Keep-Alive, Label, Last-Event-ID, Last-Modified, Link, Location, Lock-Token, MIME-Version, Man, Max-Forwards, Media-Range, Message-ID, Meter, Negotiate, Non-Compliance, OPTION, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, Pep-Info, Permanent, Position, Pragma, ProfileObject, Protocol, Protocol-Query, Protocol-Request, Proxy-Authenticate, Proxy-Authentication-Info, Proxy-Authorization, Proxy-Features, Proxy-Instruction, Public, RWS, Range, Referer, Refresh, Resolution-Hint, Resolver-Location, Retry-After, Safe, Sec-Websocket-Extensions, Sec-Websocket-Key, Sec-Websocket-Origin, Sec-Websocket-Protocol, Sec-Websocket-Version, Security-Scheme, Server, Set-Cookie, Set-Cookie2, SetProfile, SoapAction, Status, Status-URI, Strict-Transport-Security, SubOK, Subst, Surrogate-Capability, Surrogate-Control, TCN, TE, TRACE, Timeout, Title, Trailer, Transfer-Encoding, UA-Color, UA-Media, UA-Pixels, UA-Resolution, UA-Windowpixels, URI, Upgrade, User-Agent, Variant-Vary, Vary, Version, Via, Viewport-Width, WWW-Authenticate, Want-Digest, Warning, Width, X-Content-Duration, X-Content-Security-Policy, X-Content-Type-Options, X-CustomHeader, X-DNSPrefetch-Control, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Frame-Options, X-Modified, X-OTHER, X-PING, X-PINGOTHER, X-Powered-By, X-Requested-With"
  Header set   Access-Control-Expose-Headers      "Accept, Accept-CH, Accept-Charset, Accept-Datetime, Accept-Encoding, Accept-Ext, Accept-Features, Accept-Language, Accept-Params, Accept-Ranges, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Access-Control-Expose-Headers, Access-Control-Max-Age, Access-Control-Request-Headers, Access-Control-Request-Method, Age, Allow, Alternates, Authentication-Info, Authorization, C-Ext, C-Man, C-Opt, C-PEP, C-PEP-Info, CONNECT, Cache-Control, Compliance, Connection, Content-Base, Content-Disposition, Content-Encoding, Content-ID, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Script-Type, Content-Security-Policy, Content-Style-Type, Content-Transfer-Encoding, Content-Type, Content-Version, Cookie, Cost, DAV, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, HTTP-date, Host, IM, If, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Keep-Alive, Label, Last-Event-ID, Last-Modified, Link, Location, Lock-Token, MIME-Version, Man, Max-Forwards, Media-Range, Message-ID, Meter, Negotiate, Non-Compliance, OPTION, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, Pep-Info, Permanent, Position, Pragma, ProfileObject, Protocol, Protocol-Query, Protocol-Request, Proxy-Authenticate, Proxy-Authentication-Info, Proxy-Authorization, Proxy-Features, Proxy-Instruction, Public, RWS, Range, Referer, Refresh, Resolution-Hint, Resolver-Location, Retry-After, Safe, Sec-Websocket-Extensions, Sec-Websocket-Key, Sec-Websocket-Origin, Sec-Websocket-Protocol, Sec-Websocket-Version, Security-Scheme, Server, Set-Cookie, Set-Cookie2, SetProfile, SoapAction, Status, Status-URI, Strict-Transport-Security, SubOK, Subst, Surrogate-Capability, Surrogate-Control, TCN, TE, TRACE, Timeout, Title, Trailer, Transfer-Encoding, UA-Color, UA-Media, UA-Pixels, UA-Resolution, UA-Windowpixels, URI, Upgrade, User-Agent, Variant-Vary, Vary, Version, Via, Viewport-Width, WWW-Authenticate, Want-Digest, Warning, Width, X-Content-Duration, X-Content-Security-Policy, X-Content-Type-Options, X-CustomHeader, X-DNSPrefetch-Control, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Frame-Options, X-Modified, X-OTHER, X-PING, X-PINGOTHER, X-Powered-By, X-Requested-With"
  Header set   Access-Control-Allow-Methods       "CONNECT, DEBUG, DELETE, DONE, GET, HEAD, HTTP, HTTP/0.9, HTTP/1.0, HTTP/1.1, HTTP/2, OPTIONS, ORIGIN, ORIGINS, PATCH, POST, PUT, QUIC, REST, SESSION, SHOULD, SPDY, TRACE, TRACK"
  Header set   Access-Control-Allow-Credentials   "true"

  Header set DNT "0"
  Header set Accept-Ranges "bytes"
  Header set Vary "Accept-Encoding"
  Header set X-UA-Compatible "IE=edge,chrome=1"
  Header set X-Frame-Options "SAMEORIGIN"
  Header set X-Content-Type-Options "nosniff"
  Header set X-Xss-Protection "1; mode=block"
</IfModule>

PREGUNTAS MÁS FRECUENTES:

  • ¿Por qué Access-Control-Allow-Headers, Access-Control-Expose-Headers,Access-Control-Allow-Methods los valores son súper larga?

    Esos no admiten la *sintaxis, por lo que he recopilado los encabezados más comunes (y exóticos) de la web, en varios formatos # 1 # 2 # 3 (y actualizaré la lista de vez en cuando)

  • ¿Por qué usas la Header unset ______sintaxis?

    Los servidores de GoDaddy (en los que está alojado mi sitio web ...) tienen un error extraño en el que, si los encabezados ya están configurados, el valor anterior se unirá al existente ... (en lugar de reemplazarlo) de esta manera "pre-limpio" los valores existentes (realmente solo una solución rápida y sucia )

  • ¿Es seguro para mí usarlo "tal cual"?

    Bueno ... principalmente la respuesta sería SÍ, ya que .htaccessestá limitando los encabezados a los scripts (PHP, HTML, ...) y recursos (.JPG, .JS, .CSS) servidos desde la siguiente ubicación de "carpeta". Opcionalmente, es posible que desee eliminar las Access-Control-Allow-Methodslíneas. También Connection, Time-Zone, Keep-Alivey DNT, Accept-Ranges, Vary, X-UA-Compatible, X-Frame-Options, X-Content-Type-Optionsy X-Xss-Protectionson sólo una sugerencia que estoy usando para mi servicio en línea .. no dude en eliminar los que son demasiado ...

tomado de mi comentario anterior

Comunidad
fuente
Esto definitivamente me salvó la vida. Estaba usando un proveedor de CDN, con CORS habilitado, y también lo estaba permitiendo en mi sitio web, Access-Control-Allow-Origin "*"pero nada funcionó hasta que usé esto. Ni siquiera el proveedor de CDN tenía una respuesta para nosotros. Ejecuto el sitio web en Siteground , tal vez, como GoDaddy , es obligatorio desarmar primero todo.
Ignacio Bustos
Excelente publicación, esto debería subirse a la parte superior de esta página.
CommonKnowledge
1
En mi caso específico, tuve que eliminar de Access-Control-Allow-Methodstodos estos métodos: HTTP / 0.9, HTTP / 1.0, HTTP / 1.1, HTTP / 2
umbe1987
¿Es HTTP / 2 incluso un 'método' válido? ¿La actualización de HTTP / 1.1 a 2 funciona así o algo así? Si miro aquí: sookocheff.com/post/networking/how-does-http-2-work, se supone que la parte HTTP / ... es el tercer lugar, no el primero, donde se coloca el método.
Henk Poley
¿Quizás para admitir HTTP / 2.0 necesita agregar el método 'PRI'?
Henk Poley
17

Descubrí que Access-Control-Allow-Headers: *debería configurarse SOLO para la solicitud de OPCIONES. Si lo devuelve para la solicitud POST, el navegador cancela la solicitud (al menos para Chrome)

El siguiente código PHP funciona para mí

// Allow CORS
if (isset($_SERVER['HTTP_ORIGIN'])) {
    header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
    header('Access-Control-Allow-Credentials: true');    
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); 
}   
// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    header("Access-Control-Allow-Headers: *");
}

Encontré preguntas similares con alguna respuesta engañosa:

  • El hilo del servidor dice que este es un error de Chrome de 2 años: Access-Control-Allow-Headersno coincide con localhost. Está mal: puedo usar CORS en mi servidor local con Post normalmente
  • Access-Control-Allow-Headersacepta comodines. También está mal, el comodín funciona para mí (solo probé con Chrome)

Esto me lleva medio día resolver el problema.

Codificación feliz

greensuisse
fuente
2
El comodín ("Access-Control-Allow-Headers: *") no me funcionó en Safari 7.0.4.
Tsuneo Yoshioka
Descubrí que la configuración de Access-Control-Allow-Headers funciona para POST en Chrome Versión 40.0.2214.111 m.
Derek Greer
3
Esto no parece estar bien ..... La especificación no permite *en Access-Control-Allow-Headersincluso para OPTIONS.
Pacerier
1

Citado de monsur,

El encabezado Access-Control-Allow-Headers no permite comodines. Debe ser una coincidencia exacta: http://www.w3.org/TR/cors/#access-control-allow-headers-response-header .

Así que aquí está mi solución php.

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
  $headers=getallheaders();
  @$ACRH=$headers["Access-Control-Request-Headers"];
  header("Access-Control-Allow-Headers: $ACRH");
}
Jason Chiang
fuente
1
En realidad, ¿por qué no simplemente?header('Access-Control-Allow-Headers: ' . $_SERVER['HTTP_ACCESS_CONTROL_ALLOW_HEADERS']);
Pacerier
0

aquí está el encantamiento para nginx, dentro de un

location / {
    # Simple requests
    if ($request_method ~* "(GET|POST)") {
      add_header "Access-Control-Allow-Origin"  *;
    }

    # Preflighted requests
    if ($request_method = OPTIONS ) {
      add_header "Access-Control-Allow-Origin"  *;
      add_header "Access-Control-Allow-Methods" "GET, POST, OPTIONS, HEAD";
      add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept";
    }

}
dcsan
fuente