Amazon S3 CORS (Cross-Origin Resource Sharing) i ładowanie czcionek międzydomenowych Firefox

136

Od dawna występował problem polegający na tym, że Firefox nie ładował czcionek z innego źródła niż bieżąca strona internetowa. Zwykle problem pojawia się, gdy czcionki są udostępniane w sieciach CDN.

W innych pytaniach podniesiono różne rozwiązania:

CSS @ font-face nie działa z Firefoksem, ale działa z Chrome i IE

Czy wraz z wprowadzeniem Amazon S3 CORS istnieje rozwiązanie wykorzystujące CORS do rozwiązania problemu z ładowaniem czcionek w przeglądarce Firefox?

edycja: Byłoby wspaniale zobaczyć próbkę konfiguracji S3 CORS.

edit2: Znalazłem działające rozwiązanie bez faktycznego zrozumienia, co ono spowodowało. Jeśli ktokolwiek mógłby podać bardziej szczegółowe wyjaśnienia dotyczące konfiguracji i magii tła, która ma miejsce przy interpretacji konfiguracji przez Amazon, będzie to bardzo cenne, podobnie jak w przypadku nzifnab, który wniósł za to nagrodę.

VKen
źródło

Odpowiedzi:

148

Aktualizacja z 10 września 2014:

Nie powinieneś już wykonywać żadnego z poniższych hacków dotyczących ciągu zapytania, ponieważ Cloudfront poprawnie obsługuje teraz CORS. Zobacz http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ i tę odpowiedź, aby uzyskać więcej informacji: https://stackoverflow.com/a/25305915/308315


OK, w końcu sprawiłem, że czcionki działały przy użyciu poniższej konfiguracji z niewielkimi poprawkami z przykładów w dokumentacji.

Moje czcionki są hostowane na S3, ale są obsługiwane przez Cloudfront.

Nie jestem pewien, dlaczego to działa, domyślam się, że pewnie <AllowedMethod> GETi <AllowedHeader> Content-*jest potrzebne.

Jeśli ktoś biegle posługujący się konfiguracją Amazon S3 CORS może rzucić na to trochę światła, będzie to bardzo wdzięczne.

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

edytować:

Niektórzy programiści mają problemy z buforowaniem Access-Control-Allow-Originnagłówka przez Cloudfront . Ten problem został rozwiązany przez pracowników AWS w linku ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) poniżej, z komentarzem @ Jeff-Atwood.

W połączonym wątku, jako obejście, zaleca się użycie ciągu zapytania do rozróżnienia wywołań z różnych domen. Przedstawię tutaj skrócony przykład.

Używanie curldo sprawdzania nagłówków odpowiedzi:

Domena A: a.domena.com

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

Nagłówki odpowiedzi z domeny 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

Domena B: b.domain.com

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

Nagłówki odpowiedzi z domeny 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

Zauważysz, że Access-Control-Allow-Originzwrócił różne wartości, które przeszły przez buforowanie Cloudfront.

VKen
źródło
2
czy wystąpiły problemy podobne do opisanych tutaj - Access-Control-Allow-Originnagłówek jest zapisywany w pamięci podręcznej i unieważnia mechanizm CORS, gdy kolejne żądanie jest wysyłane za pośrednictwem innej subdomeny?
ov
1
@ov Nie mam problemu, ponieważ wyraźnie ustawiam domeny korzystające z zasobów. Przeczytałem link, który zamieściłeś wcześniej. Jak przez mgłę pamiętałem odpowiedzi w innym wątku mówiące, że domeny muszą być wyraźnie określone, więc <AllowedOrigin> * </AllowedOrigin> nie jest w rzeczywistości dozwolone z powodu pewnych ograniczeń. Nie mogę teraz znaleźć tych postów z odpowiedzią, może to być post na blogu, który przeczytałem gdzie indziej. Mam nadzieję, że to pomoże.
VKen
3
Możesz mieć wiele elementów AllowedOrigin w jednym elemencie CORSRule, więc możesz połączyć te CORSRules w jeden element, ponieważ inne elementy w nich są identyczne.
Ben Hull,
4
@dan, jeśli zasobnik S3 jest obsługiwany przez CloudFront, wydaje się, że odpowiedzią jest zróżnicowanie zapytań czcionek według domeny, jak udokumentowano w tej oficjalnej odpowiedzi Amazon: forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood
2
To był niezwykle frustrujący problem. Dobrą wiadomością jest to, że S3 wydaje się teraz postępować właściwie, więc przynajmniej możliwe jest serwowanie wszystkiego innego niż czcionki internetowe przez CloudFront i serwowanie plików czcionek bezpośrednio z S3. Niestety, ten wątpliwy hack nie jest tak naprawdę praktyczny w naszej aplikacji bez bardziej znaczącej refaktoryzacji, ponieważ wszystkie zasoby są obsługiwane przez potok zasobów Rails i nie ma wygodnego sposobu na modyfikowanie adresów URL zasobów w czasie żądania (wszystkie są generowane podczas wdrażania kiedy zasoby są prekompilowane). Adres URL czcionki w css jest już na S3.
Zach Lipton
99

Po pewnych poprawkach wydaje mi się, że udało mi się to bez hackowania ciągu zapytania. Więcej informacji tutaj: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Przejdę przez całą moją konfigurację, aby łatwo było zobaczyć, co zrobiłem, mam nadzieję, że pomoże to innym.

Informacje ogólne: Używam aplikacji Rails, która ma klejnot asset_sync do umieszczania zasobów na S3. Obejmuje to czcionki.

W konsoli S3 kliknąłem mój zasobnik, właściwości i „edytuj konfigurację cors”, tutaj: Przycisk konfiguracji CORS

W polu tekstowym mam coś takiego:

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

Następnie w panelu Cloudfront ( https://console.aws.amazon.com/cloudfront/home ) utworzyłem dystrybucję, dodałem Origin, które wskazywało na moje wiadro S3 dodanie początku

Następnie dodano zachowanie dla domyślnej ścieżki, aby wskazywało na punkt początkowy oparty na S3, który ustawiłem. To, co też zrobiłem, to kliknięcie nagłówków białej listy i dodanie Origin: dodanie zachowania i nagłówków białej listy

To, co dzieje się teraz, jest następujące, co uważam za słuszne:

1) Sprawdź, czy nagłówki S3 są ustawione prawidłowo

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) Sprawdź, czy Cloudfront działa z nagłówkami

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

(Zauważ, że powyższy błąd był chybiony przez Cloudfront, ponieważ te pliki są buforowane przez 180 sekund, ale to samo działało na trafieniach)

3) Hit cloudfront z innym źródłem (ale takim, które jest dozwolone na CORS dla zasobnika S3) - Access-Control-Allow-Originnie jest buforowane! yay!

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

Zauważ powyżej, że domena została pomyślnie zmieniona bez hackowania ciągu zapytania.

Kiedy zmieniam nagłówek Origin, wydaje się, że zawsze pojawia X-Cache: Miss from cloudfrontsię na pierwszym żądaniu, a potem otrzymuję oczekiwaneX-Cache: Hit from cloudfront

PS Warto zauważyć, że podczas wykonywania curl -I (duże I) NIE pokaże nagłówków Access-Control-Allow-Origin, ponieważ jest to tylko HEAD, robię -i, aby uczynić go GET i przewinąć w górę.

Eamonn Gahan
źródło
Pracował, gdy nie wszyscy inni. Dziękujemy za poświęcenie czasu na tak szczegółowe publikowanie!
iwasrobbed
To działa!! Do Twojej wiadomości - miałem ogromny tekst odpowiedzi http podczas testowania tego ... zamierzam edytować odpowiedź, aby użyć tego rozwiązania curl ... stackoverflow.com/questions/10060098/…
Michael Gorham
Fajne dzięki chłopaki - cieszę się, że to działa dla innych.
Eamonn Gahan
Nie mogę Ci powiedzieć, jak bardzo nam pomogłeś! +1
nic specjalnego tutaj
1
+1 za dodanie nagłówka klienta Originod przeglądających, aby Cloudfront buforował obiekt na podstawie tego nagłówka (i przekazał nagłówki CORS serwera z powrotem do użytkownika)
Sébastien Saunier
13

Moje czcionki były poprawnie wyświetlane aż do ostatniego wypychania do Heroku ... Nie wiem dlaczego, ale symbol wieloznaczny w dozwolonym pochodzeniu CORS przestał działać. Dodałem wszystkie moje domeny prepro i pro do zasad CORS w ustawieniu zasobnika, więc teraz wygląda to tak:

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

AKTUALIZACJA: dodaj http://localhost:PORTteż

luigi7up
źródło
1
Dziękuję za udostępnienie tego rozwiązania. To zadziałało dla mnie.
Ryan Montgomery,
8

Cóż, w dokumentacji stwierdza się, że konfigurację można zapisać jako „zasób podrzędny cors w swoim zasobniku”. Uznałem to za oznaczające, że utworzę plik o nazwie „cors” w katalogu głównym mojego wiadra z konfiguracją, ale to nie zadziała. W końcu musiałem zalogować się do obszaru administracyjnego Amazon S3 i dodać konfigurację w propertiesoknie dialogowym mojego wiadra.

S3 przydałaby się lepsza dokumentacja ...

nzifnab
źródło
1
Tak, ale miałem szczęście, że zauważyłem kilka nowych zmian interfejsu w panelu właściwości. Edytowałem zasady zasobnika, więc naturalnie szukam konfiguracji CORS w tym samym panelu.
VKen
pracował dla mnie, chciałem ustawić to w mojej aplikacji, który wiedział, że to będzie takie proste
Richlewis
7

W konfiguracji Amazon S3 CORS (S3 Bucket / Permissions / CORS), jeśli używasz tego:

<?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 działa dobrze w przypadku plików JavaScript i CSS, ale nie działa w przypadku plików czcionek .

Musisz określić domenę, aby zezwolić na CORS przy użyciu wzorca wyrażonego w odpowiedzi @VKen: https://stackoverflow.com/a/25305915/618464

Więc użyj tego :

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

Pamiętaj, aby zastąpić „mojadomena.com” nazwą swojej domeny.

Następnie unieważnij pamięć podręczną CloudFront (CloudFront / Invalidations / Create Invalidation) i zadziała.

Educoutinho
źródło
6

W moim przypadku nie zdefiniowałem przestrzeni nazw i wersji XML w konfiguracji CORS. Zdefiniowanie tych zadziałało.

Zmieniony

<CORSConfiguration>

do

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
Gaurav Toshniwal
źródło
U mnie też działa. Moje czcionki są hostowane w samym zasobniku.
khamaileon
Nie rozumiem, dlaczego domyślny szablon nie zawiera tego automatycznie.
CoatedMoose
5

Jest lepszy i łatwiejszy sposób!

Osobiście wolę używać moich subdomen DNS, aby rozwiązać ten problem. Jeśli mój CDN jest za cdn.myawesomeapp.com zamiast sdf73n7ssa.cloudfront.net, przeglądarki nie będą oszukiwać i blokować ich jako problemy z bezpieczeństwem międzydomenowym.

Aby skierować swoją subdomenę do domeny AWS Cloudfront, przejdź do panelu sterowania AWS Cloudfront, wybierz swoją dystrybucję Cloudfront i wprowadź subdomenę CDN w polu Alternate Domain Names (CNAME). Coś takiego jak cdn.myawesomeapp.com zrobi.

Teraz możesz przejść do swojego dostawcy DNS (takiego jak AWS Route 53) i utworzyć CNAME dla cdn.myawesomeapp.com wskazujące na sdf73n7ssa.cloudfront.net.

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

msroot
źródło
To zrywa SSL, a raczej kosztuje dużo pieniędzy z SSL, dlatego wiele osób tego nie robi.
maletor
4

Ta konfiguracja zadziałała dla mnie. Umiem wyświetlić listę obiektów, pobrać, zaktualizować i usunąć.

<?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
źródło
musisz zmienić domenę, ponieważ testowałem z lokalnego hosta, po prostu spójrz na tę stronę dla CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/ ...
Shahid
1
<ifModule mod_headers.c>

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

</ifModule>

Proste rozwiązanie

O-mkar
źródło
Dzięki za udostępnienie! Dał mi pomysł, aby po prostu dodać ten nagłówek jako „metadane” podczas przesyłania statycznych zasobów do pamięci w chmurze. (Chociaż w ten sposób zadziała tylko z 1 particular domainlub all domains)
Vinay Vissh
0

Ponowne uruchomienie mojej aplikacji (serwera) rozruchu wiosennego rozwiązało problem za mnie.

Skonfigurowałem poprawnie CORS na S3. Curl dawał poprawną odpowiedź z nagłówkiem pochodzenia. Safari poprawnie pobierało czcionkę. Tylko chrom nie chciał zaakceptować CORS-a.

Nie wiem, co dokładnie spowodowało to zachowanie. To musi mieć coś wspólnego z if-modified-since

Sujit Kamthe
źródło
0

Nie jest to związane z czcionkami, ale z obrazami, może to być przypadek skrajny, ale jak mi się przydarzyło, może się zdarzyć z innym. Zostawię to tutaj, mając nadzieję, że pomoże to komuś:

Jeśli jesteś w scenariuszu „Zrobiłem wszystko, co powiedzieli, ale to nadal nie zadziała” prawdopodobnie jest to problem związany z pamięcią podręczną w Chrome i Safari. Załóżmy, że Twój serwer ma odpowiedni zestaw konfiguracyjny CORS:

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

w Firefoksie wszystko działa dobrze, ale w Chrome i Safari nie. Jeśli uzyskujesz dostęp do zdalnej ścieżki obrazu zarówno z prostego <img src="http://my.remote.server.com/images/cat.png">tagu, jak i z elementu src js Image, na przykład w następujący sposób:

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'

Możesz uzyskać No 'Access-Control-Allow-Origin'błąd w przeglądarce Chrome i Safari. Dzieje się tak, ponieważ pierwsza w <img>jakiś sposób psuje pamięć podręczną przeglądarki, a kiedy próbujesz później uzyskać dostęp do tego samego obrazu (w elemencie Image w kodzie), po prostu się psuje. Aby tego uniknąć, możesz dodać fikcyjny parametr GET do jednej ścieżki .src, aby zmusić przeglądarkę do ponownego zażądania obrazu i uniknięcia korzystania z pamięci podręcznej, na przykład:

<img src="http://my.remote.server.com/images/cat.png?nocache=true"></img>
Nicola Elia
źródło
-1

Tak oczywiście. Firefox obsługuje CORS dla czcionek, tak jak wymaga tego specyfikacja pod adresem http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading

Boris Zbarsky
źródło
Dziękuję za szybką odpowiedź, Boris Zbarsky. Czy byłbyś w stanie pokazać kilka przykładowych konfiguracji ustawień S3 CORS?
VKen
Nigdy nie zastanawiałem się nad konfiguracją S3 ... Jeśli chodzi o wysyłanie na poziomie HTTP, jeśli nie masz nic przeciwko temu, wystarczy wysłać „Access-Control-Allow-Origin: *” w odpowiedzi HTTP dla plików czcionek powinno działać.
Boris Zbarsky
Dzięki, próbuję dowiedzieć się dokładnie, jak zrobić to ustawienie z konfiguracjami S3 CORS.
VKen