Прерывистые ошибки 403 CORS (Access-Control-Allow-Origin) с Cloudfront с использованием подписанных URL-адресов для получения объектов S3 - PullRequest
0 голосов
/ 10 февраля 2019

Вкратце

Чтобы сохранить загруженные носители (объекты S3) частными для всех клиентов в моей мультитенантной системе, я реализовал развертывание CloudND CDN и настроил его (и его исходную корзину S3) дляпринудительное использование подписанных URL-адресов для получения любого из объектов.


Метод

Сначала пользователь проходит проверку подлинности через мою систему, а затем генерируется подписанный URL-адрес и возвращается к ним с помощью AWS.CloudFront.Signer.getSignedUrl() метод предоставлен AWS JS SDK .чтобы они могли сделать запрос к CF / S3 для загрузки объекта (изображение, PDF, docx и т. д.).Довольно стандартные вещи.


Проблема

Вышеуказанный метод работает в 95% случаев.Пользователь получает подписанный URL-адрес из моей системы, а затем, когда он делает XHR, чтобы ПОЛУЧИТЬ объект, который он извлекает, просто отлично.

Но в 5% случаев выдается 403 с ошибкой CORS о том, что клиентorigin is not allowed by Access-Control-Allow-Origin.

The error, from Safari in this case.

Эта ошибка (ошибка) была подтверждена во всех средах: localhost, dev.myapp.com, prod.myapp.ком.И на всех платформах / браузерах.

Существует так мало рифмы или причины, по которой я начинаю думать, что это ошибка AWS (они случаются время от времени).


Контрольный список отладки до сих пор

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

Вы пробовали другой браузер / платформу?

Да.Эта проблема присутствует во всех клиентских версиях, браузерах (и версиях) и на всех платформах.

Правильно ли настроен ваш S3 Bucket для CORS?

Да.Это широко открыто на самом деле.Я даже установил <MaxAgeSeconds>0</MaxAgeSeconds>, чтобы предотвратить кэширование любых предварительных запросов OPTIONS клиента:

CORS settings

Срок действия подписанного URL-адреса истек?

Нет.Срок действия всех подписанных URL истекает через 24 часа после генерации.Эта проблема обнаруживается даже через несколько секунд после создания любого подписанного URL-адреса.

Есть ли проблема с методом, используемым для создания подписанных URL-адресов?

Маловероятно.Я просто использую метод AWS.CloudFront.Signer.getSignedUrl() их JS SDK.Подписанные URL-адреса do работают большую часть времени, поэтому может показаться очень странным, что это будет проблемой в процессе подписания.Кроме того, эта ошибка явно является ошибкой CORS, а не ошибкой совпадения подписи.

Это проблема часового пояса / часов сервера?

Нет.Система действительно обслуживает пользователей во многих часовых поясах, но эта теория оказалась ложной, учитывая, что все подписанные URL-адреса генерируются на стороне сервера.Часовой пояс клиента не имеет значения, он получает подписанный URL-адрес в течение 24 часов с момента генерации, независимо от того, в каком TZ он находится.

Настроен ли ваш дистрибутив CFправильно?

Да, насколько я могу разобрать, следуя нескольким руководствам AWS , учебникам , документам и прочим .

Вот скриншот для краткости.Вы можете видеть, что я полностью отключил кеширование, пытаясь исключить это как причину:

CF distro config

Вы видите эту ошибку для всех типов пантомимы?

Нет.Эта ошибка не была обнаружена ни для каких изображений, аудио или видео файлов (объектов).После большого количества уже выполненных испытаний эта ошибка появляется только при попытке получить документ или файл PDF (.doc, .docx, .pdf).Это привело меня к мысли, что это просто ошибка несоответствия заголовка Accept: клиент отправлял XHR с заголовком Accept: pdf, но на самом деле подпись была сгенерирована для Accept: application/pdf.Я еще не смог полностью исключить это какпричина.Но это маловероятно, учитывая, что ошибки периодически.Таким образом, если бы это была проблема несоответствия заголовка Accept, то это должно быть ошибкой каждый раз.

Кроме того, XHR отправляет Accept: */*, поэтому весьма маловероятно, что именно в этом проблема.



Вопрос

Я действительно ударил стену по этому.Кто-нибудь может увидеть, что мне здесь не хватает?Лучшее, что я могу придумать, это то, что это какая-то проблема с выбором времени.Что за проблема с синхронизацией, или если это вообще проблема с синхронизацией, я еще не выяснил.

Заранее благодарен за любую помощь.

1 Ответ

0 голосов
/ 24 июля 2019

Нашли решение для того же самого на сервере.

https://serverfault.com/questions/856904/chrome-s3-cloudfront-no-access-control-allow-origin-header-on-initial-xhr-req

Вы, очевидно, не можете успешно извлечь объект из HTML, а затем успешно извлечь его снова с запросом CORSс Chrome и S3 (с или без CloudFront), из-за особенностей реализации.

Добавление ответа из исходного поста, чтобы он не терялся.

Обходной путь:

Это поведение можно обойти с помощью CloudFront и Lambda @ Edge, используя следующий код в качестве триггера ответа источника.

Это добавляет Vary: Access-Control-RequestЗаголовки, Access-Control-Request-Method, Origin к любому ответу от S3, который не имеет Vary заголовка.В противном случае заголовок Vary в ответе не изменяется.

'use strict';

// If the response lacks a Vary: header, fix it in a CloudFront Origin Response trigger.

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;

    if (!headers['vary'])
    {
        headers['vary'] = [
            { key: 'Vary', value: 'Access-Control-Request-Headers' },
            { key: 'Vary', value: 'Access-Control-Request-Method' },
            { key: 'Vary', value: 'Origin' },
        ];
    }
    callback(null, response);
};
...