OAuth 2.0 — протокол авторизации, позволяющий входить на сайты с помощью профиля в социальных сетях. Протокол имеет гибкую структуру, в нём отсутствуют обязательные функции безопасности, что повышает вероятность успешной атаки со стороны злоумышленников. Наличие уязвимостей в OAuth 2.0 зависит от правильности применения потоков протокола, а также от использования его параметров.
Введение
Ниже речь пойдёт о протоколе авторизации, который позволяет веб-сайтам и веб-приложениям запрашивать ограниченный доступ к учётной записи пользователя в другом приложении — тем самым осуществляя вход через профиль в социальных сетях. Такой способ авторизации очень распространён, так как большинство пользователей не любят заводить новые аккаунты на различных сайтах и доверять им свои данные. Протокол OAuth 2.0 появился в 2012 году и очень отличается от предыдущей версии 2007 года.
Статья будет полезна тем, кто желает познакомиться с устройством фреймворка для авторизации и возможными тонкостями его настройки, дабы предотвратить утечку своих данных или данных пользователей.
Примером уязвимости протокола OAuth 2.0 может служить вектор кибератаки, представленный исследователями на Black Hat Europe в 2016 году. Как объяснили эксперты, в приложениях для Android и iOS небезопасно использовать технологию единого входа (Single Sign-On, SSO) через протокол OAuth 2.0.
Ход работы OAuth 2.0
OAuth 2.0 изначально был разработан как способ обмена доступом к определённым данным между приложениями. Он работает определяя ряд взаимодействий между тремя различными сторонами, а именно — клиентским приложением, владельцем ресурса и поставщиком услуг OAuth.
- Клиентское приложение — веб-сайт или веб-приложение, которое хочет получить доступ к данным пользователя.
- Владелец ресурса — пользователь, к данным которого клиентское приложение хочет получить доступ.
- Поставщик услуг OAuth — веб-сайт или приложение, которое контролирует данные пользователя и доступ к ним. Они поддерживают OAuth, предоставляя API для взаимодействия как с сервером авторизации, так и с сервером ресурсов.
Порядок авторизации через OAuth 2.0 (выполнение потока «код авторизации») следующий:
- Клиентское приложение запрашивает доступ к подмножеству данных пользователя, указывая, какой тип потока (сценарий взаимодействия сторон) он хочет использовать и какой тип доступа он хочет получить.
- Пользователю предлагается войти в сервис OAuth и явно дать согласие на запрашиваемый доступ.
- Клиентское приложение получает уникальный код доступа, который доказывает, что у него есть разрешение пользователя на доступ к запрошенным данным. То, как именно это происходит, существенно варьируется в зависимости от сценария взаимодействия.
- Клиентское приложение использует этот код доступа для выполнения вызовов API, извлекающих соответствующие данные с сервера ресурсов.
Рассмотрим этапы авторизации:
1. Запрос
Клиентское приложение отправляет запрос разрешения на доступ к определённым пользовательским данным на конечную точку сервиса OAuth:
GET
/authorization?client_id=9999&redirect_uri=https://clientapp.com
/callback&response_type=code&scope=openid%20profile%20email&state=dc33e666ae00d3b56 HTTP/1.1
Host: authorization-server.com
В этом запросе:
- «authorization» — конечная точка сервиса OAuth. Может выглядеть иначе в зависимости от поставщика услуг.
- «client_id» — обязательный параметр, содержащий уникальный идентификатор клиентского приложения. Это значение генерируется, когда клиентское приложение регистрируется в сервисе OAuth.
- «redirect_uri» — URI, на который должен быть перенаправлен браузер пользователя при отправке кода авторизации в клиентское приложение. Многие атаки на OAuth основаны на использовании недостатков в проверке этого параметра.
- «response_type» — определяет то, какого рода ответ ожидает клиентское приложение и, следовательно, какой поток оно хочет инициировать. Для типа предоставления кода авторизации используется значение «code». Для неявного типа потока (сценария взаимодействия) это значение равняется «token».
- «scope» — используется для указания того, к какому подмножеству пользовательских данных хочет получить доступ клиентское приложение.
- «state» — хранит уникальное, не поддающееся определению значение, привязанное к текущему сеансу в клиентском приложении. Сервис OAuth должен вернуть это значение в ответе вместе с кодом авторизации. Этот параметр служит формой токена CSRF для клиентского приложения, удостоверяя, что запрос к его конечной точке /callback исходит от того же лица, которое инициировало поток OAuth. Такой токен предотвращает создание полностью действительного HTTP-запроса, подходящего для подачи пользователю-жертве. Поскольку злоумышленник неспособен определить или предсказать значение токена CSRF пользователя, он не может построить запрос со всеми параметрами, которые необходимы приложению для выполнения этого запроса. Данный параметр является необязательным, но рекомендуемым.
2. Логин и согласие пользователя
Когда сервер авторизации получит первоначальный запрос, он перенаправит пользователя на страницу входа в систему, где будет предложено войти в учётную запись. Затем пользователь увидит список данных, к которым клиентское приложение хочет получить доступ. Состав этого перечня зависит от значения параметра «scope» в запросе авторизации. Пользователь может выбрать, давать или не давать согласие на этот доступ.
3. Предоставление кода авторизации
Если пользователь согласен на запрошенный доступ, его браузер будет перенаправлен на /callback — конечную точку, указанную в параметре «redirect_uri». Полученный GET-запрос будет содержать код авторизации («code») в качестве параметра запроса. В зависимости от конфигурации он также может отправить параметр «state» с тем же значением, что и в запросе авторизации:
GET /callback?code=a1b2c3d4e5f6g7h8&state=dc33e666ae00d3b56
HTTP/1.1
Host: clientapp.com
4. Запрос кода доступа
Как только клиентское приложение получает код авторизации («code»), оно должно обменять его на код доступа (access token). Для этого приложение отправляет POST-запрос от сервера к серверу на конечную точку службы OAuth — /token (она может выглядеть иначе в зависимости от поставщика услуг). Вся коммуникация с этого момента происходит в защищённом обратном канале и, следовательно, обычно не может быть замечена или проконтролирована злоумышленником.
POST /token HTTP/1.1
Host: authorization-server.com
…
client_id=9999&client_secret=SECRET&redirect_uri=https://clientapp.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8
В дополнение ко «client_id» и коду авторизации («code») есть новые параметры:
- «client_secret» — клиентское приложение должно аутентифицировать себя, указав секретный ключ, который был назначен при регистрации в службе OAuth.
- «grant_type» — позволяет убедиться, что новая конечная точка знает, какой тип потока (сценарий взаимодействия) хочет использовать клиентское приложение.
5. Предоставление кода доступа
Сервис OAuth проверит запрос кода доступа. Если всё идет так, как ожидалось, сервер отвечает, предоставляя клиентскому приложению код доступа с запрошенной областью действия:
"access_token": "q5h6s1e8u3r2",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile",
…
В этом ответе:
- «token_type» — параметр отвечающий за то, как будет представлен код доступа. Значение «Bearer» устанавливается по умолчанию и означает, что доступ предоставляется тому, у кого есть этот код.
- «expires_in» — параметр устанавливающий время жизни маркера доступа в секундах.
6. Вызов API
Теперь клиентское приложение имеет код доступа и может получить данные пользователя с сервера ресурсов. Для этого сервер выполняет вызов API в адрес конечной точки службы OAuth — /userinfo (конечная точка может выглядеть иначе в зависимости от поставщика услуг). Код доступа передаётся в заголовке «Authorization: Bearer», чтобы доказать, что клиентское приложение имеет разрешение на доступ к этим данным.
GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer q5h6s1e8u3r2
7. Предоставление ресурсов
Сервер ресурсов должен проверить, что код доступа, переданный на шаге 5, действителен и принадлежит текущему клиентскому приложению. Если это так, то сервер ответит отправив запрошенный ресурс, то есть данные пользователя, основанные на области действия кода доступа.
{
"username":"boris",
"email":"boris@gmail.com",
…
}
Клиентское приложение может, наконец, использовать эти данные по назначению.
Разбор уязвимостей авторизации
OAuth 2.0 имеет весьма гибкую конструкцию без конкретных правил реализации, за исключением некоторых обязательных компонентов, необходимых для функционирования каждого типа потока (сценария взаимодействия). Такая «плавающая» структура скрывает в себе множество возможностей для атак злоумышленников.
Помимо этого в OAuth 2.0 отсутствуют общие обязательные функции безопасности. Сама безопасность зависит от разработчиков, использующих правильную комбинацию параметров конфигурации и реализующих свои собственные дополнительные меры безопасности сверху, такие как надёжная проверка входных данных.
Также в некоторых сценариях взаимодействия высококонфиденциальные данные отправляются через браузер, что опять же даёт злоумышленникам возможность совершить перехват информации.
Уязвимости могут быть как в клиентском приложении, реализующем авторизацию через OAuth 2.0, так и в конфигурации самого сервиса. Ниже будут рассмотрены уязвимости для обоих случаев.
Уязвимость в клиентском приложении
Неправильное использование неявного типа потока
Выше уже упоминался неявный тип потока (сценарий взаимодействия). Этот сценарий наиболее прост в реализации за счёт сокращённого числа параметров. Реализуя данный тип потока, клиентское приложение отправляет POST-запрос на сервер с пользовательскими данными. Такой сценарий взаимодействия не рекомендуется использовать для классических клиент-серверных веб-приложений, так как в нём отсутствует параметр «state» (токен CSRF), что может привести ко злонамеренной подмене HTTP-запроса пользователя — вследствие чего киберпреступник сумеет выдать себя за любого пользователя либо привязать свой профиль в социальных сетях к профилю жертвы в клиентском приложении.
Уязвимость в конфигурации OAuth 2.0
Утечка кода авторизации и токена доступа
Эта уязвимость связана с конфигурацией сервиса OAuth 2.0, посредством которой злоумышленник может войти в приложение под видом жертвы и получить доступ к её данным.
Как было рассмотрено выше, код авторизации или токен доступа (в зависимости от сценария взаимодействия) отправляется на конечную точку, указанную в параметре «redirect_uri» запроса. Если сервису OAuth не удаётся должным образом проверить этот URI, злоумышленник может создать CSRF-подобную атаку, обманом заставив браузер жертвы инициировать поток OAuth, который отправит код или токен в адрес подконтрольного злоумышленнику redirect_uri.
Для нейтрализации уязвимости сервис OAuth 2.0 должен иметь в запросе не только конечную точку redirect_uri, но и исходный redirect_uri для отправки параметра при обмене кодом или токеном.
Выводы
OAuth 2.0 — простой и уже не новый протокол, он имеет широкое применение — от «Яндекса» до AliExpress. Несмотря на его простое устройство, нередко возникают проблемы с реализацией этого протокола, что порождает уязвимости, и риск подмены пользователя увеличивается. При реализации OAuth 2.0 следует обращать внимание на применяемые сценарии взаимодействия, а также помнить о дополнительных мерах безопасности.
Простому пользователю сложно оценить, насколько правильно внедрена технология авторизации и попадут ли его данные к злоумышленнику.
Единственное, что может сделать пользователь, чтобы предотвратить хищение данных при авторизации через социальные сети, — это обращать внимание на ссылки и на то, куда они ведут. Ссылки на фишинговые страницы могут быть получены по почте или скрываться на оригинальных сайтах, если разработчики допустили уязвимость типа Open Redirect. В подобном сценарии домен может выглядеть знакомо, но конечная точка изменена; после перехода по такой ссылке и ввода данных на неподдельном сайте пользователь перебрасывается на фейковый ресурс с аналогичным дизайном и формой входа, содержащей надпись о неверном вводе пароля. Тогда пользователь повторит ввод данных и переместится снова на оригинальный сайт, словно совершил вход. Тем не менее реквизиты доступа уже будут украдены и использованы злоумышленником.