Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Никакой сайт в современном вебе не обходится без формы авторизации, а под ней ты часто видишь кнопки входа через соцсети. Работают они благодаря протоколу OAuth, с устройством и основными уязвимостями которого я познакомлю тебя в этой статье. Для закрепления знаний пройдем несколько лабораторных работ.
Думаю, не нужно объяснять, что такое аутентификация на сайте. Если ты хочешь искать работу, оформлять заказы в интернете или пользоваться государственными услугами, тебя попросят подтвердить, что именно ты владелец аккаунта. И даже когда это не особенно нужно, разработчики все равно заставят тебя авторизоваться — просто чтобы было удобнее собирать о тебе данные. Но статья не об этичности, поэтому перейдем к самой теме.
Чтобы каждый раз не приходилось вбивать свою электронную почту, дожидаться прихода на нее сообщения с кодом или ссылкой для подтверждения аккаунта и придумывать сложный пароль, достаточно однажды зарегистрироваться на одном из мегапопулярных сайтов и входить под созданной учетной записью на остальных.
Такая технология есть, она давно известна и называется OAuth. Именно ее используют соцсети и прочие крупные сервисы, когда предлагают авторизоваться через них.
Страница входа в AliExpress
Этот метод входа стал настолько обыденным, что многие не задумываются о том, как он устроен, — а зря, ведь дьявол, как известно, кроется как раз в деталях. Мелочей здесь настолько много, что пришлось разделить гигантский материал по этой теме на три части.
В этой и следующих статьях мы пошагово разберем, как работают технологии OAuth и OpenID Connect, в чем отличия разных версий протоколов и какие риски несут эти технологии при неправильной реализации. Мы также обязательно пройдем лаборатории PortSwigger, чтобы научиться эксплуатировать уязвимости на практике.
Начнем с базовых атак на OAuth.
На неофициальном сайте Аарона Парецкого (Aaron Parecki), который собирает информацию об OAuth, приведено краткое, простое, емкое и довольно понятное определение:
Не надо вводить ничего лишнего: нажал кнопку, выдал согласие — и у приложения тут же оказались твои данные. В современном вебе OAuth поддерживает практически каждый крупный сайт, и действительно многие пользователи выбирают его вместо классических механизмов.
Сам протокол существует уже давно. Идея создания OAuth возникла во время разработки Twitter OpenID (не стоит путать с OpenID Connect), в ноябре 2007 года, когда компания создавала интеграцию с Ma.gnolia. Это канувший в Лету социальный сервис закладок, где люди могли делиться сохраненными ссылками на сайты.
Сайт Ma.gnolia
Целью интеграции Twitter и Ma.gnolia было дать возможность Ma.gnolia использовать виджеты информационной панели Twitter. Блейн Кук, на то время ведущий разработчик в Twitter, заметил, что открытого механизма, который делегировал бы доступ к API, просто не существует.
На тот момент уже были похожие решения, о которых ты, наверное, мог и не слышать: AuthSub (Google), BBAuth (Yahoo), OpenAuth (AOL), Windows Live ID Web Authentication (Microsoft) и Facebook Auth (Meta). Но они были проприетарными и потому не годились. Еще более древние методы вроде передачи паролей небезопасны и неудобны для таких сценариев. OAuth был предложен как решение этой проблемы.
Схема работы OAuth на условном примере
Вот как лаконично описывают OAuth разработчики Джон Панзер и Эран Хаммер‑Лахав, которые участвовали в создании открытой спецификации:
Финальный вариант реализации версии OAuth 1.0 был утвержден 4 декабря 2007 года (анонс можно найти в веб‑архиве), а уже в 2008 году этот протокол поддержал у себя Google, и аудитория протокола начала расти в геометрической прогрессии. К 2010 году Twitter заставил все сторонние приложения использовать свою реализацию OAuth 1.0.
Но за год до этого события, в 2009 году, была обнаружена атака с фиксацией сессии, позволявшая злоумышленникам получать доступ к чужим ресурсам. В результате этого аудита была разработана немного улучшенная версия протокола — OAuth 1.0a, в которой добавили параметры oauth_callback
и oauth_verifier
для защиты от таких атак.
Однако это не решило остальные проблемы OAuth 1.0 — небезопасность и неудобство использования. Разработчики жаловались, что первый OAuth требовал слишком больших криптографических вычислений на стороне клиента — запросы нужно было подписывать с помощью HMAC. Многим такая криптография срывала сроки разработки и серьезно усложняла тестирование.
За три года с момента зарождения первой версии протокола разработчики придумали более простое на уровне реализации, но более совершенное функционально решение, которое привносило много нововведений и которое стали называть OAuth 2.0. Этот протокол появился в 2010 году, а его последняя версия, в качестве RFC 6749, была опубликована в октябре 2012 года.
Чтобы было понятнее, давай использовать реальный пример. OAuth поддерживает несколько Flow, или «потоков», которые определяют, как именно происходит обмен информацией между клиентом, ресурсным сервером и сервером авторизации (с этими понятиями мы познакомимся немного позже), и самый используемый в современном вебе на десктопных сайтах — это Authorization Code Flow. С него и начнем.
Существует известный сайт legacy.midjourney.com, который позволяет создавать изображения с помощью генеративной нейросети.
Чтобы пользоваться его функциями и иметь возможность создавать картинки, надо войти в свой аккаунт, а модель авторизации построена как раз с помощью технологии OAuth.
В OAuth есть четыре сущности:
Схематично Authorization Code Flow в OAuth выглядит следующим образом.
Схематичное изображение Authorization Code Flow
Когда я описывал сервер авторизации и сервер ресурсов, ты мог заметить, что в нашем примере это в обоих случаях Discord. Здесь стоит отметить, что действительно в качестве этих серверов очень часто выступают одни и те же сервисы, но с разными эндпоинтами.
Это отлично показывает схема из документации Microsoft.
Альтернативная схема от Microsoft
Пугаться обилию информации не стоит, мы разберем каждый из пунктов по порядку.
Первый этап называется Authorization Request — запрос на авторизацию.
Сайт показывает поп‑ап с выбором социальной сети, через которую пользователь хочет войти.
Вход на сайт Midjourney
Мы выбираем Continue with Discord, приложение Midjourney генерирует ссылку на Discord и редиректит нас по ней. Там мы встречаем форму с просьбой войти в свой аккаунт.
Страница входа в Discord
При этом URL, по которому мы перешли, — это не сырая ссылка на вход, вроде /login
. Она особенна тем, что содержит множество параметров, которые были сгенерированы приложением, и выглядит следующим образом:
<https://discord.com/login>?redirect_to=/oauth2/authorize ?response_type=code &client_id=936929561302675456 &redirect_uri=https://www.midjourney.com/__/auth/handler &state=AMbdmDkycu0e3INVMzD9TaBJsUz4DqLki0MEElniTdiomtU7ejHQwa-zsdFLI3lv11Dlz0syNqa-sQ_fO9vwS_buX5sfKH_JjP1GJfgq8P0yzkAwTKOFRgZgp1Trz61FhuNd99rep6mYA_0NZniAmHeU31AHLer3ENc9UYhlPv3F0d10TtqAo3jrHFTDnzmWBoryBJbuP1dHH7fmo-UKkqedWNxmSNnOqOIE2erMiwibVnP3bhpWZKH-ka0UB6FesAGOGyaNKZG1KY92X8Rai5ceovEDCRId9vW2q_GLwVTixPua1vD1ChLxPi7QgIiRQCk &scope=identify email guilds.join guilds.members.read role_connections.write &context_uri=https://www.midjourney.com
Разберем каждый из параметров:
client_id
— случайное значение, которое генерирует Discord или любой другой сервер авторизации. Этот ID выдается сайту, в данном случае Midjourney. Для каждого из сервисов‑клиентов это значение уникально. Оно нужно для того, чтобы Discord понимал, что за приложение запрашивает данные его пользователя, то есть для идентификации; redirect_uri
— URI, на который Discord должен перенаправить пользователя после успешной авторизации. В данном случае он должен вернуть его обратно на сайт Midjourney. Несколько уязвимостей завязано на неправильной обработке этого параметра, их мы рассмотрим позже; state
— уникальное значение, которое генерируется на каждую сессию авторизации, чтобы защититься от CSRF-атак. В одной из лабораторий мы тоже научимся их эксплуатировать для кражи чужого аккаунта; response_type
— если OAuth — это протокол авторизации, то параметр response_type
говорит о том, какой флоу этого протокола будет использоваться: их несколько, и они немного отличаются друг от друга. Сейчас приложение подставляет сюда значение code
, но тут также может быть token
или id token
; scope
— это те данные или эндпоинты, на которые клиентское приложение Midjourney хочет получить у сервера ресурсов доступ. В данном случае параметры следующие:
identify
открывает приложению возможность обращаться к эндпоинту /users/@me
Discord, чтобы получить информацию о пользователе, но без email; email
— добавляет согласие на выдачу email. Предыдущий эндпоинт теперь будет возвращать и его тоже; guilds
— нужен, чтобы клиент мог обращаться к эндпоинту /users/@me/guilds
, который возвращает имя пользователя, его ID, баннер и другие параметры. Помимо identify
, email
и guids
, есть и другие атрибуты для параметра scope
, c ними можно ознакомиться в документации Discord.
После того как мы вошли, нас встречает экран‑уведомление, который называется Consent Screen. В нем говорится о том, что клиент Midjourney хочет получить доступ к данным о нас.
Страница Consent Screen в Discord
Источник: xakep.ru