ASP .NET Core 3.1 - Usando o Identity de cabo a rabo - IX


Hoje vamos continuar a série de artigos mostrando como usar o ASP .NET Core Identiy na versão 3.1 da ASP .NET .Core e do EF Core.

Continuando a oitava parte do artigo veremos como redirecionar o usuário para uma URL solicitada após o login bem  sucedido e como prevenir do ataque de redirecionamento aberto.

Vamos entender o que acontece quando tentamos navegar para uma URL que não temos acesso até que façamos o login.

Quando isso ocorre, por padrão, a ASP .NET Core vai nos redirecionar para a URL de Login com um parâmetro querystring de consulta ReturnUrl.

Assim a URl que estávamos tentando acessar será o valor do parâmetro da stringde consulta ReturnUrl.

Para entender melhor esse comportamento vejamos um exemplo.

Neste exemplo o parâmetro ReturnUrl será definido como ReturnUrl=/funcionarios/create.

Assim vamos tentar criar um novo funcionário navegando para /funcinarios/create sem fazer o login.

Como não temos acesso a /funcionarios/create antes de fazer o login, a ASP .NET Core vai nos redirecionar para a URL de Login a qual é /Account/Login com o parâmetro query string ReturnUrl :


https://localhost:44325/Account/Login?ReturnUrl=%2Ffuncionarios%2Fcreate
 

Os caracteres %2F são caractetes codificado para uma barra(/).

Nota: Para decodificar esses caracteres na URL você pode usar este site: https://meyerweb.com/eric/tools/dencoder/

Este é o comportamento padrão.

Retornando para ReturnUrl após o Login

Veremos como a ASP .NET Core atua para realizar o redirecionamento.

O model binding da ASP .NET Core automaticamente faz o mapeamento para o valor:

  1. A partir do parâmetro querystring ReturnUrl da URL;
  2. para o parâmetro ReturnUrl do método Action Login;

Assim o método Redirect(ReturnUrl) redireciona o usuário para o returnUrl especificado.

Logo temos uma falha na maneira como usamos o parâmetro querystring ReturnUrl.

Isso abre um sério problema de segurança em nosso aplicativo, conhecido como vulnerabilidade de redirecionamento aberto.

Diante deste cenário nossa aplicação está vulnerável a ataques de redirecionamento aberto se as 2 condições a seguir forem verdadeiras :

O que é vulnerabilidade de redirecionamento aberto ?

A maioria das aplicações Web redireciona os usuários para uma página de login quando acessam recursos que requerem autenticação.

O redirecionamento inclui um parâmetro querystring returnUrl, para que o usuário possa retornar à URL solicitada originalmente depois de fazer login com êxito. Ex: http://teste.com/Account/Login?ReturnUrl=/pedidos/lista

Um usuário mal-intencionado pode usar esse parâmetro querystring returnUrl para iniciar um ataque de redirecionamento aberto.

Como ele pode fazer isso ? 

A seguir um roteiro básico que mostra como o ataque acontece:

      http://teste.com/account/login?returnUrl=http://testi.com/account/login
      (o returnUrl é "testi.com", em vez de "e", existe um "i")

Agora vejamos como prevenir este tipo de ataque.

Prevenindo os ataques de redirecionamento abertos

Temos uma vulnerabilidade de redirecionamento aberto porque, a URL é fornecida ao aplicativo a partir da cadeia de caracteres de consulta.

Estamos simplesmente redirecionando para esse URL sem nenhuma validação, o que está tornando nosso aplicativo vulnerável a ataques de redirecionamento aberto.

Para evitar ataques de redirecionamento aberto, temos que verificar se a URL fornecida é um URL local ou se você está redirecionando apenas para sites confiáveis conhecidos.

Nota: Uma URL é considerado local se não tiver uma parte de host/autoridade e tiver um caminho absoluto. URLs usando caminhos virtuais ('~/') também são locais.

A ASP.NET Core possui suporte interno para redirecionamento local. Basta usar o método LocalRedirect(). Se uma URL não local for especificado, uma exceção será lançada.

public IActionResult Login(string returnUrl)
{
    return LocalRedirect(returnUrl);
}

Para verificar se uma URL fornecida é uma URL local, podemos usar o método IsLocalUrl():

public IActionResult Login(string returnUrl)
{
    if (Url.IsLocalUrl(returnUrl))
    {
         return Redirect(returnUrl);
    }
    else
    {
       return RedirectToAction("index", "home");
    }
}

No próximo artigo veremos a validação do lado do cliente.

"Portanto, não te envergonhes do testemunho de nosso Senhor, nem de mim, que sou prisioneiro seu; antes participa das aflições do evangelho segundo o poder de Deus,
Que nos salvou, e chamou com uma santa vocação; não segundo as nossas obras, mas segundo o seu próprio propósito e graça que nos foi dada em Cristo Jesus antes dos tempos dos séculos;"
2 Timóteo 1:8,9

Referências:


José Carlos Macoratti