Комментарии 25
К сожалению, они могут быть достаточно популярны. Что делать в этом случае?
В статье же речь идет о кастомной схеме (например, mailrumail), которая браузеру неизвестна.
Я не сталкивался с ситуациями, когда браузеры полностью не поддерживают Custom URI Scheme. Если такие есть, можешь привести пример?
bugs.chromium.org/p/chromium/issues/detail?id=170880
Тестирования в двух компаниях где я работал стабильно находило этот баг:(
Другое дело, если найдется браузер, для которого не открыть Custom URI Scheme — ожидаемое поведение, и при этом он будет достаточно популярным. В таком случае нужно задуматься путях решения проблемы или об альтернативах Custom URI Scheme.
1) Зачем нам добиваться редиректа в приложение? Почему не подходит вариант открывать вебвью для прохождения веб-части авторизации в рамках самого своего приложения и просто доставать полученный authorization_code из него через интерфейс взаимодействия с вебвью? В этом случае браузер и приложение существуют рядом друг с другом и связываться с кастомными схемами просто не требуется.
2) Если обращение в Token Endpoint из вашего приложения проксировать через свой сервер, то хранение client_secret можно перенести на него. Равно как и избавиться от передачи authorization_code в приложение — можно сразу за счёт указания redirect_url передавать его на свой бэкенд и в ответ возвращать в браузер готовый access_token. Стоят ли все эти ухищрения в вашей статье того, чтобы сэкономить не так много времени на реализацию простого бэкенда для авторизации? Совсем server-less приложения это всё же редкость…
По второму вопросу. У приложения может быть серверная часть, но кому-то дешевле оставить взаимодействие с токенами на стороне мобильного приложения. Не нужны сервера для хранения токенов и обработки запросов, не нужна разработка и тестирование серверного кода, не нужно заботиться о безопасности такой инфраструктуры. Это не отменяет тех случаев, когда OAuth 2.0 клиенты получают, используют и хранят
access_token
на сервере, а не в мобильном приложении. Оба варианта возможны и какой вариант использовать — это по большей части выбор OAuth 2.0 клиента (при условии, что OAuth 2.0 провайдер безопасно реализовал оба варианта на своей стороне).Вообще, если говорить про легитимность приложений, то инструмент, дающий возможность на сервере отделить своих от чужих был бы очень кстати. В частности, мы могли бы просто не открывать в WebView страницу ввода учётных данных вообще, если знаем, что инициатором запроса было не наше приложение (если, конечно, провайдером OAuth2 являемся мы сами). И, как я понимаю, это уже возможно через использование Attestation API (https://developer.android.com/training/safetynet/attestation).
В общем же случае, установленный зловредный браузер приводит к более серьезным проблемам, чем доступ к данным пользователя на одном сервисе. Таким браузером можно компрометировать аккаунты пользователя сразу нескольких веб-приложений.
Вообще, если говорить про легитимность приложений, то инструмент, дающий возможность на сервере отделить своих от чужих был бы очень кстати.
Если приложение-клиент использует OAuth 2.0 через приложение-провайдер, то такая проверка возможна. Если же приложение-клиент использует OAuth 2.0 через браузер, то там обычный HTTP запрос и зловред может его подделать, потому что секреты в мобильном приложении безопасно не зашить (их можно проснифать или разреверсить).
Поможет ли Attestation API в данном случае сходу сказать не могу, нужно читать, разбираться и пробовать. Но за ссылку спасибо, посмотрю.
В случае, если устройство пользователя не поддерживает SHA-256, то допустим даунгрейд до отсутствия преобразования code_verifier.
Вот не надо так! Откуда возьмутся такие устройства, на которых реально нет возможности реализовать SHA-256, но при этом есть возможность запускать свои OAuth-клиенты? Большинство проблем с безопасностью OAuth вызвано тем, что критичный для безопасности функционал объявляют опциональным, ибо "это фреймворк".
Приложение-клиент сравнивает пришедший и сохраненный CSRF-токен. Если значения совпадают, то процесс продолжается дальше.
Не всё так просто. Бывают атаки, которые намеренно искажают state отправляемый или получаемый легитимным клиентом (не уверен что мобильные, но для веб-клиентов я про такое читал) — делается это как раз для того, чтобы легитимный клиент остановился на этом этапе. Если state не совпал, то клиент всё-равно должен послать запрос к token endpoint и передать туда code; а вот уже после получения ответа от token endpoint (любого, включая ошибку и корректный access_token) клиент должен прервать процесс (и выкинуть полученный access_token, даже если он его получил) по причине некорректного state.
Вообще, в такие статьи надо звать Homakov, он много забавного может рассказать (если не путаю, то "OAuth by Sakurity" на который ссылается статья это его, либо основан на его "OAuth Security Cheatsheet"). :)
Зловред, притворяющийся легитимным клиентом
Из описания не совсем понятен сценарий атаки, можете пояснить как конкретно это работает?
Таким образом, мы можем использовать Implicit Grant и значительно упростить схему мобильного OAuth 2.0.
А разве использование IPC вместо HTTP не подразумевает автоматически, что это уже вообще не OAuth и не Implicit Grant, а просто какой-то свой простейший RPC-протокол access_token,err:=authorize(scope)
(client_id уже известен из взаимной проверки при установлении IPC, redirect_uri не имеет смысла — хотя по протоколу OAuth это обязательное поле, если не путаю).
Откуда возьмутся такие устройства, на которых реально нет возможности реализовать SHA-256, но при этом есть возможность запускать свои OAuth-клиенты?
Подобные устройства я не встречал и у меня возник точно такой же вопрос при чтении стандарта. Думаю, что в стандарте не просто так сделали примечание про устройства без поддержки SHA-256, поэтому и пишу про это в статье.
Еще раз подчеркну, что если SHA-256 поддерживается, то нельзя делать даунгрейд до отсутствия преобразования
code_verifier
. Это указано и в статье, и в RFC 7636.Бывают атаки, которые намеренно искажают state отправляемый или получаемый легитимным клиентом (не уверен что мобильные, но для веб-клиентов я про такое читал) — делается это как раз для того, чтобы легитимный клиент остановился на этом этапе
Интересно, не знал про подобные атаки. А для чего злоумышленнику останавливать клиента на этом этапе?
Из описания не совсем понятен сценарий атаки, можете пояснить как конкретно это работает?
У пользователя установлены два приложения: легитимное и зловред. Происходит следующее:
- Зловред поднимает consent screen легитимного приложения. Для этого зловреду достаточно передать
client_id
легитимного клиента. - Невнимательный пользователь может разрешить доступ к своим ресурсам и подумать, что дает доступ легитимному приложению (на consent screen ведь иконка и название легитимного приложения), а в действительности он предоставит доступ зловреду.
- После этого зловред получит
code
, обменяет его наaccess_token
и получит доступ к ресурсам пользователя.
А разве использование IPC вместо HTTP не подразумевает автоматически, что это уже вообще не OAuth и не Implicit Grant, а просто какой-то свой простейший RPC-протокол
На мой взгляд, IPC это всего лишь транспорт (способ доставки)
access_token
, который заменяет HTTP. Протокол OAuth 2.0 показан на примере транспорта HTTP, потому что он наиболее популярен в вебе. Если посмотреть на описание Implicit Grant, то видно, что там не сказано, что транспортом обязательно должен быть HTTP.То что IPC из коробки может передать
client_id
и "redirect_uri"
и по тому же соединению получить ответ — не делает его хуже HTTP.При использованием новых транспортов самое главное — учесть все возможные проблемы безопасности, связанные с транспортом. Хороший пример — кейс с использованием postMessage в реализации OAuth 2.0. Подчеркну, что сам по себе postMessage не является плохим транспортом, но необходимо учитывать возможные проблемы безопасности, которые он привносит.
А для чего злоумышленнику останавливать клиента на этом этапе?
Злоумышленник перехватил code
(одновременно с искажением state
), и хочет получить access_token
. Для этого ему нужно послать запрос на token endpoint. Если запрос пошлёт только он — для сервера OAuth это будет выглядеть легитимным запросом. Если запрос пошлёт и он, и настоящий клиент — сервер сможет определить вероятную утечку code
по факту получения двух запросов с одинаковым code
, и при получении второго из них инвалидировать выданный в ответ на первый запрос access_token
. Таким образом, "окно", в течении которого злоумышленник может использовать access_token
сужается до долей секунды, плюс сервер получает информацию о самом факте утечки, что тоже ценно.
У пользователя установлены два приложения: легитимное и зловред.
Т.е., условно говоря, юзер скачал где-то мобильное приложение, притворяющееся настоящим клиентом, запустил его, оно использовало client_id настоящего клиента для получения доступа. Немного напоминает "я бедный африканский хакер" в топике про вирусы под линух, ну да ладно. Но где в этой картине второй, настоящий клиент?
Если посмотреть на описание Implicit Grant, то видно, что там не сказано, что транспортом обязательно должен быть HTTP.
Хм. Насколько я его понимаю — как раз сказано (выделенные термины подразумевают именно HTTP):
"Since this is a redirection-based flow, the client must be capable of interacting with the resource owner's user-agent (typically a web browser) and capable of receiving incoming requests (via redirection) from the authorization server."
Ну и плюс к этому в разделе Introduction написано вполне однозначно:
"This specification is designed for use with HTTP ([RFC2616]). The use of OAuth over any protocol other than HTTP is out of scope."
Злоумышленник перехватил code (одновременно с искажением state), и хочет получить access_token.
А в каком случае злоумышленник может перехватить
code
и исказить state
, но при этом не может просто прервать запрос пользователя? Я вижу вариант, когда злоумышленник MitM-ит пользователя, но в этом случае он может и другими способами прервать запрос за access_token
.Т.е., условно говоря, юзер скачал где-то мобильное приложение, притворяющееся настоящим клиентом, запустил его, оно использовало client_id
настоящего клиента для получения доступа. Немного напоминает «я бедный африканский хакер» в топике про вирусы под линух, ну да ладно. Но где в этой картине второй, настоящий клиент?
Да, все так. Настоящего клиента может и не быть, суть атаки именно в том, что зловред показывает чужой consent screen, а пользователь из-за невнимательности фишится. Вектор атаки не супер критичный, но все равно я думаю, что лучше его учесть и принять меры защиты.
«This specification is designed for use with HTTP ([RFC2616]). The use of OAuth over any protocol other than HTTP is out of scope.»
Это можно трактовать как «OAuth 2.0 должен использоваться только вместе с HTTP», так и как «OAuth 2.0 разрабатывался для HTTP, любые другие транспорты вы используете на свой страх и риск». Я больше склоняюсь ко второй. При использовании транспортов отличных от HTTP нужно учитывать уязвимости, которые транспорт привнесет вместе с собой, и тщательно проверять на безопасность. Называть получившийся после замены транспорта протокол OAuth-ом или не называть, на мой взгляд, уже холиварный вопрос.
А в каком случае злоумышленник может перехватить code и исказить state, но при этом не может просто прервать запрос пользователя?
Я проверил свою шпаргалку по безопасности OAuth: к сожалению, я там не сохранил ссылку на конкретное описание атаки, но у меня это описано в разделе "если OAuth клиент уязвим к XSS". XSS бывают очень разные, не всегда есть возможность полностью захватить контроль над скриптами уязвимого сайта чтобы помешать им использовать code
, но вполне можно исказить значение state
, сохранённое где-то между отправкой запроса на authorization endpoint и редиректом обратно. Насколько это реальный кейс и насколько он применим к мобильным клиентам — мне сложно сказать, я всё-таки не эксперт в области безопасности, скорее просто продвинутый любитель. :)
А теперь представьте: пользователь нажимает кнопку «войти с помощью ...» и WebView зловредного приложения запрашивает у него логин и пароль от сервиса-провайдера.
Я не вполне понял этот сценарий — можете уточнить?
Пользователь в моем (легитимном) приложении нажимает кнопку "Войти", открывается WebView, к которому мое же приложение имеет полный доступ.
Что тут плохого? На каком этапе доступ к этому WebView получает приложение-зловред?
Так может не стоит приучать пользователей вводить пароль в приложении, ведь, как я понял, "на глаз" пользователь небезопасный WebView от безопасного Browser Custom Tab отличить может с большим трудом, а вот переключение в системный браузер всё-таки намного заметнее и понятнее?
Затем, что кто помешает стороннему клиенту в какой-то момент заменить в своём мобильном приложении Browser Custom Tab на WebView и начать красть пароли юзеров, причём так, что никто этого даже и не заметит?
По хорошему, нужен какой-то механизм определения WebView на стороне OAuth сервера. Что-то аналогичное тому, как сейчас мы определяем (и запрещаем соответствующими HTTP заголовками) встраивать страничку consent в фреймы на сторонних сайтах. Это бы дало возможность тупо заблокировать использование WebView любыми мобильными клиентами.
Я хочу приучить вводить пароль только в одном приложении — в браузере, в котором пользователи более-менее научились отличать настоящие сайты от зловредных (на самом деле нет, но там их хотя бы этому постоянно учат и дают какие-то способы их отличать). Потому что, во-первых, мне не очень нравится ставить на телефон лишние (потому что я ими не пользуюсь) "официальные" приложения только ради того, чтобы они показывали запрос логина/пароля, и во-вторых, как описано в статье, пользователю очень сложно определить какое именно мобильное приложение запрашивает пароль — легитимное или зловредное.
То есть в статье рекомендация про WebView — это рекомендация злоумышленнику по написанию более безопасного зловреда?
В частности, не говорится о том, что в общем случае невозможно отличать сервисы-клиенты по client_id. Соответственно в общем случае нельзя выдавать чувствителеные к client_id методы в публичный API.
Безопасность мобильного OAuth 2.0