ASP.NET Core 3.1 - IdentityServer4 - Client-Security-PKCE (Parte 11)

Na Parte 10 eu falei um pouco mais sobre segurança, não teve tanto código, mas foi um bom momento para todos entenderem que quando se fala de segurança, o pessoal que está sempre em busca de furos é muito criativo!

Vou focar agora na configuração e no funcionamento do PKCE (Proof Key for Code Exchange) que falei no finalzinho do post anterior, pois é ele que vai salvar a segurança da nossa aplicação MVC que está trabalhando em conjunto com o IdentityServer4 e para isso precisamos fazer algumas implementações e criar um Client novo para separar o GrantType.

PKCE

Ao habilitar o PKCE é obrigatório que você implemente o code_challenge, code_challenge_method (opcional) e o code_verifier, isso significa que o Client precisa controlar por requisição (request) um código aleatório, criar um código aleatório que nada mais será do que um hash utilizando o SHA256. Você pode obter maiores detalhes aqui.

Configuração do Client + PKCE

No IdentityServer4, lá na classe IdentityServerSeed eu criei mais 2 Clients, ambos com suporte ao PKCE: RequiredPkce = true conforme o código a seguir.

Um deles possui o AllowedGrantTypes = GrantTypes.Code, isso vai impossibilitar que através da aplicação MVC a API de Pagamento possa ser chamada, pois não há suporte ao tipo ClientCredentials, ou seja, não teremos o access_token. E configurei também um Client que possui o tipo GrantTypes.CodeAndClientCredentials.

PS: Ao habilitar o PKCE, somente o tipo Code e Hybrid vão funcionar, as outras opções possuem problemas de segurança que já falamos nos posts anteriores. Se você seguir os exemplos e o código vai dar certo, pois tudo foi testado.

Aplicação MVC

Na aplicação MVC, fiz algumas alterações no arquivo Startup.cs conforme a seguir:

  • Alterei o ClientId e ClientSecret para o Client que foi criado e que permite acessar a API de Pagamento;
  • Habilitei o o.UsePkce = true na configuração do serviço do OpenIdConnect;
  • Especifiquei qual o o.ResponseType = OpenIdConnectResponseType.Codee o.ResponseMode = OpenIdConnectResponseMode.FormPost

Code Challenge e Code Verifier

Não há como falar de um sem falar do outro, então vamos entender o funcionamento desse code flow.

  1. A aplicação cliente (MVC) requisita ao IdentityServer4 a autorização de acesso enviando o code_challenge e o code_challenge_method.
  2. O IdentityServer4 ao qual o Client em seu cadastro já indica que o PKCE está habilitado, identifica o uso do code_challenge e do code_challenge_method e permite o acesso através do código de authorização.
  3. A aplicação cliente (MVC) envia o token de acesso juntamente com o code_verifier.
  4. O IdentityServer4 valida o code_verifier juntamente com o code_challenge e code_challenge_method e disponibiliza o access token se a validação teve sucesso.

Code Verifier: O code verifier deve ser um high-entropy cryptographic random string com no mínimo 43 e no máximo de 128 caracteres, apenas aceita A-Z, a-z, 0-9, - (hífem), . (ponto), _ (underline) e ~

Code Challenge: O code challenge é criado a partir do SHA256 do code verifier e convertido para Base64Url. Caso não seja possível o code verifier pode ser usado ao natural, sem passar por essa transformação.

Code Challenge Method: O code challenge method é opcional, podemos usar o valor "S256" quando code challenge passar pela transformação acima ou "plain" (default) quando o code challenge for igual ao code verifier.

Todo esse processo funciona, pois o code challenge ou o code verifier não pode ser interceptado, visto que eles podem ser utilizados uma única fez. Toda vez que uma solicitação de autorização for feita, um novo code challenge precisa ser enviado.

Na configuração do serviço do OpenIdConnec no arquivo Startup.cs você pode ver esta configuração funcionando nas funções OnRedirectToIdentityProvider e OnAuthorizationCodeReceived.

Eu utilizei o pacote NuGet abaixo para facilitar:

IdentityModel

A RFC 7636 possui todos os detalhes do protocolo.

Sugiro você baixar o projeto, acesse o código fonte no GitHub.

Continua em ASP.NET Core 3.1 - IdentityServer4 - Digital Certificate On Azure (Parte 12).