Amazon S3 CORS (Cross-Origin Resource Sharing) e caricamento dei font tra domini di Firefox


135

Si è verificato un problema di vecchia data con Firefox che non caricava caratteri di origine diversa rispetto alla pagina Web corrente. Di solito, il problema si presenta quando i caratteri vengono offerti su CDN.

Varie soluzioni sono state sollevate in altre domande:

CSS @ font-face non funziona con Firefox, ma funziona con Chrome e IE

Con l'introduzione di Amazon S3 CORS, esiste una soluzione che utilizza CORS per risolvere il problema del caricamento dei caratteri in Firefox?

modifica: sarebbe bello vedere un esempio della configurazione S3 CORS.

edit2: ho trovato una soluzione funzionante senza realmente capire cosa ha fatto. Se qualcuno potesse fornire spiegazioni più dettagliate sui config e sulla magia di sottofondo che accade nell'interpretazione della configurazione di Amazon, sarebbe molto apprezzato, come con nzifnab che ha messo una taglia per questo.

Risposte:


148

Aggiornamento del 10 settembre 2014:

Non dovresti più dover fare nessuno degli hack della stringa di query di seguito poiché Cloudfront ora supporta correttamente CORS. Vedi http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ e questa risposta per maggiori informazioni: https://stackoverflow.com/a/25305915/308315


OK, finalmente ho ottenuto i caratteri funzionanti usando la configurazione qui sotto con un po 'di modifica dagli esempi nella documentazione.

I miei caratteri sono ospitati su S3, ma fronteggiati da cloudfront.

Io non sono sicuro perché funziona, la mia ipotesi è probabilmente che la <AllowedMethod> GETe <AllowedHeader> Content-*è necessario.

Se qualcuno che è esperto con la configurazione Amazon S3 CORS può far luce su questo, sarà molto apprezzato.

<?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>

modificare:

Alcuni sviluppatori stanno affrontando problemi di memorizzazione nella cache Access-Control-Allow-Origindell'intestazione da parte di Cloudfront . Questo problema è stato risolto dallo staff di AWS nel link ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) di seguito, commentato da @ Jeff-Atwood.

Dal thread collegato, si consiglia, come soluzione alternativa, di utilizzare una stringa di query per differenziare le chiamate da domini diversi. Riprodurrò qui l'esempio abbreviato.

Utilizzo curlper controllare le intestazioni di risposta:

Dominio A: a.domain.com

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

Header di risposta dal 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

Header di risposta dal 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

Noterai che Access-Control-Allow-Originha restituito valori diversi, che hanno superato la memorizzazione nella cache di Cloudfront.


2
hai riscontrato problemi simili a quelli descritti qui : l' Access-Control-Allow-Originintestazione viene memorizzata nella cache e invalida CORS quando viene effettuata una richiesta successiva tramite un sottodominio diverso?
Ov

1
@ov Non riscontro il problema poiché imposto esplicitamente i domini che utilizzano le risorse. Ho letto il link che hai pubblicato prima. Ho vagamente ricordato alcune risposte su un altro thread in cui si diceva che i domini devono essere esplicitamente dichiarati, quindi <AllowedOrigin> * </AllowedOrigin> non è effettivamente consentito, a causa di alcune restrizioni. Non riesco a trovare quei post di risposta ora, potrebbe essere post sul blog che ho letto altrove. Spero che aiuti.
VKen,

3
È possibile avere più elementi AllowOrigin all'interno di un singolo elemento CORSRule, quindi è possibile combinare tali CORSRule in un singolo elemento, poiché gli altri elementi in essi contenuti sono identici.
Ben Hull,

4
@dan se il bucket S3 è servito da CloudFront, sembra che la risposta sia variare il querystring dei caratteri per dominio come documentato in questa risposta ufficiale di Amazon: forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood

2
Questo è stato un problema estremamente frustrante. La buona notizia è che ora S3 sembra fare la cosa giusta, quindi almeno è possibile servire qualsiasi cosa tranne i font web tramite CloudFront e servire i file dei font direttamente da S3. Purtroppo, l'hacking di querystring non è davvero pratico nella nostra applicazione senza un refactoring più significativo, poiché gli asset sono tutti serviti attraverso la pipeline di asset Rails e non c'è modo conveniente di modificare gli URL degli asset al momento della richiesta (sono tutti generati durante l'implementazione quando le attività sono precompilate). L'URL del carattere in CSS è già attivo su S3.
Zach Lipton,

97

Dopo alcune modifiche, sembra che questo funzioni senza l'hack della stringa di query. Maggiori informazioni qui: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Esaminerò tutta la mia configurazione in modo che sia facile vedere cosa ho fatto, spero che questo aiuti gli altri.

Informazioni di base: sto usando un'app Rails che ha la gemma asset_sync per mettere le risorse su S3. Questo include i caratteri.

All'interno della console S3, ho fatto clic sul mio bucket, proprietà e "modifica configurazione cors", qui: Pulsante di configurazione CORS

All'interno dell'area di testo ho qualcosa come:

<?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>

Quindi all'interno del pannello Cloudfront ( https://console.aws.amazon.com/cloudfront/home ) ho creato una distribuzione, aggiunto un Origin che puntava al mio bucket S3 aggiungendo un'origine

Quindi aggiunto un comportamento per un percorso predefinito che punta all'impostazione di origine I basata su S3. Ho fatto anche clic sulle intestazioni della whitelist e ho aggiunto Origin: aggiunta di intestazioni di comportamento e whitelist

Quello che succede ora è il seguente, che credo sia giusto:

1) Verificare che le intestazioni S3 siano impostate correttamente

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) Verifica che Cloudfront funzioni con le intestazioni

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==

(Si noti che quanto sopra è stato un fallimento da cloudfront perché questi file vengono memorizzati nella cache per 180 secondi, ma lo stesso funzionava sugli hit)

3) Raggiungi il cloudfront con un'origine diversa (ma è consentito su CORS per il bucket S3): Access-Control-Allow-Originnon viene memorizzato nella cache! Sìì!

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==

Si noti sopra che il dominio è stato modificato correttamente senza un hack della stringa di query.

Quando cambio l'intestazione Origin, sembra che ci sia sempre un X-Cache: Miss from cloudfrontsulla prima richiesta, poi ricevo l'attesoX-Cache: Hit from cloudfront

PS Vale la pena notare che quando si fa arricciatura -I (maiuscola I) NON mostrerà le intestazioni Access-Control-Allow-Origin in quanto è solo una HEAD, lo faccio -i per renderlo un GET e scorrere verso l'alto.


Ha funzionato quando tutti gli altri no. Grazie per aver dedicato del tempo a pubblicare in modo così dettagliato!
Iwasrobbed il

Funziona!! Cordiali saluti - Ho avuto un enorme testo di risposta http durante il test di questo ... modificherò la risposta per utilizzare questa soluzione di arricciatura ... stackoverflow.com/questions/10060098/…
Michael Gorham,

Fantastico grazie ragazzi - felice di vedere che funziona per gli altri.
Eamonn Gahan,

Non posso dirti quanto ci hai aiutato! +1
niente di speciale-qui il

1
+1 per l'aggiunta dell'intestazione del cliente Origindagli spettatori in modo che Cloudfront memorizzi nella cache l'oggetto in base a tale intestazione (e inoltri all'utente le intestazioni CORS del server all'utente)
Sébastien Saunier,

13

I miei caratteri sono stati serviti correttamente fino all'ultima spinta verso Heroku ... Non so perché, ma il carattere jolly nel CORS ha permesso a origin di smettere di funzionare. Ho aggiunto tutti i miei domini prepro e pro alla politica CORS nell'impostazione bucket, quindi ora è così:

<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>

AGGIORNAMENTO: aggiungi http://localhost:PORTanche il tuo


1
Grazie per aver condiviso questa soluzione. Questo ha funzionato per me.
Ryan Montgomery,

8

Bene, la documentazione afferma che è possibile attaccare la configurazione come "la risorsa secondaria cors nel tuo secchio". Ho preso questo per significare che avrei creato un file chiamato "cors" nella radice del mio bucket con la configurazione, ma questo non avrebbe funzionato. Alla fine ho dovuto accedere all'area di amministrazione di Amazon S3 e aggiungere la configurazione nella propertiesfinestra di dialogo del mio bucket.

S3 potrebbe usare della documentazione migliore ...


1
Sì, ma sono stato fortunato ad individuare alcune nuove modifiche all'interfaccia nel pannello delle proprietà. Ho modificato i criteri del bucket, quindi naturalmente cerco la configurazione CORS nello stesso pannello.
VKen,

ha funzionato per me, stavo cercando di impostare questo nella mia applicazione, chi sapeva che sarebbe stato così semplice
Richlewis

7

Nella configurazione Amazon S3 CORS (S3 Bucket / Autorizzazioni / CORS) se si utilizza questo:

<?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 funziona bene per i file Javascript e CSS, ma non per i file Font .

Devi specificare il dominio per consentire CORS utilizzando il modello espresso nella risposta @VKen: https://stackoverflow.com/a/25305915/618464

Quindi, usa questo :

<?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>

Ricorda di sostituire "mydomain.com" per il tuo dominio.

Dopo questo, invalidare la cache di CloudFront (CloudFront / Invalidations / Create Invalidation) e funzionerà.


6

Nel mio caso, non avevo definito lo spazio dei nomi e la versione XML nella configurazione CORS. Definire quelli ha funzionato.

Cambiato

<CORSConfiguration>

per

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">

Funziona anche per me. I miei caratteri sono ospitati sul bucket stesso.
Khamaileon,

Perché il modello predefinito non includa automaticamente questo è oltre me.
CoatedMoose

4

C'è un modo migliore e più semplice!

Personalmente preferisco utilizzare i miei sottodomini DNS per risolvere questo problema. Se il mio CDN è dietro cdn.myawesomeapp.com invece di sdf73n7ssa.cloudfront.net, i browser non andranno fuori di testa e li bloccheranno come problemi di sicurezza tra domini.

Per indirizzare il tuo sottodominio al tuo dominio AWS Cloudfront vai al pannello di controllo di AWS Cloudfront, seleziona la tua distribuzione Cloudfront e inserisci il tuo sottodominio CDN nel campo Nomi di dominio alternativi (CNAME). Qualcosa come cdn.myawesomeapp.com farà.

Ora puoi andare al tuo provider DNS (come AWS Route 53) e creare un CNAME per cdn.myawesomeapp.com che punta a sdf73n7ssa.cloudfront.net.

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


Questo rompe SSL o piuttosto costa un sacco di soldi a che fare con SSL quindi molte persone non lo fanno.
Maletor,

4

Questa configurazione ha funzionato per me. Posso elencare l'oggetto, recuperare, aggiornare ed eliminare.

<?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>

devi cambiare dominio, mentre stavo testando da localhost, guarda CORS in questa pagina: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Shahid,

1
<ifModule mod_headers.c>

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

</ifModule>

Soluzione semplice


Grazie per la condivisione! Mi è venuta l'idea di aggiungere questa intestazione come "metadati" durante il caricamento di risorse statiche nel cloud storage. (Anche se in questo modo funzionerà solo con 1 particular domaino all domains)
Vinay Vissh

0

Il riavvio della mia applicazione di avvio a molla (server) ha risolto il problema per me.

Avevo configurato CORS correttamente su S3. Il ricciolo stava dando la risposta corretta con l'intestazione dell'origine. Safari stava recuperando correttamente il carattere. Era solo il Chrome che non era disposto ad accettare il CORS.

Non sono sicuro di cosa abbia causato esattamente il comportamento. Deve essere qualcosa a che fare con If-modified-since


0

Questo non è legato ai caratteri ma alle immagini, potrebbe essere un caso limite, ma come è successo a me, potrebbe accadere a un altro. Lascio questo qui sperando che possa aiutare qualcuno:

Se ti trovi nello scenario "Ho fatto tutto quello che hanno detto, ma ancora non funzionerà" probabilmente è un problema relativo alla cache in Chrome e Safari. Supponiamo che il tuo server abbia un corretto set di configurazione CORS:

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

e in Firefox tutto funziona bene, ma in Chrome e Safari non funziona. Se si accede al percorso dell'immagine remota sia da un semplice <img src="http://my.remote.server.com/images/cat.png">tag sia da un elemento js Image src, come nel modo seguente:

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'

Potresti ottenere l' No 'Access-Control-Allow-Origin'errore in Chrome e Safari. Ciò accade perché il primo in <img>qualche modo confonde la cache del browser e quando si tenta di accedere alla stessa immagine in un secondo momento (sull'elemento Image nel codice), si interrompe semplicemente. Per evitare ciò, è possibile aggiungere un parametro GET fittizio a un percorso .src, al fine di forzare il browser a richiedere nuovamente l'immagine ed evitare di utilizzare la cache, in questo modo:

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

-1

Sì, naturalmente. Firefox supporta CORS per i caratteri, proprio come le specifiche richieste su http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading


Grazie per la pronta risposta, Boris Zbarsky. Saresti in grado di mostrare alcune configurazioni di esempio per le impostazioni S3 CORS?
VKen,

Non ho mai cercato di configurare S3 ... Per quanto riguarda cosa inviare a livello HTTP, se stai bene inviando semplicemente "Access-Control-Allow-Origin: *" nella risposta HTTP per i file dei caratteri dovrebbe funzionare.
Boris Zbarsky,

Grazie, sto cercando di scoprire esattamente come eseguire questa impostazione con le configurazioni S3 CORS.
VKen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.