- PVSM.RU - https://www.pvsm.ru -
Данная блогозапись на хабр прежде всего обусловлена появлением «Ключницы» [1] — хороший повод связать [2] и [3] перевести [4] накопленное.
У нас в программе: вольный пересказ спек OAuth2, слабые стороны и Threat Model, 0day на хабретрюк с аутенфикацией.
Длинный, но правильный путь изучить его. [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).
Длинный, но правильный путь безопасно пользоваться 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 в сессии/куке и проверять по возврату на колбэк на соответствие. Хотя, так почти никто не делает (точнее не делали).
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>
Самая частая уязвимость, присутствует например на хабре [2] — об этом ниже. Нарушается пункт 4.
Если вы видите в запросе state не спешите сдаваться. Что хабр, что digg.com не видили разницы между a12b6467c3fb385e237109502277ab26 и heyman0day123123
Реализация сделана по каким-то древним манускриптам — отсутствие проверки это грубое нарушение пункта 3.
Смотрите, вот ссылка [11] Жмите, не бойтесь, и откройте Network Panel. Видите запрос?
Реферер слился, код слился — теперь его можно использовать чтобы зайти в ваш аккаунт через ваш вконтакте(если вы его привязали).
Если вы используете Implicit Flow — т.е. получаете access_token от юзера напрямую, то нет никаких гарантий что этот токен принадлежит текущему юзеру. Он мог его просто украсть через вредоносного Клиента, и использовать чтобы попасть в аккаунт какого-то юзера на вашем сайте.
Обязательно проверяйте, был ли выпущен данный токен для вашего client_id.
Так же OAuth2 не дает никаких гарантий что пользователь дал вам те разрешения что вы запросили на этапе авторизации в параметре scope. Он мог просто удалить их [12] — в итоге вы должны на колбэке проверить разрешил ли он что вы запросили.
Если на сайте найдена XSS то есть легкий способ украсть кучу access_token-ов. Возьмите authorize URL который сайт использует для facebook и замените response_type=code на token. Осталось вставить этот URL во фрейм, дождаться возврата токена в ссылке вида callback#access_token=123, срезать токен и слить его. Спамьте на здоровье!
Тот же эксплоит работает и для 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
Автор: 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/
Нажмите здесь для печати.