Вот вопрос от коллеги, который я получаю довольно часто:

Учитывая, что запросы curl не имеют ограничений API выборки, как эта политика браузера [CORS] предотвращает обход злоупотреблений или неправильного использования конечных точек сервера, если злоумышленник в любом случае может сделать это по умолчанию через curl? И поскольку злоумышленник может использовать curl, какова в первую очередь реальная эффективность политики браузера?

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

Этот вопрос сводится к тому, почему существует CORS. Часто ошибочно понимается, что CORS - это способ предотвратить получение информации друг от друга разными веб-сайтами, но это как раз наоборот. Давайте сначала поговорим о мире без CORS.

До появления CORS, как могли помнить некоторые читатели, Javascript не мог (с оговорками) получать данные, такие как JSON, из другого веб-источника в браузере. Это ограничение называется компонентом «политики одного и того же происхождения» в «концепции веб-происхождения» и во многом лежит в основе безопасности просмотра веб-страниц.

Если я создам веб-сайт, mywebsite.com, он сможет использовать Javascript для запроса информации только mywebsite.com. Если бы это было не так, я бы просто попросил Javascript извлечь google.com/account, прочитать вашу личную информацию из результата и отправить ее мне. Поскольку Javascript выполняет запрос как вы с вашим файлом cookie, из вашего браузера, он получает доступ ко всему, что вы делаете, но контролирует автор сайта. Обратите внимание, что это ограничение только применяется к запросам Javascript. Я могу вставлять изображения и скрипты с других сайтов, сколько захочу.

В результате, до CORS, если я хотел написать веб-сайт, который извлекал бы данные из другого, например Google API, мне приходилось делать это через свой собственный внутренний сервер. Взгляните на этот поток:

Здесь моя веб-страница http://mywebsite.com/index.html запрашивает две вещи: (1) данные моей учетной записи от mywebsite.com/me.json и (2) широту и долготу Лондона через api.google.com/lookup. Однако политика одинакового происхождения не позволяет нам напрямую запрашивать Google, поэтому мы настраиваем наш сервер так, чтобы он отправлял запрос за нас.

CORS представил набор заголовков, которые начинаются с Acess-Control-, которые позволяют серверу утверждать, что разрешить Javascript извлекать информацию безопасно. Например, Access-Control-Allow-Origin: mywebsite.com позволяет Javascript на mywebsite.com получить доступ к ответу на этот запрос.

Так почему же злоумышленники не игнорируют заголовок Access-Control-Allow-Origin? Потому что это им ничего не дает. Если я формирую HTTP-запрос с помощью CuRL, вся информация, которую я отправляю на сервер, уже известна мне, и все, к чему я получаю доступ, у меня уже был доступ. На самом деле злоумышленник хочет, чтобы браузер жертвы предоставил часть имеющейся информации о жертве.

Частично по устаревшим причинам запросы в браузерах имеют определенные внешние привилегии («внешние полномочия»). Мой веб-сайт в браузере будет отправлять запрос с IP-адреса пользователя, возможно, с его собственным сеансом входа в систему. CORS выполняет навигацию, предоставляя доступ к определенным ресурсам, которые заявили, что они осведомлены о том, что это может повлечь за собой, через Access-Control-Allow-Origin и предотвращает небезопасность старых приложений, использующих устаревшее поведение.

Почему бы нам просто не разрешить чему-либо запрашивать что-либо еще и заблокировать файлы cookie?

Это может звучать до некоторой степени как анархия, но нельзя ли просто заблокировать файлы cookie для запросов CORS и позволить кому-либо загружать кого-нибудь еще? В этот момент я не смогу получить информацию о чьей-либо учетной записи, верно?

Это совсем не плохая идея. Фактически, это часть CORS. Access-Control-Allow-Origin: * делает именно это: он позволяет любому веб-сайту загружать ваш ресурс, но предотвращает отправку файлов cookie. Однако его еще предстоит выбрать. Мир Access-Control-Allow-Origin: *, возможно, значительно более безопасен, потому что он почти полностью устраняет всю категорию уязвимостей CSRF.

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

Это неверное предположение из-за CSRF - все еще можно указать браузеру загрузить ресурс с помощью HTML-тега, такого как <img src=your.router/logout/>, и он все равно выполнит и выйдет из системы текущего пользователя, но получить ответ невозможно. Если бы можно было получить ответ, было бы значительно хуже.

CORS также предоставляет функции Javascript браузера для установки заголовков запросов через Access-Control-Allow-Headers в аналогичном ключе: существует множество заголовков, которые Javascript не может контролировать и которые важны для веб-безопасности - Origin, вероятно, являются наиболее опасными, но есть также Cookie, Host и все виды.

Я надеюсь, что эта статья поможет пролить свет на то, почему существует CORS и как он вписывается в безопасность браузера. Преимущества безопасности CORS не присущи самому протоколу CORS - в конце концов, как уже отмечалось, вы можете полностью избежать этого, - но альтернативы, которых он избегает.

И последнее, что я хотел бы сказать, это то, что CORS часто рассматривается как сложный протокол, требующий серверной части, и это делает его огромной проблемой для многих людей, обслуживающих определенные виды активов. Многие реализации CORS используют запрашивающий заголовок Origin, чтобы определить, следует ли разрешить запрос, и возвращают то же происхождение, если это так.

По большей части CORS полностью статичен, и можно просто отправить Access-Control-Allow-Origin: myorigin или Access-Control-Allow-Origin: * в ответ на любой запрос. В более ранних черновиках Access-Control-Allow-Origin это было более очевидным, поскольку заголовок мог включать сразу несколько источников, а Access-Control-Max-Age на какое-то время упрощал кэширование статической политики CORS.

Я не совсем понимаю, почему Access-Control-Allow-Origin сейчас не разрешает список источников происхождения из белого списка. Какое-то время Firefox допускал этот шаблон. Я предполагаю, что ранние реализации CORS допускали только одно происхождение, и этот шаблон застрял. Заголовки политики безопасности контента используют этот шаблон для своей функции-убийцы allow-src и ее преемника X-Frame-Options, в том числе директивы frame-ancestors.

Томас