Laden von domänenübergreifenden Amazon S3 CORS- (Cross-Origin Resource Sharing) und Firefox-Schriftarten


134

Es gibt seit langem ein Problem damit, dass Firefox keine Schriftarten von einem anderen Ursprung als der aktuellen Webseite lädt. Normalerweise tritt das Problem auf, wenn die Schriftarten auf CDNs bereitgestellt werden.

In anderen Fragen wurden verschiedene Lösungen angesprochen:

CSS @ font-face funktioniert nicht mit Firefox, sondern mit Chrome und IE

Gibt es mit der Einführung von Amazon S3 CORS eine Lösung, die CORS verwendet, um das Problem beim Laden von Schriftarten in Firefox zu beheben?

edit: Es wäre toll, ein Beispiel der S3 CORS-Konfiguration zu sehen.

edit2: Ich habe eine funktionierende Lösung gefunden, ohne wirklich zu verstehen, was sie getan hat. Wenn jemand detailliertere Erklärungen zu den Konfigurationen und der Hintergrundmagie geben könnte, die bei der Interpretation der Konfiguration durch Amazon auftreten, wird dies sehr geschätzt, wie bei nzifnab, der ein Kopfgeld dafür aufbringt.

Antworten:


148

Update 10. September 2014:

Sie sollten keine der folgenden Abfragenzeichenfolgen-Hacks mehr durchführen müssen, da Cloudfront CORS jetzt ordnungsgemäß unterstützt. Weitere Informationen finden Sie unter http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ und in dieser Antwort: https://stackoverflow.com/a/25305915/308315


OK, ich habe endlich die Schriftarten mit der folgenden Konfiguration zum Laufen gebracht, mit ein wenig Optimierung anhand von Beispielen in der Dokumentation.

Meine Schriftarten werden auf S3 gehostet, aber von Cloudfront.

Ich bin nicht sicher, warum es funktioniert, meine Vermutung ist wahrscheinlich, dass das <AllowedMethod> GETund <AllowedHeader> Content-*benötigt wird.

Wenn jemand, der mit der Amazon S3 CORS-Konfiguration vertraut ist, etwas Licht ins Dunkel bringen kann, wird dies sehr geschätzt.

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

bearbeiten:

Einige Entwickler haben Probleme mit dem Zwischenspeichern des Access-Control-Allow-OriginHeaders durch Cloudfront . Dieses Problem wurde von den AWS-Mitarbeitern unter dem folgenden Link ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) behoben, der von @ Jeff-Atwood kommentiert wurde.

Aus dem verlinkten Thread, ist es ratsam, als Behelfslösung, eine verwenden Abfrage - Zeichenfolge für die Unterscheidung zwischen Anrufen aus verschiedenen Bereichen. Ich werde das verkürzte Beispiel hier wiedergeben.

Verwenden curlzum Überprüfen von Antwortheadern:

Domain A: a.domain.com

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

Antwortheader von Domäne 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

Domain B: b.domain.com

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

Antwortheader von Domäne 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

Sie werden feststellen, dass Access-Control-Allow-Originunterschiedliche Werte zurückgegeben wurden, die das Cloudfront-Caching überschritten haben.


2
Haben Sie ähnliche Probleme wie hier beschrieben festgestellt - der Access-Control-Allow-OriginHeader wird zwischengespeichert und macht CORS ungültig, wenn eine nachfolgende Anforderung über eine andere Subdomain erfolgt?
ov

1
@ov Das Problem tritt nicht auf, da ich die Domänen, die die Ressourcen verwenden, explizit festgelegt habe. Ich habe den Link gelesen, den Sie zuvor gepostet haben. Ich erinnerte mich vage an einige Antworten in einem anderen Thread, die besagten, dass Domains explizit angegeben werden müssen, sodass <AllowedOrigin> * </ AllowedOrigin> aufgrund einiger Einschränkungen nicht zulässig ist. Ich kann diese Antwortbeiträge jetzt nicht finden. Es könnte sich um einen Blogbeitrag handeln, den ich an anderer Stelle gelesen habe. Hoffentlich hilft das.
VKen

3
Sie können mehrere AllowedOrigin-Elemente in einem einzelnen CORSRule-Element haben, sodass Sie diese CORSRules zu einem einzigen Element kombinieren können, da die anderen Elemente in ihnen identisch sind.
Ben Hull

4
@dan Wenn der S3-Bucket von CloudFront bereitgestellt wird, besteht die Antwort darin, die Abfrage der Schriftart nach Domain zu variieren, wie in dieser offiziellen Amazon-Antwort dokumentiert: forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood

2
Dies war ein äußerst frustrierendes Problem. Die gute Nachricht ist, dass S3 jetzt anscheinend das Richtige tut, sodass es zumindest möglich ist, alles andere als Webfonts über CloudFront bereitzustellen und die Schriftdateien direkt aus S3 bereitzustellen. Leider ist der Querystring-Hack in unserer Anwendung ohne umfangreicheres Refactoring nicht wirklich praktisch, da die Assets alle über die Rails-Asset-Pipeline bereitgestellt werden und es keine bequeme Möglichkeit gibt, die Asset-URLs zur Anforderungszeit zu optimieren (sie werden alle während der Bereitstellung generiert) wenn die Vermögenswerte vorkompiliert sind). Die URL der Schriftart in CSS ist bereits in S3 verfügbar.
Zach Lipton

97

Nach einigen Optimierungen scheint dies ohne den Abfragezeichenfolgen-Hack zu funktionieren. Weitere Informationen finden Sie hier: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Ich werde mein gesamtes Setup durchgehen, damit ich leicht sehen kann, was ich getan habe. Hoffentlich hilft dies anderen.

Hintergrundinformationen: Ich verwende eine Rails-App mit dem Juwel "Asset_Sync", um Assets in S3 zu platzieren. Dies schließt Schriftarten ein.

In der S3-Konsole habe ich hier auf meinen Bucket, Eigenschaften und 'Cors-Konfiguration bearbeiten' geklickt: CORS-Konfigurationstaste

Im Textbereich habe ich so etwas wie:

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

Dann habe ich im Cloudfront-Bereich ( https://console.aws.amazon.com/cloudfront/home ) eine Distribution erstellt und einen Origin hinzugefügt, der auf meinen S3-Bucket verweistHinzufügen eines Ursprungs

Anschließend wurde ein Verhalten für einen Standardpfad hinzugefügt, der auf das S3-basierte Ursprungs-I-Setup verweist. Ich habe auch auf Whitelist-Header geklickt und hinzugefügt Origin: Hinzufügen eines Verhaltens und von Whitelist-Headern

Was jetzt passiert, ist das Folgende, was ich für richtig halte:

1) Überprüfen Sie, ob die S3-Header richtig eingestellt sind

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) Überprüfen Sie, ob Cloudfront mit den Headern funktioniert

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

(Beachten Sie, dass das oben Genannte ein Fehler von der Cloudfront war, da diese Dateien 180 Sekunden lang zwischengespeichert werden, aber dasselbe funktionierte bei Treffern.)

3) Schlagen Sie die Cloudfront mit einem anderen Ursprung an (aber einem, der auf CORS für den S3-Bucket zulässig ist) - der Access-Control-Allow-Originwird nicht zwischengespeichert! 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==

Beachten Sie oben, dass die Domain ohne einen Hack für Abfragezeichenfolgen erfolgreich geändert wurde.

Wenn ich den Origin-Header ändere, scheint es immer eine X-Cache: Miss from cloudfrontbei der ersten Anfrage zu geben, danach erhalte ich die erwarteteX-Cache: Hit from cloudfront

PS Es ist erwähnenswert, dass bei Curl -I (Großbuchstabe I) die Header Access-Control-Allow-Origin NICHT angezeigt werden, da es sich nur um einen HEAD handelt. Ich mache -i, um es zu einem GET zu machen und nach oben zu scrollen.


Arbeitete, als alle anderen es nicht taten. Vielen Dank, dass Sie sich die Zeit genommen haben, so detailliert zu posten!
Ich wurde


Cool, danke Jungs - ich bin froh zu sehen, dass es für andere funktioniert.
Eamonn Gahan

Ich kann dir nicht sagen, wie sehr du uns geholfen hast! +1
nichts Besonderes-hier

1
+1 für das Hinzufügen des Kunden-Headers Originaus den Viewern, sodass Cloudfront das Objekt basierend auf diesem Header zwischenspeichert (und die CORS-Header des Servers an den Benutzer zurückleitet)
Sébastien Saunier

13

Meine Schriftarten wurden bis zum letzten Push an Heroku korrekt bereitgestellt ... Ich weiß nicht warum, aber der Platzhalter im CORS erlaubte, dass der Ursprung nicht mehr funktionierte. Ich habe der CORS-Richtlinie in der Bucket-Einstellung alle meine Prepro- und Pro- Domains hinzugefügt. Jetzt sieht es so aus:

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

UPDATE: Fügen Sie http://localhost:PORTauch Ihre hinzu


1
Vielen Dank, dass Sie diese Lösung geteilt haben. Das hat bei mir funktioniert.
Ryan Montgomery

8

In der Dokumentation heißt es, dass Sie die Konfiguration als "die cors-Subressource in Ihrem Bucket" speichern können. Ich habe das so verstanden, dass ich mit der Konfiguration eine Datei namens "cors" im Stammverzeichnis meines Buckets erstellen würde, aber das würde nicht funktionieren. Am Ende musste ich mich im Amazon S3-Verwaltungsbereich anmelden und die Konfiguration im propertiesDialogfeld meines Buckets hinzufügen .

S3 könnte eine bessere Dokumentation gebrauchen ...


1
Ja, aber ich hatte das Glück, einige neue Änderungen an der Benutzeroberfläche im Eigenschaftenfenster zu entdecken. Ich habe Bucket-Richtlinien bearbeitet, daher suche ich natürlich im selben Bereich nach der CORS-Konfiguration.
VKen

arbeitete für mich, ich wollte dies in meiner Anwendung festlegen, wer wusste, dass es so einfach sein würde
Richlewis

7

Wenn Sie in der Amazon S3 CORS-Konfiguration (S3 Bucket / Permissions / CORS) Folgendes verwenden:

<?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 funktioniert gut für Javascript- und CSS-Dateien, aber nicht für Schriftdateien .

Sie müssen die Domäne angeben, damit CORS das in der @ VKen-Antwort angegebene Muster zulässt: https://stackoverflow.com/a/25305915/618464

Verwenden Sie also Folgendes :

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

Denken Sie daran, "mydomain.com" für Ihre Domain zu ersetzen.

Danach machen Sie den CloudFront-Cache ungültig (CloudFront / Invalidations / Create Invalidation) und es wird funktionieren.


6

In meinem Fall hatte ich den XML-Namespace und die XML-Version in der CORS-Konfiguration nicht definiert. Definieren Sie die funktionierten.

Geändert

<CORSConfiguration>

zu

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

Funktioniert auch bei mir. Meine Schriftarten werden im Bucket selbst gehostet.
Khamaileon

Warum die Standardvorlage dies nicht automatisch enthält, ist mir ein Rätsel.
CoatedMoose

4

Es gibt einen besseren und einfacheren Weg!

Ich persönlich bevorzuge die Verwendung meiner DNS-Subdomains, um dieses Problem zu lösen. Wenn sich mein CDN hinter cdn.myawesomeapp.com anstelle von sdf73n7ssa.cloudfront.net befindet, werden Browser nicht ausflippen und sie als domänenübergreifende Sicherheitsprobleme blockieren.

Um Ihre Subdomain auf Ihre AWS Cloudfront-Domain zu verweisen, rufen Sie das AWS Cloudfront-Kontrollfeld auf, wählen Sie Ihre Cloudfront-Distribution aus und geben Sie Ihre CDN-Subdomain in das Feld Alternative Domain Names (CNAMEs) ein. So etwas wie cdn.myawesomeapp.com reicht aus.

Jetzt können Sie zu Ihrem DNS-Anbieter (wie AWS Route 53) gehen und einen CNAME für cdn.myawesomeapp.com erstellen, der auf sdf73n7ssa.cloudfront.net verweist.

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


Dies bricht SSL oder vielmehr kostet es viel Geld, mit SSL zu arbeiten, daher tun dies viele Leute nicht.
Maletor

4

Diese Konfiguration hat bei mir funktioniert. Ich kann Objekte auflisten, abrufen, aktualisieren und löschen.

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

Sie müssen die Domain ändern, da ich von localhost getestet habe. Schauen Sie einfach auf dieser Seite nach CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Shahid

1
<ifModule mod_headers.c>

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

</ifModule>

Einfache Lösung


Danke für das Teilen! Hat mich auf die Idee gebracht, diesen Header einfach als 'Metadaten' hinzuzufügen , während statische Assets in den Cloud-Speicher hochgeladen werden . (Obwohl so funktioniert es nur mit 1 particular domainoder all domains)
Vinay Vissh

0

Ein Neustart meiner Spring Boot-Anwendung (Server) hat das Problem für mich gelöst.

Ich hatte CORS auf S3 richtig konfiguriert. Die Locke gab die richtige Antwort mit dem Ursprungsheader. Safari hat die Schriftart korrekt abgerufen. Es war nur das Chrom, das nicht bereit war, das CORS zu akzeptieren.

Ich bin mir nicht sicher, was genau das Verhalten verursacht hat. Muss etwas mit If-modifiziert-seit zu tun haben


0

Dies bezieht sich nicht auf Schriftarten, sondern auf Bilder. Es kann sich um einen Randfall handeln, aber wie es mir passiert ist, kann es auch einem anderen passieren. Ich lasse das hier in der Hoffnung, dass es jemandem hilft:

Wenn Sie sich im Szenario "Ich habe alles getan, was sie gesagt haben, aber es funktioniert immer noch nicht" befinden, handelt es sich wahrscheinlich um ein Cache-Problem in Chrome und Safari. Angenommen, Ihr Server verfügt über einen geeigneten CORS-Konfigurationssatz:

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

und in Firefox funktioniert alles gut, in Chrome und Safari jedoch nicht. Wenn Sie sowohl über ein einfaches <img src="http://my.remote.server.com/images/cat.png">Tag als auch über ein js Image-Element src auf Ihren Remote-Image-Pfad zugreifen, wie folgt:

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'

Möglicherweise wird der No 'Access-Control-Allow-Origin'Fehler in Chrome und Safari angezeigt. Dies geschieht, weil der erste <img>den Browser-Cache irgendwie durcheinander bringt und wenn Sie später versuchen, auf dasselbe Bild zuzugreifen (auf das In-Code-Image-Element), wird es einfach unterbrochen. Um dies zu vermeiden, können Sie einem .src-Pfad einen fiktiven GET-Parameter hinzufügen, um den Browser zu zwingen, das Bild erneut anzufordern und die Verwendung des Cache wie folgt zu vermeiden:

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

-1

Ja natürlich. Firefox unterstützt CORS für Schriftarten, genau wie es die Spezifikation unter http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading erfordert


Vielen Dank für Ihre schnelle Antwort, Boris Zbarsky. Können Sie einige Beispielkonfigurationen für die S3 CORS-Einstellungen anzeigen?
VKen

Ich habe mich noch nie mit der Konfiguration von S3 befasst ... Wenn Sie damit einverstanden sind, senden Sie einfach "Access-Control-Allow-Origin: *" in der HTTP-Antwort für die Schriftdateien sollte arbeiten.
Boris Zbarsky

Vielen Dank, ich versuche genau herauszufinden, wie diese Einstellung mit den S3 CORS-Konfigurationen durchgeführt wird.
VKen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.