1. Введение
OAuth — это отраслевой стандарт для делегированной авторизации. Много внимания и заботы было потрачено на создание различных потоков, составляющих стандарт. Даже в этом случае не обошлось без уязвимостей.
В этой серии статей мы обсудим атаки против OAuth с теоретической точки зрения и опишем различные варианты, которые существуют для защиты наших приложений.
2. Предоставление кода авторизации
Поток предоставления кода авторизации — это поток по умолчанию, который используется большинством приложений, реализующих делегированную авторизацию.
Прежде чем этот поток начнется, клиент должен предварительно зарегистрироваться на сервере авторизации, и во время этого процесса он также должен предоставить URL-адрес перенаправления, то есть URL-адрес, по которому сервер авторизации может перезвонить клиенту с авторизацией. Код.
Давайте подробнее рассмотрим, как это работает и что означают некоторые из этих терминов.
Во время потока предоставления кода авторизации клиент (приложение, запрашивающее делегированную авторизацию) перенаправляет владельца ресурса (пользователя) на сервер авторизации (например, « Войти через Google » ). После входа в систему сервер авторизации перенаправляет обратно клиенту код авторизации.
Затем клиент вызывает конечную точку на сервере авторизации, запрашивая токен доступа, предоставляя код авторизации. На этом поток завершается, и клиент может использовать токен для доступа к ресурсам, защищенным сервером авторизации.
Теперь OAuth 2.0 Framework позволяет этим клиентам быть общедоступными
, скажем, в сценариях, когда клиент не может безопасно хранить секрет клиента. Давайте рассмотрим некоторые атаки перенаправления, которые возможны против публичных клиентов.
3. Атаки перенаправления
3.1. Предварительные условия атаки
Атаки с перенаправлением основаны на том факте, что стандарт OAuth не полностью описывает степень, в которой должен быть указан этот URL-адрес перенаправления. Это по дизайну.
Это позволяет некоторым реализациям протокола OAuth разрешать частичный URL-адрес перенаправления.
Например, если мы зарегистрируем идентификатор клиента и URL-адрес перенаправления клиента со следующим совпадением на основе подстановочных знаков с сервером авторизации:
*.cloudapp.net
Это будет справедливо для:
app.cloudapp.net
но и для:
зло.cloudapp.net
Мы специально выбрали домен cloudapp.net
, так как это реальное место, где мы можем размещать приложения на основе OAuth. Домен является частью платформы Microsoft Windows Azure и позволяет любому разработчику разместить под ним поддомен для тестирования приложения. Само по себе это не проблема, но это жизненно важная часть большого подвига.
Второй частью этого эксплойта является сервер авторизации, который разрешает сопоставление подстановочных знаков в URL-адресах обратного вызова.
Наконец, чтобы реализовать этот эксплойт, разработчик приложения должен зарегистрироваться на сервере авторизации, чтобы принимать любой URL-адрес в основном домене в виде *.cloudapp.net
.
3.2. Атака
Когда эти условия соблюдены, злоумышленнику необходимо обманом заставить пользователя запустить страницу из поддомена, находящегося под его контролем, например, отправив пользователю подлинное электронное письмо с просьбой предпринять какие-либо действия с учетной записью, защищенной OAuth. Обычно это выглядит примерно так: https://evil.cloudapp.net/login
. Когда пользователь открывает эту ссылку и выбирает логин, он будет перенаправлен на Сервер авторизации с запросом на авторизацию:
GET /authorize?response_type=code&client_id={apps-client-id}&state={state}&redirect_uri=https%3A%2F%2Fevil.cloudapp.net%2Fcb HTTP/1.1
Хотя это может показаться типичным, этот URL-адрес является вредоносным. Смотрите, в этом случае сервер авторизации получает поддельный URL-адрес с идентификатором клиента приложения
и URL-адресом перенаправления, указывающим обратно на злое
приложение.
Затем сервер авторизации проверит URL-адрес, который является субдоменом в указанном основном домене. Поскольку сервер авторизации считает, что запрос исходит из допустимого источника, он аутентифицирует пользователя и затем запросит согласие, как обычно.
После того, как это будет сделано, он теперь будет перенаправляться обратно на поддомен evil.cloudapp.net
, передавая код авторизации злоумышленнику.
Поскольку у злоумышленника теперь есть код авторизации, все, что ему нужно сделать, это вызвать конечную точку токена сервера авторизации с кодом авторизации, чтобы получить токен, который позволяет ему получить доступ к защищенным ресурсам владельца ресурса.
4. Оценка уязвимости сервера авторизации Spring OAuth
Давайте взглянем на простую конфигурацию сервера авторизации Spring OAuth:
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("apricot-client-id")
.authorizedGrantTypes("authorization_code")
.scopes("scope1", "scope2")
.redirectUris("https://app.cloudapp.net/oauth");
}
// ...
}
Здесь мы видим, что сервер авторизации настраивает нового клиента с идентификатором «apricot-client-id»
. Секрета клиента нет, так что это публичный клиент.
Наши уши безопасности должны насторожиться , так как теперь у нас есть два из трех условий — злые люди могут регистрировать поддомены , и
мы используем публичный клиент.
Но обратите внимание, что здесь мы также настраиваем URL-адрес перенаправления и что он является абсолютным . Таким образом мы можем смягчить уязвимость.
4.1. Строгий
По умолчанию Spring OAuth допускает определенную степень гибкости при сопоставлении URL-адресов перенаправления.
Например, DefaultRedirectResolver
поддерживает сопоставление субдоменов.
Давайте использовать только то, что нам нужно. И если мы можем просто точно сопоставить URL-адрес перенаправления, мы должны сделать:
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//...
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.redirectResolver(new ExactMatchRedirectResolver());
}
}
В этом случае мы переключились на использование ExactMatchRedirectResolver
для URL-адресов перенаправления. Этот преобразователь выполняет точное соответствие строки без какого-либо анализа URL-адреса перенаправления. Это делает его поведение гораздо более безопасным и определенным.
4.2. Снисходительный
Мы можем найти код по умолчанию, который имеет дело с сопоставлением URL-адресов перенаправления, в источнике Spring Security OAuth :
/**
Whether the requested redirect URI "matches" the specified redirect URI. For a URL, this implementation tests if
the user requested redirect starts with the registered redirect, so it would have the same host and root path if
it is an HTTP URL. The port, userinfo, query params also matched. Request redirect uri path can include
additional parameters which are ignored for the match
<p>
For other (non-URL) cases, such as for some implicit clients, the redirect_uri must be an exact match.
@param requestedRedirect The requested redirect URI.
@param redirectUri The registered redirect URI.
@return Whether the requested redirect URI "matches" the specified redirect URI.
*/
protected boolean redirectMatches(String requestedRedirect, String redirectUri) {
UriComponents requestedRedirectUri = UriComponentsBuilder.fromUriString(requestedRedirect).build();
UriComponents registeredRedirectUri = UriComponentsBuilder.fromUriString(redirectUri).build();
boolean schemeMatch = isEqual(registeredRedirectUri.getScheme(), requestedRedirectUri.getScheme());
boolean userInfoMatch = isEqual(registeredRedirectUri.getUserInfo(), requestedRedirectUri.getUserInfo());
boolean hostMatch = hostMatches(registeredRedirectUri.getHost(), requestedRedirectUri.getHost());
boolean portMatch = matchPorts ? registeredRedirectUri.getPort() == requestedRedirectUri.getPort() : true;
boolean pathMatch = isEqual(registeredRedirectUri.getPath(),
StringUtils.cleanPath(requestedRedirectUri.getPath()));
boolean queryParamMatch = matchQueryParams(registeredRedirectUri.getQueryParams(),
requestedRedirectUri.getQueryParams());
return schemeMatch && userInfoMatch && hostMatch && portMatch && pathMatch && queryParamMatch;
}
Мы видим, что сопоставление URL-адресов выполняется путем разбора входящего URL-адреса перенаправления на его составные части. Это довольно сложно из-за нескольких функций, таких как соответствие порта, поддомена и параметров запроса. И о том, чтобы разрешить совпадения субдоменов, следует подумать дважды.
Конечно, эта гибкость есть, если она нам понадобится — давайте просто будем использовать ее с осторожностью.
5. Атаки с неявным перенаправлением потока
Чтобы было ясно, неявный поток не рекомендуется . Гораздо лучше использовать поток предоставления кода авторизации с дополнительной защитой, обеспечиваемой PKCE . Тем не менее, давайте посмотрим, как атака перенаправления проявляется с неявным потоком.
Атака с перенаправлением на неявный поток будет следовать той же базовой схеме, что мы видели выше. Основное отличие заключается в том, что атакующий получает токен сразу, так как нет шага обмена кодом авторизации.
Как и прежде, абсолютное совпадение URL-адреса перенаправления также смягчит этот класс атак.
Кроме того, мы можем обнаружить, что неявный поток содержит другую связанную уязвимость. Злоумышленник может использовать клиента в качестве открытого перенаправителя и заставить его переприкреплять фрагменты .
Атака начинается, как и раньше, с того, что злоумышленник заставляет пользователя посетить страницу, находящуюся под контролем злоумышленника, например, https://evil.cloudapp.net/info
. Страница создается для инициирования запроса на авторизацию, как и раньше. Однако теперь он включает URL-адрес перенаправления:
GET /authorize?response_type=token&client_id=ABCD&state=xyz&redirect_uri=https%3A%2F%2Fapp.cloudapp.net%2Fcb%26redirect_to
%253Dhttps%253A%252F%252Fevil.cloudapp.net%252Fcb HTTP/1.1
Redirect_to https://evil.cloudapp.net
настраивает конечную точку авторизации для перенаправления токена на домен, находящийся под контролем злоумышленника. Сервер авторизации теперь сначала перенаправит на фактический сайт приложения:
Location: https://app.cloudapp.net/cb?redirect_to%3Dhttps%3A%2F%2Fevil.cloudapp.net%2Fcb#access_token=LdKgJIfEWR34aslkf&...
Когда этот запрос поступает на открытый редиректор, он извлекает URL-адрес перенаправления evil.cloudapp.net,
а затем перенаправляет на сайт злоумышленника:
https://evil.cloudapp.net/cb#access_token=LdKgJIfEWR34aslkf&...
Абсолютное соответствие URL-адресов также смягчит эту атаку.
6. Резюме
В этой статье мы обсудили класс атак на протокол OAuth, основанных на URL-адресах перенаправления.
Хотя это может иметь серьезные последствия, использование абсолютного сопоставления URL-адресов на сервере авторизации смягчает атаки этого класса.