Spring Security - Atacando o OAuth
1. Introdução
OAuth é a estrutura padrão do setor para autorização delegada. Muito pensamento e cuidado foram aplicados na criação dos vários fluxos que compõem o padrão. Mesmo assim, não é sem vulnerabilidade.
Nesta série de artigos, discutiremos ataques contra OAuth de um ponto de vista teórico e descreveremos várias opções que existem para proteger nossos aplicativos.
2. A concessão do código de autorização
O fluxoAuthorization Code Grant é o fluxo padrão usado pela maioria dos aplicativos que implementam a autorização delegada.
Antes que esse fluxo comece, o cliente deve ter pré-registrado no servidor de autorização e, durante este processo, ele também deve ter fornecido uma URL de redirecionamento - ou seja,a URL on which the Authorization Server can call back into the Client with an Authorization Code.
Vamos dar uma olhada mais de perto em como funciona e o que alguns desses termos significam.
Durante um fluxo de concessão de código de autorização, um cliente (o aplicativo que está solicitando autorização delegada) redireciona o proprietário do recurso (usuário) para um servidor de autorização (por exemplo,Login with Google). Após o login, o servidor de autorizaçãoredirects back to the client with an Authorization Code.
Em seguida, o cliente chama um terminal no Servidor de Autorização, solicitando um Token de Acesso, fornecendo o Código de Autorização. Nesse ponto, o fluxo termina e o cliente pode usar o token para acessar os recursos protegidos pelo Servidor de Autorização.
Agora,the OAuth 2.0 Framework allows for these Clients to be public, digamos em cenários onde o cliente não pode segurar com segurança um segredo do cliente. Vamos dar uma olhada em alguns ataques de redirecionamento que são possíveis contra clientes públicos.
3. Ataques de redirecionamento
3.1. Pré-condições de ataque
Os ataques de redirecionamento dependem do fato de quethe OAuth standard doesn’t fully describe the extent to which this redirect URL must be specified. Isso ocorre por design.
Isso permite algumas implementações do protocolo OAuth para permitir um URL de redirecionamento parcial.
Por exemplo, se registrarmos uma ID de cliente e uma URL de redirecionamento de cliente com a seguinte correspondência baseada em curinga em um servidor de autorização:
* .cloudapp.net
Isso seria válido para:
app.cloudapp.net
mas também para:
evil.cloudapp.net
Selecionamos o domíniocloudapp.net propositalmente, pois este é um local real onde podemos hospedar aplicativos baseados em OAuth. O domínio faz parte deMicrosoft’s Windows Azure platforme permite que qualquer desenvolvedor hospede um subdomínio sob ele para testar um aplicativo. Isso em si não é um problema, mas é uma parte vital da exploração maior.
A segunda parte dessa exploração é um servidor de autorização que permite a correspondência de caracteres curinga nos URLs de retorno de chamada.
Finalmente, para realizar esse exploit, o desenvolvedor do aplicativo precisa se registrar no servidor de autorização para aceitar qualquer URL no domínio principal, no formato*.cloudapp.net.
3.2. O ataque
Quando essas condições são atendidas, o invasor precisa enganar o usuário para iniciar uma página do subdomínio sob seu controle, por exemplo, enviandothe user an authentic looking email pedindo que ele execute alguma ação na conta protegida por OAuth. Normalmente, seria algo comohttps://evil.cloudapp.net/login. Quando o usuário abre esse link e seleciona o login, ele será redirecionado para o Authorization Server com uma solicitação de autorização:
GET /authorize?response_type=code&client_id={apps-client-id}&state={state}&redirect_uri=https%3A%2F%2Fevil.cloudapp.net%2Fcb HTTP/1.1
Embora isso possa parecer típico, este URL é malicioso. Veja, neste caso, o Authorization Serverreceives a doctored URL with the app’s Client IDe uma URL de redirecionamento apontando de volta para o appevil’s.
O Servidor de Autorização validará o URL, que é um subdomínio no domínio principal especificado. Como o Servidor de Autorização acredita que a solicitação foi originada de uma fonte válida, ele autenticará o usuário e solicitará o consentimento, como faria normalmente.
Depois que isso for feito, ele irá redirecionar de volta para o subdomínioevil.cloudapp.net, entregando o código de autorização ao invasor.
Como o invasor agora tem o Código de Autorização, tudo o que ele precisa fazer é chamar o ponto de extremidade do token do Servidor de Autorização com o Código de Autorização para receber um token, que permite a ele acesso aos recursos protegidos do Proprietário do Recurso.
4. Avaliação da Vulnerabilidade no Servidor de Autorização Spring OAuth
Vamos dar uma olhada em uma configuração simples do Spring OAuth Authorization Server:
@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");
}
// ...
}
Podemos ver aqui que o Authorization Server está configurando um novo cliente com o id“apricot-client-id”. Não há segredo do cliente, portanto este é um Cliente Público.
Our security ears should perk up at this, já que agora temos duas das três condições - pessoas más podem registrar subdomíniosand, estamos usando um Cliente Público.
Mas, observe que estamos configurandothe redirect URL here too and that it’s absolute. Podemos mitigar a vulnerabilidade fazendo isso.
4.1. Rigoroso
Por padrão, o Spring OAuth permite um certo grau de flexibilidade na correspondência de URL de redirecionamento.
Por exemplo,DefaultRedirectResolver suporta correspondência de subdomínio.
Let’s only use what we need. E se pudermos corresponder exatamente ao URL de redirecionamento, devemos fazer:
@Configuration
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
//...
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.redirectResolver(new ExactMatchRedirectResolver());
}
}
Nesse caso, passamos a usarExactMatchRedirectResolver para URLs de redirecionamento. Esse resolvedor faz uma correspondência exata de sequência, sem analisar o URL de redirecionamento de forma alguma. This makes its behavior far more secure and certain.
4.2. Leniente
Podemos encontrar o código padrão que lida com a correspondência de URL de redirecionamento noSpring Security OAuth source:
/**
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
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;
}
Podemos ver que a correspondência de URL é feita analisando o URL de redirecionamento recebido em suas partes componentes. Isso é bastante complexo devido a seus vários recursos,like whether the port, subdomain, and query parameters should match. E escolher permitir correspondências de subdomínio é algo para se pensar duas vezes.
Claro, essa flexibilidade existe, se precisarmos - vamos apenas usá-la com cautela.
5. Ataques implícitos de redirecionamento de fluxo
To be clear, the Implicit Flow isn’t recommended. É muito melhor usar o fluxo de Concessão do Código de Autorização com segurança adicional fornecida porPKCE. Dito isso, vamos dar uma olhada em como um ataque de redirecionamento se manifesta com o fluxo implícito.
Um ataque de redirecionamento contra um fluxo implícito seguiria o mesmo esquema básico que vimos acima. A principal diferença é que o invasor obtém o token imediatamente, pois não há etapa de troca de código de autorização.
Como antes, uma correspondência absoluta do URL de redirecionamento também mitigará essa classe de ataque.
Além disso, podemos descobrir que o fluxo implícito contém outra vulnerabilidade relacionada. An attacker can use a client as an open redirector and get it to reattach fragments.
O ataque começa como antes, com um invasor fazendo com que o usuário visite uma página sob o controle do invasor, por exemplo,https://evil.cloudapp.net/info. A página foi criada para iniciar uma solicitação de autorização como antes. No entanto, agora inclui um URL de redirecionamento:
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
Oredirect_to https://evil.cloudapp.net está configurando o Endpoint de autorização para redirecionar o token para um domínio sob o controle do invasor. O servidor de autorização agora redirecionará primeiro para o site do aplicativo real:
Location: https://app.cloudapp.net/cb?redirect_to%3Dhttps%3A%2F%2Fevil.cloudapp.net%2Fcb#access_token=LdKgJIfEWR34aslkf&...
Quando essa solicitação chega no redirecionador aberto, ele extrai o URL de redirecionamentoevil.cloudapp.net e, em seguida, redireciona para o site do invasor:
https://evil.cloudapp.net/cb#access_token=LdKgJIfEWR34aslkf&...
A correspondência absoluta de URL também atenuará esse ataque.
6. Sumário
Neste artigo, discutimos uma classe de ataques contra o protocolo OAuth que são baseados em URLs de redirecionamento.
Embora isso tenha consequências potencialmente graves, o uso da correspondência absoluta de URL no servidor de autorização atenua essa classe de ataque.