Миран — База знанийМиран — База знаний

CORS: зачем нужно, примеры настройки, частые ошибки

CORS (Cross-Origin Resource Sharing) — механизм браузера, который разрешает веб-странице обращаться к ресурсам на другом домене. Без корректной CORS-политики браузер блокирует такие запросы, даже если сам объект в S3 доступен по URL.

Для S3 это особенно важно, если фронтенд загружает изображения, видео, JSON, шрифты или отправляет файлы напрямую в бакет. В этом случае CORS должен быть разрешен именно на стороне бакета, а не только на фронтенде.

Когда CORS нужен

CORS нужен, если вы:

открываете файлы из S3 в браузере с другого домена;

загружаете файлы в S3 напрямую из веб-приложения;

используете fetch, XHR или upload через presigned URL;

подставляете S3-объекты в <img>, <scrypt>, <video> или в загрузку файлов с браузера.

Если доступ идет не из браузера, а с сервера, CORS обычно не нужен, потому что ограничение применяет именно браузер.

Какие бывают запросы

В контексте CORS обычно выделяют два типа запросов: simple request и preflight request. Для S3 это особенно важно, потому что именно от типа запроса зависит, будет ли браузер сначала делать OPTIONS.

Simple request

Это “простой” запрос, который браузер может отправить без предварительной проверки OPTIONS. В S3 это часто GET или HEAD для публичного чтения объекта, если не используются дополнительные заголовки и нестандартные условия.

В ответ сервер добавляет заголовок:

Access-Control-Allow-Origin: <домен | *>

Если в нём указан запрашивающий домен или символ *, браузер допускает обработку ответа.

Preflight request

Это предварительный запрос OPTIONS, который браузер отправляет перед основным запросом, если метод или заголовки могут потребовать отдельного разрешения. В S3 preflight часто возникает при PUT, POST, DELETE, при загрузке файлов, при работе с Authorization, Content-Type и x-amz-* заголовками.

Цель — убедиться, что сервер разрешает такие обращения. В ответе он указывает допустимые параметры, например:

Access-Control-Allow-Methods: GET, POST, PUT 

Access-Control-Allow-Headers: Content-Type  

Access-Control-Allow-Origin: https://example.com

Если условия совпадают, браузер выполняет основной запрос.

Actual request

Это основной запрос, который идет после успешного preflight. Например, PUT для загрузки файла, GET для чтения объекта или POST для отправки формы/данных в бакет.

Пример конфигурации

Ниже базовый пример CORS для бакета S3, который разрешает доступ с одного домена и поддерживает чтение, загрузку и preflight-запросы:

{
  "CORSRules": [
    {
      "AllowedOrigins": ["https://example.com"],
      "AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
      "AllowedHeaders": ["*"],
      "ExposeHeaders": ["ETag"],
      "MaxAgeSeconds": 3600
    }
  ]
}

Если пользователь открывает страницу на https://example.com и браузер пытается загрузить файл из S3, S3 сравнивает origin страницы с AllowedOrigins. Если фронтенд делает загрузку файла методом PUT, этот метод тоже должен быть в AllowedMethods.

Если приложение работает только на чтение, достаточно GET и HEAD. Если браузер должен загружать файлы, обычно добавляют PUT и/или POST.

Настройка S3 хранилища Миран

Для S3-хранилища miran.ru CORS обычно настраивается не в панели, а через S3 API или AWS CLI, если провайдер не добавил отдельный интерфейс. Стандартный путь — команда put-bucket-cors с JSON-файлом конфигурации.

Пример настройки через aws s3api

Создайте файл cors.json (например, в текущей директории)

{
  "CORSRules": [
    {
      "AllowedOrigins": ["https://example.com"],
      "AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
      "AllowedHeaders": ["*"],
      "ExposeHeaders": ["ETag"],
      "MaxAgeSeconds": 3600
    }
  ]
}

Если нужно разрешить все домены (только для теста, не для продакшена):

"AllowedOrigins": ["*"]

Установка CORS-правил

aws s3api put-bucket-cors \
  --bucket test \
  --endpoint-url https://s3.cloud.miran.ru \
  --cors-configuration file://cors.json

После применения можно проверить конфигурацию командой get-bucket-cors. Просмотр текущих правил

aws s3api get-bucket-cors \
  --bucket test \
  --endpoint-url https://s3.cloud.miran.ru

При необходимости удаление CORS-правил

aws s3api delete-bucket-cors \
  --bucket test \
  --endpoint-url https://s3.cloud.miran.ru

Пример настройки через s3cmd

s3cmd для S3‑совместимых хранилищ работает через XML‑конфиг CORS, а не JSON.

Создайте файл cors.xml

<CORSConfiguration>
  <CORSRule>
    <ID>AllowFromMyDomain</ID>
    <AllowedOrigin>https://example.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
    <MaxAgeSeconds>3600</MaxAgeSeconds>
  </CORSRule>
</CORSConfiguration>

Если нужно разрешить все домены (только для теста, не для продакшена):

<AllowedOrigin>*</AllowedOrigin>

Установка CORS для бакета test

s3cmd setcors cors.xml s3://test

Проверка CORS

s3cmd info s3://test

Пример вывода

s3://test/ (bucket):
   Location:  ru-spb
   Payer:     BucketOwner
   Ownership: none
   Versioning:Enabled
   Expiration rule: none
   Block Public Access: none
   Policy:    none
   CORS:     
   <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
     <CORSRule>
      <ID>rules from CLI</ID>
      <AllowedMethod>GET</AllowedMethod>
      <AllowedMethod>PUT</AllowedMethod>
      <AllowedMethod>DELETE</AllowedMethod>
      <AllowedMethod>HEAD</AllowedMethod>
      <AllowedMethod>POST</AllowedMethod>
      <AllowedOrigin>https://example.com</AllowedOrigin>
      <AllowedHeader>*</AllowedHeader>
      <MaxAgeSeconds>6000</MaxAgeSeconds>
     </CORSRule>
   </CORSConfiguration>
   ACL:       *anon*: WRITE
   ACL:       S3 #232151: FULL_CONTROL

Проверка и отладка

Если браузер продолжает блокировать запрос, проверьте три вещи: совпадает ли Origin, разрешен ли нужный HTTP-метод и не забыты ли заголовки, которые отправляет браузер. Частая причина ошибки — лишний слэш в AllowedOrigins или использование * там, где нужен конкретный домен.

Для проверки preflight-запроса можно открыть DevTools в браузере и посмотреть OPTIONS-ответ. Если он не содержит Access-Control-Allow-OriginAccess-Control-Allow-Methods или Access-Control-Allow-Headers, браузер заблокирует запрос.

Типичные ошибки

Указан не тот origin, например http:// вместо https:// или домен с лишним слэшем.

В CORS разрешен только GET, а фронтенд делает PUT или POST.

Не разрешен заголовок Content-Type, Authorization или x-amz-*.

Конфигурация применена к неправильному бакету.

Используется неверный endpoint S3, из-за чего CLI получает неожиданный ответ или SSL-ошибку.

Часто задаваемые вопросы

Можно ли поставить AllowedOrigins: ["*"]?
Да, но только для тестов или публичных ресурсов. Для продакшена безопаснее указать конкретные домены.

Нужно ли менять CORS для каждого объекта отдельно?
Нет, CORS настраивается на уровне бакета, а не отдельного файла.

Почему браузер блокирует запрос, хотя файл доступен по ссылке?
Потому что доступность по URL и разрешение cross-origin-запросов — это разные механизмы. Файл может открываться напрямую, но быть запрещен для чтения из JavaScript.

Похожие статьи

Версионирование в S3 хранилище
Описание