- PVSM.RU - https://www.pvsm.ru -

Безопасность OAuth2

Данная блогозапись на хабр прежде всего обусловлена появлением «Ключницы» [1] — хороший повод связать [2] и [3] перевести [4] накопленное.

Безопасность OAuth2
У нас в программе: вольный пересказ спек OAuth2, слабые стороны и Threat Model, 0day на хабретрюк с аутенфикацией.
image

OAuth2 это просто

Длинный, но правильный путь изучить его. [5]
Для ленивых я опишу своими словами Authorization Code Flow как самый распространенный и безопасный, aka Server-Side [6].

Ключевые понятия — Клиент(website/online game/app), Юзер(you), Провайдер(facebook/vkontakte/google), Код(code) и Токен(access_token).

Клиент посылает Юзера — «авторизуй меня для доступа к твоим ресурсам». Юзер идет по ссылке к провайдеру, смотрит что от него требуют — scope параметр — жмет Разрешить. Далее Провайдер редиректит его назад на указанный redirect_uri на домене Клиента со следующими параметрами:
code — идентификатор Юзера у Провайдера, который нужен Клиенту чтобы получить Токен
state — то же значение что было передано на начальный URL. используется для защиты от CSRF и для удобства.

Код из себя не представляет никакой ценности для Юзера(и User-Agent соответственно) т.к. с его помощью нельзя совершать запросы API и нужен он лишь для одной цели — получения Токена.
Для получения Токена Клиент производит запрос на определенный эндпоинт, передав client_id, client_secret, code, redirect_uri по которому был получен код — таким образом Провайдер уверен что это нужный Клиент и по Коду он отдает Токен того самого Юзера. Как видите ни Юзер, ни User-Agent и клиентские скрипты не увидили настоящий Токен. Его знают только Клиент и Провайдер — в идеале.

Дальше Токен используют для совершения API запросов, впоследствии его можно рефрешить (для этого вместе с Токеном возвращается refresh_token).

Threat Model или Я Знаю О Чем Вы Подумали

Длинный, но правильный путь безопасно пользоваться OAuth. [7]
Здесь же отмечу:

1. А что если я подставлю такой redirect_uri который будет вести на свой сайт а потом использую этот Код сам для аутенфикации?

Все redirect_uri должны находится на домене Клиента. Часто разрешен еще домен Провайдера. Ваша ссылка вернет redirect_uri_mismatch.

2. ОК а что если я найду такое место на сайте Клиента, которое сольет мне Код? Может открытый редирект вида site.com?url=http://outsite.com или hot-linked картинку которая сольет реферер?

Каждый Код привязан к тому redirect_uri для которого он был выпущен и для получения Токена Клиент передает «правильный» redirect_uri. Если ваш Код был выпущен для clientsite.com/leak_referer [8] а Клиент при получении Токена отошлет clientsite.com/facebook_callback [9] то Провайдер не отдаст Токен.

3. А можно ли как то слить Код передав правильный redirect_uri?

Нет, т.к. любая правильная реализация Клиента обязана сразу редиректить на другую страницу после получения Кода — так что Код не виден даже в истории браузера.
Даже если вам удалось достать код для правильного redirect_uri то т.к. он уже был 1 раз использован он больше не активен.

4. Допустим у меня есть Код для моего аккаунта в соц сети выпущенный для правильного redirect_uri. Что будет если я заставлю посетить эту ссылку Васю?

В таком случае сайт Клиента подумает что ваш аккаунт в соц сети принадлежит Васе. И присоеденит его. Чтобы типичного CSRF не происходило Клиент обязан сохранять рандомное значение state в сессии/куке и проверять по возврату на колбэк на соответствие. Хотя, так почти никто не делает (точнее не делали).

Реальность

FB Reply Attack

Facebook Connect уязвим для классической Replay attack. [10]
Демонстрирует пункт 3 — после одного использования кода он еще может быть использован для аутенфикации в течение 60-80 минут — стандартное expire_in токена. Реплай атака в чистом виде.
Допустим, на сайте нашли XSS — примерно такой инжект поможет вытащить код для правильного redirect_uri через document.referrer фрейма.
<iframe src="https://www.facebook.com/dialog/permissions.request?app_id=159618457465836&display=page&next=http://magru.net/users/auth/facebook/callback&response_type=code" name="refcontainer" onload="alert(refcontainer.document.referrer)"></iframe>

Hijacking Account

Самая частая уязвимость, присутствует например на хабре [2] — об этом ниже. Нарушается пункт 4.
Если вы видите в запросе state не спешите сдаваться. Что хабр, что digg.com не видили разницы между a12b6467c3fb385e237109502277ab26 и heyman0day123123

VK redirect_uri

Реализация сделана по каким-то древним манускриптам — отсутствие проверки это грубое нарушение пункта 3.
Смотрите, вот ссылка [11] Жмите, не бойтесь, и откройте Network Panel. Видите запрос?
Безопасность OAuth2
Реферер слился, код слился — теперь его можно использовать чтобы зайти в ваш аккаунт через ваш вконтакте(если вы его привязали).

misc

Если вы используете Implicit Flow — т.е. получаете access_token от юзера напрямую, то нет никаких гарантий что этот токен принадлежит текущему юзеру. Он мог его просто украсть через вредоносного Клиента, и использовать чтобы попасть в аккаунт какого-то юзера на вашем сайте.
Обязательно проверяйте, был ли выпущен данный токен для вашего client_id.

Так же OAuth2 не дает никаких гарантий что пользователь дал вам те разрешения что вы запросили на этапе авторизации в параметре scope. Он мог просто удалить их [12] — в итоге вы должны на колбэке проверить разрешил ли он что вы запросили.

Если на сайте найдена XSS то есть легкий способ украсть кучу access_token-ов. Возьмите authorize URL который сайт использует для facebook и замените response_type=code на token. Осталось вставить этот URL во фрейм, дождаться возврата токена в ссылке вида callback#access_token=123, срезать токен и слить его. Спамьте на здоровье!

0day на хабре?

Тот же эксплоит работает и для facebook/google только сложнее получить redirect_uri с кодом без использования его — нужен NoRedirect+FF
Поэтому демо на VK. дяденька не бань

1. Данный VK аккаунт не должен быть привязан к какому-то читательу. Авторизуйтесь тут: oauth.vk.com/authorize?response_type=code&client_id=3110645&redirect_uri=http%3A%2F%2Fhabrahabr.ru&scope=offline&display=page [13]
2. Вас вернуло на habrahabr.ru/?code=CODE [14]
3. Заставьте другого читателя посетить habrahabr.ru/social/callback/vkontakte/?code=CODE&state=whogivesafuckaboutstate [15] можно подкинуть саму ссылку, но лучше спрятать в img или iframe и тд. Если он залогинен на хабре ваш ВК привяжен к его хабрааккаунту.
4. Логинимся через ваш ВК в его хабрааккаунт, меняем его аватар на nayncat.

Мораль

Вконтакте: перестаньте игнорировать письма в Поддержку, либо попросите ваших разработчиков снизойти поговорить с простым смертным. А еще введите bounty program (sarcasm: есть риск разориться на ней).
Хабр: рекомендую выключить Ключницу на время и пофиксить уязвимость путем правильной проверки 'state' со значением из cookie/session. Этот пост и есть репорт по причине отстутствия времени объяснять два раза.

Road to Hell [16] короче. Вы можете присоедениться к разработке принципиально нового стандарта с нескучными токенами — OAuth2.a (Charm — Provider [17]). Печенек, правда, нет.

Egor Homakov [18] (@homakov [19]) & isciurus [20] #RT pls
Безопасность OAuth2

Автор: Chikey


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/facebook/14560

Ссылки в тексте:

[1] «Ключницы»: http://habrahabr.ru/settings/social/

[2] связать: http://homakov.blogspot.com/2012/07/saferweb-most-common-oauth2.html

[3] и: http://homakov.blogspot.com/2012/08/saferweb-oauth2a-or-lets-just-fix-it.html

[4] перевести: http://homakov.blogspot.com/2012/08/oauth2-one-accesstoken-to-rule-them-all.html

[5] Длинный, но правильный путь изучить его.: http://tools.ietf.org/html/draft-ietf-oauth-v2-31

[6] Server-Side: http://developers.facebook.com/docs/authentication/server-side/

[7] Длинный, но правильный путь безопасно пользоваться OAuth.: http://tools.ietf.org/html/draft-ietf-oauth-v2-threatmodel-07

[8] clientsite.com/leak_referer: http://clientsite.com/leak_referer

[9] clientsite.com/facebook_callback: http://clientsite.com/facebook_callback

[10] Replay attack.: http://en.wikipedia.org/wiki/Replay_attack

[11] вот ссылка: http://oauth.vk.com/authorize?response_type=code&client_id=3110645&redirect_uri=http://habrahabr.ru/qa/4659/&state=a12b6467c3fb385e237109502277ab26&scope=offline&display=page

[12] Он мог просто удалить их: http://homakov.blogspot.com/2012/08/how-to-cheat-on-facebook-apps.html

[13] oauth.vk.com/authorize?response_type=code&client_id=3110645&redirect_uri=http%3A%2F%2Fhabrahabr.ru&scope=offline&display=page: http://oauth.vk.com/authorize?response_type=code&client_id=3110645&redirect_uri=http%3A%2F%2Fhabrahabr.ru&scope=offline&display=page

[14] habrahabr.ru/?code=CODE: http://habrahabr.ru/?code=CODE

[15] habrahabr.ru/social/callback/vkontakte/?code=CODE&state=whogivesafuckaboutstate: http://habrahabr.ru/social/callback/vkontakte/?code=CODE&state=whogivesafuckaboutstate

[16] Road to Hell: http://hueniverse.com/2012/07/oauth-2-0-and-the-road-to-hell/

[17] Charm — Provider: https://github.com/ysoslow/charm

[18] Egor Homakov: http://homakov.blogspot.com

[19] @homakov: http://twitter.com/homakov

[20] isciurus: http://isciurus.blogspot.com/