Amazon S3 CORS (Cross-Origin Resource Sharing) и междоменная загрузка шрифтов Firefox

135

Давно существовала проблема с Firefox, который не загружал шрифт из другого источника, чем текущая веб-страница. Обычно проблема возникает, когда шрифты обслуживаются на CDN.

В других вопросах были подняты различные решения:

CSS @ font-face не работает с Firefox, но работает с Chrome и IE

Есть ли решение с использованием CORS для решения проблемы загрузки шрифтов в Firefox с появлением Amazon S3 CORS?

edit: Было бы здорово увидеть образец конфигурации S3 CORS.

edit2: Я нашел рабочее решение, не понимая, что оно делает. Если кто-нибудь сможет предоставить более подробные объяснения о конфигурациях и фоновой магии, которая происходит при интерпретации конфигурации Amazon, он будет очень признателен, как и nzifnab, который назначил за это вознаграждение.

VKen
источник

Ответы:

148

Обновление от 10 сентября 2014 г .:

Вам больше не нужно делать какие-либо взломы строки запроса ниже, поскольку Cloudfront теперь правильно поддерживает CORS. См. Http://aws.amazon.com/blogs/aws/enhanced-cloudfront-customization/ и этот ответ для получения дополнительной информации: https://stackoverflow.com/a/25305915/308315


Хорошо, я наконец-то заставил шрифты работать, используя конфигурацию ниже, с небольшой настройкой из примеров в документации.

Мои шрифты размещены на S3, но находятся на облачном сервере.

Я не уверен , почему это работает, я думаю, возможно , что <AllowedMethod> GETи <AllowedHeader> Content-*требуется.

Если кто-либо, владеющий конфигурацией Amazon S3 CORS, сможет пролить свет на это, мы будем очень признательны.

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

редактировать:

Некоторые разработчики сталкиваются с проблемами, связанными с кешированием Access-Control-Allow-Originзаголовка Cloudfront . Эта проблема решена сотрудниками AWS по ссылке ( https://forums.aws.amazon.com/thread.jspa?threadID=114646). ) и прокомментирована @ Jeff-Atwood.

Из связанного потока рекомендуется в качестве временного решения использовать строку запроса для различения вызовов из разных доменов. Я воспроизведу здесь сокращенный пример.

Используем curlдля проверки заголовков ответов:

Домен A: a.domain.com

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

Заголовки ответа из домена 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

Домен B: b.domain.com

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

Заголовки ответа из домена 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

Вы заметите, что Access-Control-Allow-Originон вернул разные значения, которые прошли кэширование Cloudfront.

VKen
источник
2
Были ли у вас проблемы, подобные описанным здесь - Access-Control-Allow-Originзаголовок кэшируется и делает CORS недействительным, когда последующий запрос выполняется через другой поддомен?
ov
1
@ov Я не испытываю этой проблемы, поскольку я явно задаю домены, использующие ресурсы. Я читал ссылку, которую вы разместили раньше. Я смутно вспомнил некоторые ответы в другом потоке, в которых говорилось, что домены должны быть явно указаны, поэтому <AllowedOrigin> * </AllowedOrigin> фактически не разрешен из-за некоторых ограничений. Я не могу найти эти ответные сообщения сейчас, это может быть сообщение в блоге, которое я читал в другом месте. Надеюсь, это поможет.
VKen 01
3
У вас может быть несколько элементов AllowedOrigin внутри одного элемента CORSRule, поэтому вы можете объединить эти CORSRule в один элемент, поскольку остальные элементы в них идентичны.
Бен Халл
4
@dan, если ведро S3 обслуживается CloudFront, похоже, что ответ заключается в изменении строки запроса шрифта по домену, как описано
Джефф Этвуд
2
Это была чрезвычайно неприятная проблема. Хорошая новость заключается в том, что теперь S3, похоже, поступает правильно, поэтому, по крайней мере, можно обслуживать все, кроме веб-шрифтов, через CloudFront, а файлы шрифтов - непосредственно из S3. К сожалению, взлом строки запроса не очень практичен в нашем приложении без более значительного рефакторинга, поскольку все ресурсы обслуживаются через конвейер ресурсов Rails, и нет удобного способа настроить URL-адреса ресурсов во время запроса (все они генерируются во время развертывания когда активы предварительно скомпилированы). URL-адрес шрифта в css уже установлен на S3.
Зак Липтон
97

После некоторой настройки мне кажется, что это работает без взлома строки запроса. Подробнее здесь: http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorS3Origin.html#RequestS3-cors

Я собираюсь пройти всю настройку, чтобы было легко увидеть, что я сделал, надеюсь, это поможет другим.

Общая информация: я использую приложение Rails, в котором есть гем asset_sync для размещения ресурсов на S3. Сюда входят шрифты.

В консоли S3 я щелкнул по своей корзине, свойствам и «редактировать конфигурацию cors», здесь: Кнопка конфигурации CORS

Внутри текстового поля у меня есть что-то вроде:

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

Затем на панели Cloudfront ( https://console.aws.amazon.com/cloudfront/home ) я создал дистрибутив, добавил источник, указывающий на мою корзину S3. добавление происхождения

Затем добавил поведение для пути по умолчанию, чтобы указать на исходную точку на основе S3, которую я установил. Я также нажал на заголовки белого списка и добавил Origin: добавление заголовков поведения и белого списка

Сейчас происходит следующее, что я считаю правильным:

1) Убедитесь, что заголовки S3 установлены правильно

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) Убедитесь, что Cloudfront работает с заголовками

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

(Обратите внимание, что вышеупомянутое было пропущено из облачного интерфейса, потому что эти файлы кэшируются в течение 180 секунд, но то же самое работало с обращениями)

3) Нажмите cloudfront с другим источником (но тем, который разрешен в CORS для ведра S3) - Access-Control-Allow-Originне кэшируется! ура!

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

Обратите внимание, что домен был успешно изменен без взлома строки запроса.

Когда я меняю заголовок Origin, кажется, что всегда X-Cache: Miss from cloudfrontпри первом запросе появляется сообщение, а затем я получаю ожидаемыйX-Cache: Hit from cloudfront

PS Стоит отметить, что при выполнении curl -I (заглавная I) НЕ будут отображаться заголовки Access-Control-Allow-Origin, поскольку это только HEAD, я делаю -i, чтобы сделать его GET и прокручивать вверх.

Имонн Гаан
источник
Работало, когда все остальные - нет. Спасибо, что нашли время опубликовать такую ​​подробную информацию!
iwasrobted
Оно работает!! К вашему сведению - при тестировании у меня был огромный текст ответа http ... собираюсь отредактировать ответ, чтобы использовать это решение curl ... stackoverflow.com/questions/10060098/…
Майкл Горхэм
Круто спасибо, ребята - рад видеть, что это работает для других.
Eamonn Gahan
Не могу передать, насколько вы нам помогли! +1
ничего особенного
1
+1 за добавление заголовка клиента Originиз средств просмотра, чтобы Cloudfront кэшировал объект на основе этого заголовка (и пересылал серверные заголовки CORS обратно пользователю)
Себастьен Сонье
13

Мои шрифты обслуживались правильно до последнего нажатия на Heroku ... Я не знаю почему, но подстановочный знак в разрешенном источнике CORS перестал работать. Я добавил все свои домены prepro и pro в политику CORS в настройках корзины, и теперь это выглядит так:

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

ОБНОВЛЕНИЕ: добавьте http://localhost:PORTтоже

luigi7up
источник
1
Спасибо, что поделились этим решением. Это сработало для меня.
Райан Монтгомери
8

Что ж, в документации указано, что вы можете использовать конфигурацию как «подресурс cors в вашем сегменте». Я понял, что это означает, что я создам файл с именем «cors» в корне моей корзины с конфигурацией, но это не сработает. В конце концов мне пришлось войти в область администрирования Amazon S3 и добавить конфигурацию в propertiesдиалоговом окне моей корзины.

S3 мог бы использовать лучшую документацию ...

nzifnab
источник
1
Да, но мне посчастливилось заметить некоторые новые изменения интерфейса на панели свойств. Я редактировал политики корзины, поэтому, естественно, я ищу конфигурацию CORS на той же панели.
VKen 01
сработало для меня, я хотел установить это в своем приложении, кто знал, что это будет так просто
Richlewis
7

В конфигурации Amazon S3 CORS (S3 Bucket / Permissions / CORS), если вы используете это:

<?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 хорошо работает с файлами Javascript и CSS, но не работает с файлами шрифтов .

Вы должны указать домен, чтобы разрешить CORS использовать шаблон, выраженный в ответе @VKen: https://stackoverflow.com/a/25305915/618464

Итак, используйте это :

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

Не забудьте заменить «mydomain.com» на свой домен.

После этого сделайте недействительным кеш CloudFront (CloudFront / Invalidations / Create Invalidation), и он будет работать.

educoutinho
источник
6

В моем случае я не определил пространство имен и версию XML в конфигурации CORS. Определение тех, которые работали.

Изменено

<CORSConfiguration>

в

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
Гаурав Тошнивал
источник
У меня тоже работает. Мои шрифты размещены в самом ведре.
khamaileon
Я не понимаю, почему шаблон по умолчанию не включает это автоматически.
CoatedMoose
4

Есть способ лучше и проще!

Лично я предпочитаю использовать свои поддомены DNS для решения этой проблемы. Если мой CDN находится за cdn.myawesomeapp.com вместо sdf73n7ssa.cloudfront.net, тогда браузеры не будут волноваться и блокировать их как проблемы междоменной безопасности.

Чтобы указать свой субдомен на домен AWS Cloudfront, перейдите в панель управления AWS Cloudfront, выберите дистрибутив Cloudfront и введите свой субдомен CDN в поле Альтернативные доменные имена (CNAME). Что-то вроде cdn.myawesomeapp.com подойдет.

Теперь вы можете перейти к своему провайдеру DNS (например, AWS Route 53) и создать CNAME для cdn.myawesomeapp.com, указывающую на sdf73n7ssa.cloudfront.net.

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

msroot
источник
Это нарушает работу SSL или, скорее, использование SSL стоит больших денег, поэтому многие люди этого не делают.
maletor
4

Эта конфигурация сработала для меня. Я могу перечислять объекты, получать, обновлять и удалять.

<?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>
Шахид
источник
вам нужно сменить домен, так как я тестировал с локального хоста, просто посмотрите на эту страницу для CORS: docs.aws.amazon.com/AWSJavaScriptSDK/guide/…
Шахид
1
<ifModule mod_headers.c>

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

</ifModule>

Простое решение

О-MKAR
источник
Спасибо, что поделился! Подал мне идею просто добавить этот заголовок как «метаданные» при загрузке статических ресурсов в облачное хранилище. (Хотя в этом случае он будет работать только с 1 particular domainили all domains)
Vinay Vissh
0

Перезапуск моего весеннего загрузочного приложения (сервера) решил проблему для меня.

Я правильно настроил CORS на S3. Curl давал правильный ответ с заголовком origin. Safari правильно загружал шрифт. Только хром не захотел принять CORS.

Не уверен, что именно вызвало такое поведение. Должно быть какое-то отношение к If-modified-Since

Суджит Камтхе
источник
0

Это связано не со шрифтами, а с изображениями, это может быть крайний случай, но, как это случилось со мной, это может случиться с другим. Я оставлю это здесь, надеясь, что это кому-то поможет:

Если вы находитесь в сценарии «Я сделал все, что они сказали, но он все равно не работает», вероятно, это проблема, связанная с кешем в Chrome и Safari. Предположим, у вашего сервера есть правильный набор конфигурации CORS:

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

а в Firefox все работает нормально, а в Chrome и Safari - нет. Если вы обращаетесь к своему удаленному пути к изображению как из простого <img src="http://my.remote.server.com/images/cat.png">тега, так и из элемента src js Image, например, следующим образом:

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'

Вы можете получить No 'Access-Control-Allow-Origin'ошибку в Chrome и Safari. Это происходит потому, что первый <img>каким-то образом портит кеш браузера, и когда вы позже пытаетесь получить доступ к тому же изображению (в элементе изображения в коде), оно просто ломается. Чтобы избежать этого, вы можете добавить фиктивный параметр GET к одному пути .src, чтобы заставить браузер повторно запрашивать изображение и избегать использования кеша, например:

<img src="http://my.remote.server.com/images/cat.png?nocache=true"></img>
Никола Элиа
источник
-1

Ну конечно; естественно. Firefox поддерживает CORS для шрифтов, как того требует спецификация http://dev.w3.org/csswg/css3-fonts/#allowing-cross-origin-font-loading.

Борис Збарский
источник
Спасибо за оперативный ответ, Борис Збарский. Не могли бы вы показать несколько примеров конфигураций для настроек S3 CORS?
VKen 03
Я никогда не рассматривал настройку S3 ... Что касается того, что отправлять на уровне HTTP, если вы в порядке, просто отправьте «Access-Control-Allow-Origin: *» в HTTP-ответе для файлов шрифтов должно сработать.
Борис Збарский
Спасибо, я пытаюсь выяснить, как именно сделать эту настройку с конфигурациями S3 CORS.
VKen 06