Amazon S3 CORS (Cross-Origin Resource Sharing) y carga de fuentes entre dominios de Firefox

134

Ha habido un problema de larga data con Firefox que no carga la fuente desde un origen diferente que la página web actual. Por lo general, el problema surge cuando las fuentes se sirven en CDN.

Se han planteado varias soluciones en otras preguntas:

CSS @ font-face no funciona con Firefox, pero funciona con Chrome e IE

Con la introducción de Amazon S3 CORS, ¿existe una solución que use CORS para abordar el problema de carga de fuentes en Firefox?

editar: Sería genial ver una muestra de la configuración de S3 CORS.

edit2: He encontrado una solución que funciona sin comprender realmente lo que hizo. Si alguien pudiera proporcionar explicaciones más detalladas sobre las configuraciones y la magia de fondo que ocurre en la interpretación de Amazon de la configuración, sería muy apreciado, como con nzifnab, que ofreció una recompensa por ello.

VKen
fuente

Respuestas:

148

Actualización 10 de septiembre de 2014:

Ya no debería necesitar hacer ninguno de los hacks de cadenas de consulta a continuación, ya que Cloudfront ahora admite CORS correctamente. Consulte http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ y esta respuesta para obtener más información: https://stackoverflow.com/a/25305915/308315


OK, finalmente conseguí que las fuentes funcionen usando la configuración a continuación con un pequeño ajuste de los ejemplos en la documentación.

Mis fuentes están alojadas en S3, pero con frente de nube.

No estoy seguro de por qué funciona, yo creo que es probable que el <AllowedMethod> GETy <AllowedHeader> Content-*que se necesita.

Si alguien competente con la configuración de Amazon S3 CORS puede arrojar algunas luces sobre esto, será muy apreciado.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
    <CORSRule>
        <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Content-*</AllowedHeader>
        <AllowedHeader>Host</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

editar:

Algunos desarrolladores enfrentan problemas de almacenamiento en caché de Cloudfront en el Access-Control-Allow-Originencabezado. Este problema ha sido abordado por el personal de AWS en el enlace ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) a continuación, comentado por @ Jeff-Atwood.

Desde el hilo vinculado, se recomienda, como solución alternativa, utilizar una Cadena de consulta para diferenciar entre llamadas de diferentes dominios. Reproduciré el ejemplo abreviado aquí.

Utilizando curlpara verificar encabezados de respuesta:

Dominio A: a.domain.com

curl -i -H "Origin: https://a.domain.com" http://hashhashhash.cloudfront.net/font.woff?https_a.domain.com

Encabezados de respuesta del dominio A:

Access-Control-Allow-Origin: https://a.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

Dominio B: b.domain.com

curl -i -H "Origin: http://b.domain.com" http://hashhashhash.cloudfront.net/font.woff?http_b.domain.com

Encabezados de respuesta del dominio B:

Access-Control-Allow-Origin: http://b.domain.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
X-Cache: Miss from Cloudfront

Notará que Access-Control-Allow-Originha devuelto diferentes valores, que superaron el almacenamiento en caché de Cloudfront.

VKen
fuente
2
¿Ha experimentado problemas similares a los que se describen aquí : el Access-Control-Allow-Originencabezado se almacena en caché e invalida CORS cuando se realiza una solicitud posterior a través de un subdominio diferente?
OV
1
@ov No experimento el problema, ya que configuro explícitamente los dominios que utilizan los recursos. He leído el enlace que publicaste antes. Recordaba vagamente algunas respuestas en otro hilo que decía que los dominios deben ser explícitamente establecidos, por lo que <AllowedOrigin> * </AllowedOrigin> no está permitido debido a algunas restricciones. No puedo encontrar esas publicaciones de respuesta ahora, podría ser una publicación de blog que leí en otro lugar. Espero que ayude.
VKen
3
Puede tener varios elementos AllowOrigin dentro de un solo elemento CORSRule, por lo que puede combinar esos CORSRules en un solo elemento, ya que los otros elementos en ellos son idénticos.
Ben Hull
44
@dan si CloudFront sirve el segmento S3, parece que la respuesta es variar la cadena de consulta de la fuente por dominio como se documenta en esta respuesta oficial de Amazon: forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood
2
Este ha sido un tema extremadamente frustrante. La buena noticia es que ahora S3 parece estar haciendo lo correcto, por lo que al menos es posible servir todo lo que no sea webfonts a través de CloudFront y servir los archivos de fuentes directamente desde S3. Lamentablemente, el truco de la cadena de consulta no es realmente práctico en nuestra aplicación sin una refactorización más significativa, ya que todos los activos se sirven a través de la tubería de activos de Rails, y no hay una forma conveniente de modificar las URL de los activos en el momento de la solicitud (todos se generan durante la implementación cuando los activos están precompilados). La URL de la fuente en CSS ya está activada en S3.
Zach Lipton el
97

Después de algunos ajustes, parece que hice que esto funcione sin el truco de la cadena de consulta. Más información aquí: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Voy a revisar toda mi configuración para que sea fácil ver lo que he hecho, espero que esto ayude a otros.

Información básica: estoy usando una aplicación Rails que tiene la gema asset_sync para poner activos en S3. Esto incluye fuentes.

Dentro de la consola S3, hice clic en mi bucket, propiedades y 'editar configuración de cors', aquí: Botón de configuración CORS

Dentro del área de texto tengo algo como:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>https://*.example.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Luego, dentro del panel Cloudfront ( https://console.aws.amazon.com/cloudfront/home ) creé una distribución, agregué un Origen que apuntaba a mi cubo S3 agregando un origen

Luego agregó un comportamiento para una ruta predeterminada para apuntar al origen basado en S3 que configuré. Lo que también hice fue hacer clic en los encabezados de la Lista blanca y agregar Origin: Agregar un comportamiento y encabezados de lista blanca

Lo que sucede ahora es lo siguiente, que creo que es correcto:

1) Verifique que los encabezados S3 se estén configurando correctamente

curl -i -H "Origin: https://example.com" https://s3.amazonaws.com/xxxxxxxxx/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
x-amz-id-2: Ay63Qb5uR98ag47SRJ91+YALtc4onRu1JUJgMTU98Es/pzQ3ckmuWhzzbTgDTCt+
x-amz-request-id: F1FFE275C0FBE500
Date: Thu, 14 Aug 2014 09:39:40 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Vary: Origin, Access-Control-Request-Headers, Access-Control-Request-Method
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Content-Type: application/x-font-ttf
Content-Length: 12156
Server: AmazonS3

2) Compruebe que Cloudfront funciona con los encabezados

curl -i -H "Origin: https://example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 09:35:26 GMT
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 77bdacfea247b6cbe84dffa61da5a554.cloudfront.net (CloudFront)
X-Amz-Cf-Id: cmCxaUcFf3bT48zpPw0Q-vDDza0nZoWm9-_3qY5pJBhj64iTpkgMlg==

(Tenga en cuenta que lo anterior fue un error de Cloudfront porque estos archivos se almacenan en caché durante 180 segundos, pero lo mismo funcionaba en los hits)

3) Golpee el frente de la nube con un origen diferente (pero que esté permitido en CORS para el bucket S3): ¡ Access-Control-Allow-Originno está en caché! ¡Hurra!

curl -i -H "Origin: https://www2.example.com" https://xxxxx.cloudfront.net/assets/fonts/my-cool-font.ttf
HTTP/1.1 200 OK
Content-Type: application/x-font-ttf
Content-Length: 12156
Connection: keep-alive
Date: Thu, 14 Aug 2014 10:02:33 GMT
Access-Control-Allow-Origin: https://www2.example.com
Access-Control-Allow-Methods: GET
Access-Control-Max-Age: 3000
Access-Control-Allow-Credentials: true
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=180
Last-Modified: Mon, 09 Dec 2013 14:29:04 GMT
ETag: "98918ee7f339c7534c34b9f5a448c3e2"
Accept-Ranges: bytes
Server: AmazonS3
Vary: Origin
X-Cache: Miss from cloudfront
Via: 1.1 ba7014bad8e9bf2ed075d09443dcc4f1.cloudfront.net (CloudFront)
X-Amz-Cf-Id: vy-UccJ094cjdbdT0tcKuil22XYwWdIECdBZ_5hqoTjr0tNH80NQPg==

Tenga en cuenta que el dominio ha cambiado correctamente sin un hack de cadena de consulta.

Cuando cambio el encabezado Origen, parece que siempre hay un X-Cache: Miss from cloudfronten la primera solicitud y luego obtengo el esperadoX-Cache: Hit from cloudfront

PD Vale la pena señalar que al hacer curl -I (mayúscula I) NO mostrará los encabezados Access-Control-Allow-Origin, ya que solo es un HEAD, hago -i para que sea un GET y desplácese hacia arriba.

Eamonn Gahan
fuente
Funcionó cuando todos los demás no lo hicieron. ¡Gracias por tomarse el tiempo de publicar con tanto detalle!
Fui robado el
¡¡Funciona!! FYI - Tuve un gran texto de respuesta http al probar esto ... voy a editar la respuesta para usar esta solución curl ... stackoverflow.com/questions/10060098/…
Michael Gorham
Genial, gracias chicos, me alegra ver que está funcionando para otros.
Eamonn Gahan
¡No puedo decirte cuánto nos has ayudado! +1
nada especial aquí el
1
+1 para agregar el encabezado de cliente Originde los espectadores para que Cloudfront almacene en caché el objeto en función de ese encabezado (y reenvíe los encabezados CORS del servidor al usuario)
Sébastien Saunier
13

Mis fuentes se sirvieron correctamente hasta el último envío a Heroku ... No sé por qué, pero el comodín en el origen permitido CORS dejó de funcionar. Agregué todos mis dominios prepro y pro a la política CORS en la configuración del depósito, por lo que ahora se ve así:

<CORSConfiguration>
    <CORSRule>
        <AllowedOrigin>http://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>https://prepro.examle.com</AllowedOrigin>
        <AllowedOrigin>http://examle.com</AllowedOrigin>
        <AllowedOrigin>https://examle.com</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>

</CORSConfiguration>

ACTUALIZACIÓN: agregue su http://localhost:PORTtambién

luigi7up
fuente
1
Gracias por compartir esta solución. Esto funcionó para mí.
Ryan Montgomery
8

Bueno, la documentación indica que puede pegar la configuración como "el sub recurso de cors en su bucket". Tomé esto para significar que crearía un archivo llamado "cors" en la raíz de mi cubo con la configuración, pero esto no funcionaría. Al final tuve que iniciar sesión en el área de administración de Amazon S3 y agregar la configuración dentro del propertiescuadro de diálogo de mi bucket.

S3 podría usar una mejor documentación ...

nzifnab
fuente
1
Sí, pero tuve la suerte de detectar algunos nuevos cambios en la interfaz en el panel de propiedades. He estado editando políticas de depósito, así que, naturalmente, busco la configuración de CORS en el mismo panel.
VKen
funcionó para mí, estaba buscando configurar esto en mi aplicación, quién sabía que sería tan simple
Richlewis
7

En la configuración de Amazon S3 CORS (S3 Bucket / Permissions / CORS) si usa esto:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>

CORS funciona bien para archivos Javascript y CSS, pero no funciona para archivos Font .

Debe especificar el dominio para permitir CORS utilizando el patrón expresado en la respuesta @VKen: https://stackoverflow.com/a/25305915/618464

Entonces, usa esto :

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
<CORSRule>
    <AllowedOrigin>https://*.mydomain.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Recuerde reemplazar "midominio.com" por su dominio.

Después de esto, invalide la caché de CloudFront (CloudFront / Invalidations / Create Invalidation) y funcionará.

educoutinho
fuente
6

En mi caso, no había definido el espacio de nombres XML y la versión en la configuración de CORS. Definiendo aquellos trabajados.

Cambiado

<CORSConfiguration>

a

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
Gaurav Toshniwal
fuente
A mí también me funciona. Mis fuentes están alojadas en el cubo mismo.
Khamaileon
Por qué la plantilla predeterminada no incluye automáticamente esto está más allá de mí.
CoatedMoose
4

¡Hay una manera mejor y más fácil!

Personalmente prefiero usar mis subdominios DNS para resolver este problema. Si mi CDN está detrás de cdn.myawesomeapp.com en lugar de sdf73n7ssa.cloudfront.net, los navegadores no se asustarán y los bloquearán como problemas de seguridad entre dominios.

Para apuntar su subdominio a su dominio de AWS Cloudfront, vaya al panel de control de AWS Cloudfront, seleccione su distribución de Cloudfront e ingrese su subdominio CDN en el campo Nombres de dominio alternativo (CNAME). Algo como cdn.myawesomeapp.com hará.

Ahora puede ir a su proveedor de DNS (como AWS Route 53) y crear un CNAME para cdn.myawesomeapp.com que apunte a sdf73n7ssa.cloudfront.net.

http://blog.cloud66.com/cross-origin-resource-sharing-cors-blocked-for-cloudfront-in-rails/

msroot
fuente
Esto rompe SSL o, más bien, cuesta mucho dinero hacer con SSL, por lo tanto, mucha gente no hace esto.
maletor
4

Esta configuración funcionó para mí. Puedo enumerar objetos, recuperar, actualizar y eliminar.

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <CORSRule>
    <AllowedOrigin>http://localhost:3000</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    <ExposeHeader>ETag</ExposeHeader>
    <ExposeHeader>x-amz-meta-custom-header</ExposeHeader>
  </CORSRule>
</CORSConfiguration>
Shahid
fuente
necesita cambiar el dominio, ya que estaba probando desde localhost, solo mire esta página para CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Shahid
1
<ifModule mod_headers.c>

   Header set Access-Control-Allow-Origin: http://domainurl.com

</ifModule>

Solución simple

O-mkar
fuente
¡Gracias por compartir! Me dio la idea de agregar este encabezado como 'metadatos' mientras cargaba activos estáticos en el almacenamiento en la nube. (Aunque de esa manera funcionará con solo 1 particular domaino all domains)
Vinay Vissh
0

Reiniciar mi aplicación de arranque de primavera (servidor) resolvió el problema para mí.

Había configurado CORS correctamente en S3. El rizo estaba dando la respuesta correcta con el encabezado de origen. Safari estaba buscando la fuente correctamente. Solo el cromo no estaba dispuesto a aceptar el CORS.

No estoy seguro de qué causó exactamente el comportamiento. Debe tener algo que ver con If-modified-since

Sujit Kamthe
fuente
0

Esto no está relacionado con las fuentes, sino con las imágenes, podría ser un caso extremo, pero como me sucedió a mí, podría sucederle a otro. Dejaré esto aquí esperando que ayude a alguien:

Si se encuentra en el escenario "He hecho todo lo que me dijeron, pero todavía no funciona", probablemente sea un problema relacionado con la memoria caché en Chrome y Safari. Supongamos que su servidor tiene un conjunto de configuración CORS adecuado:

<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
    </CORSRule>
</CORSConfiguration>

y en Firefox todo funciona bien, pero en Chrome y Safari no. Si está accediendo a su ruta de imagen remota de tanto un simple <img src="http://my.remote.server.com/images/cat.png">etiqueta y de un elemento de imagen src js, al igual que de la siguiente manera:

var myImg = new Image()
myImg.crossOrigin = 'Anonymous'
myImg.onload = () => {
  // do stuff (maybe draw the downloaded img on a canvas)
}
myImg.src = 'http://my.remote.server.com/images/cat.png'

Es posible que obtenga el No 'Access-Control-Allow-Origin'error en Chrome y Safari. Esto sucede porque el primero de <img>alguna manera desordena la memoria caché del navegador, y cuando intenta acceder a la misma imagen más tarde (en el elemento Imagen en código), simplemente se rompe. Para evitar esto, puede agregar un parámetro GET ficticio a una ruta .src, para obligar al navegador a volver a solicitar la imagen y evitar el uso de caché, de esta manera:

<img src="http://my.remote.server.com/images/cat.png?nocache=true"></img>
Nicola Elia
fuente
-1

Sí, por supuesto. Firefox admite CORS para fuentes, tal como lo requiere la especificación en http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading

Boris Zbarsky
fuente
Gracias por su pronta respuesta, Boris Zbarsky. ¿Podría mostrar algunas configuraciones de ejemplo para la configuración de S3 CORS?
VKen
Nunca he buscado configurar S3 ... En cuanto a qué enviar en el nivel HTTP, si está de acuerdo con eso, simplemente envíe "Access-Control-Allow-Origin: *" en la respuesta HTTP para los archivos de fuentes Deberia trabajar.
Boris Zbarsky
Gracias, estoy tratando de averiguar exactamente cómo hacer esa configuración con las configuraciones S3 CORS.
VKen