Получение 403 (Запрещено) при загрузке файла AWS CloudFront

Я работаю над видеоприложением и сохраняю файлы на AWS S3, используя URL-адрес по умолчанию, такой как https://***.amazonaws.com/*** отлично работает, но я решил использовать CloudFront, который быстрее для доставки контента.

Используя CF, я продолжаю получать 403 (Forbidden) с помощью этого URL https://***.cloudfront.net/***. Я что-то пропустил?

Все работает нормально, пока я не решит загрузить содержимое из CloudFront, которое указывает на мое ведро.

Любое решение, пожалуйста?

Ответ 1

При ограничении доступа к содержимому S3 с использованием политики ведра, которая проверяет входящий заголовок Referer:, вам нужно немного настроить пользовательскую конфигурацию для "перехитрить" CloudFront.

Важно понимать, что CloudFront предназначен для хранения кэша. "Хорошо себя", я имею в виду, что CloudFront предназначен для того, чтобы никогда не возвращать ответ, который отличается от возвращаемого сервера происхождения. Я уверен, что вы видите, что это важный фактор.

Скажем, у меня есть веб-сервер (а не S3) за CloudFront, и мой веб-сайт разработан таким образом, что он возвращает другой контент на основе проверки заголовка Referer:... или любого другого заголовка HTTP-запроса, например User-Agent: например. В зависимости от вашего браузера я могу вернуть другой контент. Как CloudFront узнает об этом, чтобы избежать обслуживания неправильной версии определенной страницы?

Ответ: он не сможет сказать - он не может этого знать. Таким образом, решение CloudFront не пересылает большинство заголовков запросов на мой сервер вообще. То, что мой веб-сервер не видит, на него нельзя реагировать, поэтому возвращаемый контент не может меняться в зависимости от заголовков, которые я не получаю, что предотвращает кеширование CloudFront и возвращает неправильный ответ на основе этих заголовков. Веб-кеши должны не возвращать неверный кешированный контент для данной страницы.

"Но подождите", вы возражаете. "Мой сайт зависит от значения из определенного заголовка, чтобы определить, как реагировать". Правильно, это имеет смысл... поэтому мы должны сказать CloudFront:

Вместо того, чтобы кэшировать мои страницы на основе только запрошенного пути, вам нужно также переслать Referer: или User-Agent: или один из нескольких других заголовков, отправленных браузером, и кешировать ответ для использования на других запросах, которые включают не только один и тот же путь, но и те же значения для дополнительных заголовков, которые вы пересылаете мне.

Однако, когда исходным сервером является S3, CloudFront не поддерживает пересылку большинства заголовков запросов, исходя из предположения, что, поскольку статический контент вряд ли изменится, эти заголовки просто заставляют его кэшировать несколько идентичных ответов без необходимости.

Ваше решение не означает CloudFront, что вы используете S3 в качестве источника. Вместо этого настройте свой дистрибутив для использования "настраиваемого" источника и укажите ему имя хоста для использования в качестве имени хоста исходного сервера.

Затем вы можете настроить CloudFront для пересылки заголовка Referer: в начало координат, и ваша политика веток S3, которая отрицает/разрешает запросы на основе этого заголовка, будет работать, как ожидалось.

Ну, почти как ожидалось. Это несколько снизит коэффициент попадания в кеш, так как теперь кешированные страницы будут кэшироваться на основе ссылки на путь + ссылку. На объект S3 ссылаются более чем на одну из страниц вашего сайта, CloudFront кэширует копию для каждого уникального запроса. Это похоже на ограничение, но на самом деле это только артефакт правильного поведения кеша - все, что передается в фоновый код, почти все это, должно использоваться для определения того, можно ли использовать этот конкретный ответ для обслуживания будущих запросов.

См. http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesForwardHeaders для настройки CloudFront для белого списка конкретных заголовков для отправки на исходный сервер.

Важно: не пересылайте какие-либо заголовки, которые вам не нужны, так как каждый вариант запроса снижает ваш рейтинг. В частности, при использовании S3 в качестве исходного кода для пользовательского источника не пересылайте заголовок Host:, потому что это, вероятно, не будет делать то, что вы ожидаете. Выберите здесь Referer: и проверьте. S3 должен начать видеть заголовок и соответственно реагировать.

Обратите внимание, что когда вы удалили свою политику ведра для тестирования, CloudFront продолжал бы обслуживать страницу кэшированных ошибок, если вы не сбросили свой кеш, отправив запрос аннулирования, что заставляет CloudFront очищать все кэшированные страницы, соответствующие указанному шаблону пути, в течение примерно 15 минут. Самое простое в эксперименте - просто создать новый дистрибутив CloudFront с новой конфигурацией, поскольку для самих дистрибутивов нет никакой платы.

При просмотре заголовков ответов от CloudFront обратите внимание на теги X-Cache: (hit/miss) и Age: (как давно эта страница была кэширована). Они также полезны при устранении неполадок.


Обновление: @alexjsсделал важное замечание: вместо этого с использованием политики ведра и пересылки заголовка Referer: на S3 для анализа - что может повредить ваш коэффициент кэша в той мере, которая зависит от распространения ресурсов по ссылкам на страницы - вы можете используйте новую службу брандмауэра веб-приложений AWS, которая позволяет вам навязывать правилам фильтрации от входящих запросов к CloudFront, разрешать или блокировать запросы на основе соответствия строк в заголовках запросов.

Для этого вам нужно будет подключить дистрибутив к S3 как начало S3 (нормальная конфигурация, вопреки тому, что я предложил, в вышеприведенном решении с "обычным" происхождением) и использовать встроенную функцию CloudFront для аутентификации обратных запросов к S3 (поэтому содержимое ведра напрямую не доступно, если запрашивается у S3 напрямую злоумышленником).

Подробнее об этой опции см. https://www.alexjs.eu/preventing-hotlinking-using-cloudfront-waf-and-referer-checking/.

Ответ 2

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

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

Файлы в этой папке (и любых подпапках) будут опубликованы, и вы сможете обслуживать файлы с S3.

Для CLI AWS добавьте в свою команду параметр "-acl public-read", например:

aws s3 cp index.html s3://your.remote.bucket --acl public-read

Ответ 3

Для меня я дал CodePipeline доступ к S3, который переписал мою политику корзины s3. Например что-то вроде этого:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::mys3bucket/*"
        }
    ]
}

Ответ 4

Я обнаружил еще одну причину, по которой CloudFront может вернуть 403 (Bad request). Может быть, это крайний случай, но я хотел бы поделиться с вами.

CloudFront реализует механизм обнаружения прямого цикла, чтобы предотвратить атаки прямого цикла.
Вы не можете каскадировать более двух дистрибутивов CloudFront как организации в соответствии с поддержкой AWS.

Предположим, вы настроили CloudFront A с CloudFront B в качестве источника, а из CloudFront B вы настроили CloudFront C в качестве источника, а в CloudFront C у вас есть корзина S3 в качестве источника.

A --> B --> C --> S3 bucket (can return a 403 error)

Если вы запрашиваете файл из CloudFront A, который находится в сегменте S3 в конце каскада, CloudFront C вернет 403 (неверный запрос).

Если ваш каскад состоит только из двух дистрибутивов CloudFront и блока S3 в конце, запрос файла из источника S3 работает.

A --> B --> S3 bucket (works)