Как работает механизм CORS в веб-приложениях?

Ответ

CORS (Cross-Origin Resource Sharing) — это механизм безопасности браузера, который позволяет веб-странице запрашивать ресурсы с другого домена, отличного от того, с которого была загружена сама страница. По умолчанию, браузеры блокируют такие запросы из-за политики Same-Origin Policy, если сервер явно не разрешил их.

Принцип работы:

  1. Простые запросы (GET, HEAD, POST с Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain): Браузер отправляет запрос напрямую, добавляя заголовок Origin. Сервер должен ответить с заголовком Access-Control-Allow-Origin.
  2. Сложные запросы (PUT, DELETE, запросы с кастомными заголовками или другими Content-Type): Браузер сначала отправляет предварительный запрос (preflight request) методом OPTIONS.
    • Этот OPTIONS запрос содержит заголовки Access-Control-Request-Method и Access-Control-Request-Headers, указывающие, какой метод и заголовки будут использоваться в реальном запросе.
    • Сервер должен ответить на OPTIONS запрос с соответствующими CORS-заголовками (Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers, Access-Control-Max-Age).
    • Если preflight запрос успешен, браузер отправляет основной запрос.

Ключевые заголовки ответа сервера:

  • Access-Control-Allow-Origin: Указывает, каким доменам разрешен доступ (например, * для всех или https://example.com).
  • Access-Control-Allow-Methods: Перечисляет разрешенные HTTP-методы (например, GET, POST, PUT, DELETE).
  • Access-Control-Allow-Headers: Перечисляет разрешенные HTTP-заголовки.
  • Access-Control-Max-Age: Время (в секундах), в течение которого результаты preflight запроса могут быть кэшированы.

Пример настройки CORS в Flask с flask-cors:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
# Разрешить CORS для всех маршрутов /api/* только с домена https://example.com
CORS(app, resources={r"/api/*": {"origins": "https://example.com"}})

@app.route("/api/data")
def get_data():
    return {"message": "Hello from API"}

if __name__ == "__main__":
    app.run(debug=True)

Важно: CORS — это механизм безопасности, реализуемый браузером. Сервер должен самостоятельно проверять Origin заголовок и проводить дополнительную авторизацию/аутентификацию, так как злоумышленник может подделать Origin при прямом запросе, минуя браузер.

Ответ 18+ 🔞

Слушай, а вот эта ваша CORS, блядь... Это ж такая песня, что в рот меня чих-пых! Представь: сидит браузер, такой бдительный пидорас шерстяной, и говорит: «Стой, сука! Куда полез?»

Вот есть у тебя сайт my-site.com. И он хочет стянуть данные с api.another-site.com. А браузер ему: «Ага, щас, блядь! Не, дружок, это другой домен, нахуй нельзя!» Это и есть та самая Same-Origin Policy — политика одного хуя, то есть источника. Без неё был бы пиздец, любой скрипт мог бы твои данные воровать.

Но иногда надо, сука, надо! Вот для этого и придумали CORS — Cross-Origin Resource Sharing. Механизм, чтобы сервер мог сказать браузеру: «Да, отпусти его, этот домен я знаю, пусть берет что хочет».

Как это, блядь, работает? Да не просто, ёпта!

  1. Простые запросы (типа GET или POST с простыми данными). Браузер просто добавляет в запрос заголовок Origin (типа «я с такого-то домена пришел») и шлет его. А сервер в ответ должен выдать заголовок Access-Control-Allow-Origin. Если там звездочка * или нужный домен — всё, проезд разрешен. Если нет — браузер тебе покажет ошибку и посланет нахуй.

  2. Сложные запросы (PUT, DELETE или с какими-нибудь хитрожопыми заголовками). Тут начинается цирк, блядь! Браузер, такой перестраховщик ебаный, сначала шлет предварительный запрос (preflight) методом OPTIONS. Типа: «Эй, сервак, а можно я вот так и так сделаю?»

    • В этом OPTIONS запросе он указывает, что хочет (Access-Control-Request-Method) и с какими заголовками (Access-Control-Request-Headers).
    • Сервер должен ответить на этот OPTIONS не просто «200 OK», а с кучей своих заголовков: что разрешает, кому разрешает и на сколько.
    • И только если этот предварительный танец с бубном прошел успешно, браузер шлет уже настоящий, основной запрос. А если нет — всё, приехали, в рот меня чих-пых!

Какие, блядь, заголовки сервер должен выдать?

  • Access-Control-Allow-Origin: Самый главный. Говорит, с каких доменов пускать. * — значит со всех, но это не всегда безопасно, ёпта.
  • Access-Control-Allow-Methods: Какие методы HTTP разрешены (GET, POST, PUT, DELETE...).
  • Access-Control-Allow-Headers: Какие кастомные заголовки можно слать.
  • Access-Control-Max-Age: Чтобы не слать этот ебучий OPTIONS перед каждым чихом, можно сказать браузеру: «Запомни ответ на столько-то секунд».

Вот тебе пример, как это в Python на Flask с flask-cors делается, чтоб ты не мучался:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
# Разрешаем CORS только для маршрутов /api/* и только с домена https://example.com
CORS(app, resources={r"/api/*": {"origins": "https://example.com"}})

@app.route("/api/data")
def get_data():
    return {"message": "Hello from API"}

if __name__ == "__main__":
    app.run(debug=True)

И главное, запомни, чувак: CORS — это защита в браузере, а не на сервере! Сервер всё равно получает твой запрос. Любой ебанат с curl может слать запросы откуда угодно, потому что он не браузер, ему похуй на CORS. Поэтому серверная сторона обязана делать свою проверку прав и авторизацию, а не надеяться на этот заголовок Origin. Иначе будет овердохуища проблем, блядь!