Amazon S3 CORS (Berbagi Sumber Daya Silang) dan pemuatan font lintas domain Firefox

134

Ada masalah lama dengan Firefox yang tidak memuat font dari asal yang berbeda dari halaman web saat ini. Biasanya, masalah muncul ketika font disajikan pada CDN.

Berbagai solusi telah diajukan dalam pertanyaan lain:

CSS @ font-face tidak bekerja dengan Firefox, tetapi bekerja dengan Chrome dan IE

Dengan diperkenalkannya Amazon S3 CORS, apakah ada solusi menggunakan CORS untuk mengatasi masalah pemuatan font di Firefox?

sunting: Akan sangat bagus untuk melihat contoh konfigurasi S3 CORS.

sunting2: Saya telah menemukan solusi yang berfungsi tanpa benar-benar memahami apa yang dilakukannya. Jika ada yang bisa memberikan penjelasan lebih rinci tentang konfigurasi dan sihir latar belakang yang terjadi pada interpretasi Amazon tentang konfigurasi, itu akan sangat dihargai, seperti halnya dengan nzifnab yang memberikan hadiah untuk itu.

VKen
sumber

Jawaban:

148

Pembaruan 10 September 2014:

Anda tidak perlu lagi melakukan peretasan string kueri di bawah ini karena Cloudfront mendukung CORS dengan benar sekarang. Lihat http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ dan jawaban ini untuk info lebih lanjut: https://stackoverflow.com/a/25305915/308315


OK, saya akhirnya membuat font bekerja menggunakan konfigurasi di bawah ini dengan sedikit perubahan dari contoh dalam dokumentasi.

Font saya di-host pada S3, tetapi digawangi oleh cloudfront.

Saya tidak yakin mengapa itu berhasil, dugaan saya mungkin <AllowedMethod> GETdan <AllowedHeader> Content-*diperlukan.

Jika ada yang mahir dengan konfigurasi Amazon S3 CORS dapat menjelaskan ini, itu akan sangat dihargai.

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

edit:

Beberapa pengembang menghadapi masalah caching Access-Control-Allow-Originheader Cloudfront . Masalah ini telah diatasi oleh staf AWS di tautan ( https://forums.aws.amazon.com/thread.jspa?threadID=114646 ) di bawah ini, dikomentari oleh @ Jeff-Atwood.

Dari utas tertaut, disarankan, sebagai solusi, untuk menggunakan String Kueri untuk membedakan antara panggilan dari domain yang berbeda. Saya akan mereproduksi contoh singkat di sini.

Menggunakan curluntuk memeriksa header respons:

Domain A: a.domain.com

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

Header respons dari Domain 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

Header respons dari Domain 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

Anda akan melihat Access-Control-Allow-Origintelah mengembalikan nilai yang berbeda, yang berhasil melewati caching Cloudfront.

VKen
sumber
2
Sudahkah Anda mengalami masalah yang mirip dengan yang dijelaskan di sini - Access-Control-Allow-Originheader di-cache dan membatalkan CORS ketika permintaan selanjutnya dilakukan melalui subdomain yang berbeda?
Ov
1
@ov Saya tidak mengalami masalah karena saya secara eksplisit mengatur domain yang menggunakan sumber daya. Saya telah membaca tautan yang Anda poskan sebelumnya. Samar-samar saya ingat beberapa balasan pada utas lain yang mengatakan bahwa domain harus dinyatakan secara eksplisit, jadi <AllowedOrigin> * </AllowedOrigin> sebenarnya tidak diizinkan, karena beberapa batasan. Saya tidak dapat menemukan posting balasan itu sekarang, bisa jadi posting blog yang saya baca di tempat lain. Semoga itu bisa membantu.
VKen
3
Anda dapat memiliki beberapa elemen DiizinkanOrigin di dalam elemen CORSRule tunggal, sehingga Anda dapat menggabungkan CORSRules menjadi elemen tunggal, karena elemen lain di dalamnya identik.
Ben Hull
4
@dan jika bucket S3 dilayani oleh CloudFront, sepertinya jawabannya adalah memvariasikan font querystring menurut domain seperti yang didokumentasikan dalam jawaban resmi Amazon ini: forums.aws.amazon.com/thread.jspa?threadID=114646
Jeff Atwood
2
Ini merupakan masalah yang sangat membuat frustrasi. Kabar baiknya adalah S3 sekarang tampaknya melakukan hal yang benar, jadi setidaknya mungkin untuk melayani segala sesuatu selain webfont melalui CloudFront dan melayani file font langsung dari S3. Sayangnya, querystring hack tidak benar-benar praktis dalam aplikasi kita tanpa refactoring yang lebih signifikan, karena semua aset dilayani melalui pipa aset Rails, dan tidak ada cara yang mudah untuk mengubah URL aset pada waktu permintaan (semuanya dihasilkan selama penyebaran ketika aset dikompilasi). URL font di css sudah di atas S3.
Zach Lipton
97

Setelah beberapa tweaker, saya tampaknya telah berhasil ini tanpa peretasan string kueri. Info lebih lanjut di sini: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Saya akan pergi melalui seluruh pengaturan saya sehingga mudah untuk melihat apa yang telah saya lakukan, semoga ini membantu orang lain.

Informasi Latar Belakang: Saya menggunakan aplikasi Rails yang memiliki permata asset_sync untuk menempatkan aset ke S3. Ini termasuk font.

Di dalam konsol S3, saya mengklik ember, properti, dan 'edit konfigurasi kors' saya, di sini: Tombol konfigurasi CORS

Di dalam textarea saya punya sesuatu seperti:

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

Kemudian di dalam panel Cloudfront ( https://console.aws.amazon.com/cloudfront/home ) saya membuat distribusi, menambahkan Origin yang menunjuk ke ember S3 saya menambahkan asal

Kemudian menambahkan perilaku untuk jalur default untuk menunjuk ke pengaturan saya asal S3 berbasis. Apa yang saya juga lakukan adalah mengklik header Daftar Putih dan menambahkan Origin: menambahkan header perilaku dan daftar putih

Apa yang terjadi sekarang adalah yang berikut, yang saya yakini benar:

1) Periksa apakah header S3 sedang diatur dengan benar

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) Periksa Cloudfront berfungsi dengan header

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

(Catatan di atas adalah kehilangan dari cloudfront karena file-file ini di-cache selama 180 detik, tetapi hal yang sama berhasil pada hit)

3) Memukul cloudfront dengan asal yang berbeda (tapi yang diizinkan pada CORS untuk bucket S3) - yang Access-Control-Allow-Origintidak di-cache! 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==

Perhatikan di atas bahwa domain berhasil diubah tanpa peretasan string kueri.

Ketika saya mengubah header Origin, sepertinya selalu ada X-Cache: Miss from cloudfrontpada permintaan pertama kemudian setelah itu saya mendapatkan yang diharapkanX-Cache: Hit from cloudfront

PS Perlu dicatat bahwa ketika melakukan curl -I (modal I) TIDAK akan menunjukkan header Access-Control-Allow-Origin karena hanya HEAD, saya lakukan -i untuk membuatnya GET dan gulir ke atas.

Eamonn Gahan
sumber
Bekerja ketika yang lain tidak. Terima kasih telah meluangkan waktu untuk memposting dengan detail seperti itu!
iwasrobbed
Berhasil!! FYI - Saya punya teks respons http yang sangat besar ketika menguji ini ... akan mengedit jawaban untuk menggunakan solusi ikal ini ... stackoverflow.com/questions/10060098/
Michael Gorham
Keren, terima kasih teman-teman - senang melihatnya bekerja untuk orang lain.
Eamonn Gahan
Saya tidak bisa memberi tahu Anda betapa Anda telah membantu kami! +1
tidak ada yang istimewa di sini
1
+1 untuk menambahkan header pelanggan Origindari pemirsa sehingga Cloudfront cache objek berdasarkan header itu (dan meneruskan server CORS header kembali ke pengguna)
Sébastien Saunier
13

Font saya disajikan dengan benar hingga dorongan terakhir ke Heroku ... Saya tidak tahu mengapa, tetapi wildcard di CORS yang diizinkan asal berhenti berfungsi. Saya menambahkan semua domain prepro dan pro saya ke kebijakan CORS dalam pengaturan bucket jadi sekarang terlihat seperti ini:

<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: tambahkan http://localhost:PORTjuga Anda

luigi7up
sumber
1
Terima kasih telah berbagi solusi ini. Ini berhasil untuk saya.
Ryan Montgomery
8

Nah, dokumentasi menyatakan bahwa Anda dapat menempel konfigurasi sebagai "sub-sumber kor dalam ember Anda." Saya menganggap ini berarti saya akan membuat file bernama "cors" di root bucket saya dengan konfigurasi, tetapi ini tidak akan berhasil. Pada akhirnya saya harus masuk ke area administrasi Amazon S3 dan menambahkan konfigurasi dalam propertiesdialog ember saya.

S3 dapat menggunakan beberapa dokumentasi yang lebih baik ...

nzifnab
sumber
1
Yap, tapi saya beruntung melihat beberapa perubahan antarmuka baru di panel properti. Saya telah mengedit kebijakan bucket, jadi tentu saja saya mencari konfigurasi CORS di panel yang sama.
VKen
bekerja untuk saya, saya ingin mengatur ini di aplikasi saya, yang tahu itu akan sangat sederhana
Richlewis
7

Dalam konfigurasi Amazon S3 CORS (S3 Bucket / Izin / CORS) jika Anda menggunakan ini:

<?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 berfungsi dengan baik untuk file Javascript dan CSS, tetapi itu tidak berfungsi untuk file Font .

Anda harus menentukan domain untuk memungkinkan CORS menggunakan pola yang dinyatakan dalam jawaban @VKen: https://stackoverflow.com/a/25305915/618464

Jadi, gunakan ini :

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

Ingatlah untuk mengganti "mydomain.com" untuk domain Anda.

Setelah ini, batalkan cache CloudFront (CloudFront / Invalidations / Create Invalidation) dan itu akan berfungsi.

educoutinho
sumber
6

Dalam kasus saya, saya belum mendefinisikan XML namespace dan versi dalam konfigurasi CORS. Mendefinisikan itu berhasil.

Berubah

<CORSConfiguration>

untuk

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
Gaurav Toshniwal
sumber
Bekerja untuk saya juga. Font saya di-host di ember itu sendiri.
khamaileon
Mengapa templat bawaan tidak secara otomatis menyertakan ini di luar saya.
CoatedMoose
4

Ada cara yang lebih baik dan lebih mudah!

Saya pribadi lebih suka menggunakan subdomain DNS saya untuk menyelesaikan masalah ini. Jika CDN saya ada di belakang cdn.myawesomeapp.com alih-alih sdf73n7ssa.cloudfront.net maka browser tidak akan panik dan memblokirnya sebagai masalah keamanan lintas domain.

Untuk mengarahkan subdomain Anda ke domain AWS Cloudfront Anda, buka panel kontrol AWS Cloudfront, pilih distribusi Cloudfront Anda dan masukkan subdomain CDN Anda ke dalam bidang Nama Domain Alternatif (CNAME). Sesuatu seperti cdn.myawesomeapp.com akan dilakukan.

Sekarang Anda dapat pergi ke penyedia DNS Anda (seperti AWS Route 53) dan membuat CNAME untuk cdn.myawesomeapp.com dengan menunjuk ke sdf73n7ssa.cloudfront.net.

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

msroot
sumber
Hal ini merusak SSL atau lebih tepatnya menghabiskan banyak uang dengan SSL karena itu banyak orang tidak melakukan ini.
maletor
4

Konfigurasi ini bekerja untuk saya. Saya dapat membuat daftar objek, mengambil, memperbarui dan menghapus.

<?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
sumber
Anda perlu mengubah domain, karena saya sedang menguji dari localhost, Lihat saja halaman ini untuk CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Shahid
1
<ifModule mod_headers.c>

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

</ifModule>

Solusi Sederhana

O-mkar
sumber
Terima kasih telah berbagi! Memberi saya ide untuk hanya menambahkan tajuk ini sebagai 'meta-data' saat mengunggah aset statis ke penyimpanan cloud. (Meskipun demikian hanya akan bekerja dengan 1 particular domainatau all domains)
Vinay Vissh
0

Restart aplikasi boot spring saya (server) memecahkan masalah bagi saya.

Saya telah mengkonfigurasi CORS dengan benar pada S3. Curl memberi respons yang benar dengan header asli. Safari mengambil fon dengan benar. Hanya chrome yang tidak mau menerima CORS.

Tidak yakin apa yang sebenarnya menyebabkan perilaku itu. Pasti ada hubungannya dengan If-modified-since

Sujit Kamthe
sumber
0

Ini tidak terkait dengan font tetapi untuk gambar, itu mungkin kasus tepi, tetapi seperti yang terjadi pada saya, mungkin terjadi pada yang lain. Saya akan meninggalkan ini di sini berharap itu akan membantu seseorang:

Jika Anda berada dalam skenario "Saya telah melakukan semua yang mereka katakan, tetapi masih tidak berhasil" mungkin ini adalah masalah terkait cache di Chrome dan Safari. Misalkan server Anda memiliki set konfigurasi CORS yang tepat:

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

dan di Firefox semuanya bekerja dengan baik, tetapi di Chrome dan Safari tidak. Jika Anda mengakses ke jalur gambar jauh Anda dari kedua sederhana <img src="http://my.remote.server.com/images/cat.png">tag dan dari src js Gambar elemen, seperti dengan cara berikut:

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'

Anda mungkin mendapatkan No 'Access-Control-Allow-Origin'kesalahan di Chrome dan Safari. Ini terjadi karena yang pertama <img>entah bagaimana mengacaukan cache browser, dan ketika Anda mencoba untuk mengakses gambar yang sama kemudian (pada elemen Gambar dalam kode), itu hanya rusak. Untuk menghindari ini, Anda dapat menambahkan param GET fiktif ke satu jalur .src, untuk memaksa browser meminta kembali gambar dan menghindari menggunakan cache, seperti ini:

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

Ya tentu saja. Firefox mendukung CORS untuk font, seperti spesifikasi yang disyaratkan di http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading

Boris Zbarsky
sumber
Terima kasih atas tanggapan cepat Anda, Boris Zbarsky. Apakah Anda dapat menampilkan beberapa contoh konfigurasi untuk pengaturan S3 CORS?
VKen
Saya tidak pernah melihat ke konfigurasi S3 ... Sejauh apa yang harus dikirim pada tingkat HTTP, jika Anda setuju dengan itu hanya mengirim "Access-Control-Allow-Origin: *" dalam respons HTTP untuk file font harus bekerja.
Boris Zbarsky
Terima kasih, saya mencoba mencari tahu bagaimana melakukan pengaturan dengan konfigurasi S3 CORS.
VKen