• безопасность
  • oauth
  • PKCE

Краткое введение в безопасность OAuth

Насколько хорошо вы знакомы с защитными мерами, используемыми OAuth? Соответствует ли ваша система открытому стандарту OAuth? Вы ли учитываете потенциальные риски, которые могут возникнуть при реализации потока аутентификации пользователя? Давайте кратко повторим то, что мы узнали о OAuth.

Simeng
Simeng
Developer

Введение

Несколько дней назад нас поразила статья о интересной уязвимости OAuth. A-new-oauth-vulnerability-that-may-impact-hundreds-of-online-services от SALT lab. В этой конкретной публикации подчеркивается обнаруженная уязвимость в Expo, широко используемом фреймворке для реализации OAuth и других функций. Она конкретно адресована уязвимости в библиотеке expo-auth-session, которая была определена и должнообразом решена.

Если вам интересно OAuth или вы работаете над продуктом, связанным с CIAM, как мы, мы настоятельно рекомендуем прочитать эту статью. Она довольно вдохновляющая и предоставляет полезные инсайты. Эти отчеты белых хакеров служат напоминанием о том, как даже самый простой элемент может вызвать уязвимости. Когда речь идет о кибербезопасности и авторизации, мы не можем быть слишком осторожны, обеспечивая безопасность и конфиденциальность информации пользователя. Если эта статья привлекла ваше внимание, я уверен, что вы с нами согласитесь.

Это напоминает мне время, когда мы только начинали. Мы потратили много времени на изучение и исследование деталей протоколов OAuth и OIDC. Это было мучительно и утомительно, но выгоды были огромны. Хотя возможно, не каждый член нашей команды является экспертом по OAuth, каждый прилагает непрерывные усилия для обеспечения безопасности и тщательности. Благодаря этим усилиям, продукт Logto превратился в то, что он есть сегодня.

Благодаря этой замечательной возможности, мы хотели бы освежить в памяти некоторые детали безопасности OAuth здесь.

Краткий обзор потока авторизации OAuth

OAuth 2.0 предоставляет различные потоки авторизации, соответствующие различным типам клиентов и требованиям. К ним относятся Implicit Flow, Client Credentials Flow, Resource Owner Password Credentials Flow, и Device Authorization Flow. Однако поток авторизации кода выделяется как наиболее безопасный и широко используемый. В отличие от других потоков, он разделяет аутентификацию пользователя от клиентского приложения и включает обмен авторизационного кода на токены. Этот подход обеспечивает дополнительный уровень безопасности, так как чувствительные токены никогда не доступны клиенту. Кроме того, поток авторизации кода поддерживает управление токенами на стороне сервера, что делает его подходящим для веб-приложений, требующих надежной безопасности и расширенного контроля над доступом пользователей.

Здесь представлена простейшая диаграмма Authorization Code Flow:

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

Точка конца авторизации:

Точка конца обмена токенами:

Учетные данные клиента

В OAuth, Client Credentials - это учетные данные, используемые клиентским приложением для аутентификации и идентификации себя перед сервером авторизации. Эти учетные данные получаются в процессе регистрации клиента и используются для проверки идентичности клиента при отправке запросов на сервер авторизации. (Вы можете найти учетные данные вашего клиента в консоли администратора Logto, когда вы в первый раз регистрируете свое приложение.)

Учетные данные клиента обычно состоят из двух компонентов:

  1. Client ID: уникальный идентификатор, присваиваемый клиентскому приложению сервером авторизации. Это открытое значение, которое в общем случае не считается чувствительным.
  2. Client Secret: конфиденциальное и надежно хранящееся значение, известное только клиенту и серверу авторизации. Он служит формой аутентификации для клиентского приложения и используется для проверки идентичности клиента при отправке запросов на сервер авторизации.

Как вы можете заметить, комбинация Client ID и Client Secret используется в запросе токена для аутентификации клиента и получения токенов доступа.

Учетные данные клиента играют важную роль в обеспечении безопасности потока OAuth. Они помогают серверу авторизации проверить подлинность клиентских приложений и контролировать доступ к защищенным ресурсам. Важно обрабатывать учетные данные клиента безопасно и защищать их от несанкционированного доступа. Logto категоризирует приложения клиентов по двум различным уровням безопасности:

  • Конфиденциальные клиенты: к ним относятся веб-приложения, отображаемые на сервере, и приложения машина-машина (M2M). В случае конфиденциальных клиентов все учетные данные, связанные с авторизацией, включая учетные данные клиента, хранятся на сервере. Кроме того, все промежуточные запросы обмена зашифрованы, чтобы обеспечить конфиденциальность данных. Риск утечки учетных данных клиента для конфиденциальных клиентов очень низкий, что делает их внатуре более безопасными. Поэтому конфиденциальные клиенты по умолчанию рассматриваются на более высоком уровне безопасности. В потоке обмена токенами, представление Client Secret является ОБЯЗАТЕЛЬНЫМ.
  • Публичные клиенты: к ним относятся одностраничные веб-приложения (SPA) и нативные приложения. Для публичных клиентов учетные данные клиента обычно жестко кодируются на стороне клиента, например, в пакете JavaScript или в пакете приложения на нативной платформе. Риск утечки учетных данных выше, чем у конфиденциальных клиентов, из-за внутренней подверженности учетных данных клиента в коде на стороне клиента. В потоке обмена токенами, представление Client Secret является НЕОБЯЗАТЕЛЬНЫМ. Logto по умолчанию не будет доверять этим учетным данным от публичного клиента.

Состояние

В потоке OAuth, параметр state - это случайно сгенерированное значение, которое включается в запрос на авторизацию, отправленный клиентом серверу авторизации. Его цель - сохранить состояние или контекст запроса клиента на протяжении процесса авторизации.

Параметр state действует как мера безопасности для предотвращения атак cross-site request forgery (CSRF). Когда сервер авторизации перенаправляет пользователя обратно в клиентское приложение после аутентификации и авторизации, он включает в ответ то же значение state. Клиентское приложение ДОЛЖНО сравнить это значение с исходным значением state, которое оно отправило в запросе на авторизацию.

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

Рассмотрим следующий пример атаки CSRF в вымышленном сценарии использования:

Атака CSRF: мошенничество с привязкой социального аккаунта - проблема

С помощью правильного механизма проверки состояния, клиент может обнаружить атаку и предотвратить переадресацию пользователя на сайт злоумышленника:

Атака CSRF: мошенничество с привязкой социального аккаунта - решение

PKCE

Как уже упоминалось ранее, публичные клиенты, такие как веб-приложения SPA и нативные приложения, несут более высокий риск утечки учетных данных авторизации, включая код авторизации, выданный сервером авторизации.

PKCE расшифровывается как Proof Key for Code Exchange. Это расширение OAuth 2.0 Authorization Code Flow, улучшающее безопасность публичных клиентов.

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

Для реализации PKCE клиентское приложение генерирует случайный верификатор кода и получает из него вызов кода с использованием конкретного алгоритма хэширования (обычно SHA-256). Код вызова включается в исходный запрос на авторизацию, отправляемый серверу авторизации.

Когда сервер авторизации выдает код авторизации, клиентское приложение включает оригинальный верификатор кода в запрос на токен. Сервер проверяет, соответствует ли верификатор кода сохраненному вызову кода, и только тогда выдает токен доступа.

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

Logto использует PKCE как ЕДИНСТВЕННЫЙ поток авторизации для всех приложений типа публичный клиент. Однако PKCE может быть опущен для тех конфиденциальных клиентов.

Redirect URI

A Redirect URI(Uniform Resource Identifier) - это конкретная конечная точка или URL, на который сервер авторизации перенаправляет пользователя после процесса аутентификации и авторизации в OAuth.

Во время потока OAuth, клиентское приложение включает Redirect URI в часть исходного запроса на авторизацию. Этот URI служит URL обратного вызова, куда будет перенаправлен пользователь после успешной аутентификации и предоставления разрешений клиенту.

Как только пользователь завершает процесс аутентификации, сервер авторизации формирует ответ, который включает код авторизации, и перенаправляет пользователя обратно на указанный Redirect URI.

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

Давайте вернемся и посмотрим на оригинальный отчет об уязвимости OAuth. (Следующий раздел приведен из оригинального поста)

Когда пользователь нажимает «войти через Facebook» с помощью мобильного приложения Expo Go, он перенаправляет пользователя по следующей ссылке:

https://auth.expo.io/@moreisless3/me321/start?authUrl=https://www.facebook.com/v6.0/dialog/oauth?code_challenge=...&display=popup&auth_nonce=...&code_challenge_method=S256&redirect_uri=https://auth.expo.io/@moreisless3/me321&client_id=3287341734837076&response_type=code,token&state=gBpzi0quEg&scope=public_profile,email&returnUrl=exp://192.168.14.41:19000/--/expo-auth-session

В ответе auth.expo.io установил следующий файл cookie: ru=exp://192.168.14.41:19000/--/expo-auth-session. Значение RU будет впоследствии использоваться как Return Url на шаге 5. Затем он показывает пользователю сообщение подтверждения, и если пользователь одобряет - перенаправляет его на вход в Facebook для продолжения процесса аутентификации

Эта страница читает параметр запроса «returnUrl» и соответствующим образом устанавливает файл cookie.

Давайте изменить returnUrl на hTTps://attacker.com (https не дозволен, поэтому я попытался поместить заглавные буквы, и это сработало), что устанавливает RU (Return Url) в cookie как https://attacker.com.

В вышеуказанном случае, несмотря на оригинальные параметры redirect_uri, Expo ввел новый параметр под названием returnUrl без надлежащей проверки. Это недосмотр предоставил возможность злоумышленникам получить доступ к коду авторизации, возвращенному Facebook. Для более подробной информации обратитесь к оригинальной публикации.

Проверка Redirect URI служит для решения нескольких важных задач:

  1. Предотвращение фишинговых атак: проверка Redirect URI помогает серверу авторизации убедиться, что пользователь перенаправляется обратно на доверенную и разрешенную конечную точку. Это помогает предотвратить перенаправление пользователей злоумышленниками на вредоносные или несанкционированные места.
  2. Защита от открыто перенаправляемых URL: открытые перенаправления - это уязвимости, которые могут быть использованы для перенаправления пользователей на злонамеренные веб-сайты. Проверяя Redirect URI, сервер авторизации может гарантировать, что перенаправление осуществляется в пределах разрешенного домена или набора доверенных доменов.
  3. Гарантирование правильной маршрутизации ответов авторизации: проверка Redirect URI помогает гарантировать, что сервер авторизации перенаправляет пользователя обратно в преднамеренное клиентское приложение. Это обеспечивает доставку ответа, такого как код авторизации или токен доступа, в правильное место.

В Logto регистрация redirect_uri обязательна для всех типов приложений. Мы сравниваем и сравниваем полученное значение с зарегистрированными на сервере Logto. Это включает любые пользовательские параметры поиска. Если запрос на авторизацию не проходит проверку из-за отсутствующего, недействительного или несовпадающего значения redirect_uri, ошибку недействительного Redirect URI возвращается в зарегистрированный redirect_uri на файле.

Итог

Из-за их сложности и нюансов часто упускают из виду эти детали. Некоторые просто являются случайной строкой, как state.

Однако важно отметить, что эти меры безопасности добавляют слои защиты к авторизации пользователя, снижая риски, такие как атаки CSRF, перехват кода авторизации и несанкционированные перенаправления.

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

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