A partir de sgcWebSockets 2024.5.0 PKCE, que son las siglas de "Proof of Key Code Exchange", es una extensión del protocolo OAuth 2.0 que ayuda a prevenir ataques de interceptación del código.
PKCE está soportado tanto en los componentes servidor como cliente OAuth2.
Qué es PKCE
PKCE (Proof Key for Code Exchange) es una mejora de seguridad de OAuth 2.0 diseñada para proteger frente a ataques de interceptación del código de autorización en aplicaciones públicas o nativas. Se detalla en RFC 7636 y sirve como técnica de mitigación frente a la vulnerabilidad de "authorization code interception", especialmente en entornos en los que no se puede garantizar la confidencialidad de los client secrets, como aplicaciones móviles o de cliente.
En un flujo típico OAuth 2.0 Authorization Code Grant, una aplicación cliente obtiene un código de autorización redirigiendo al usuario a un servidor de autorización y, después, intercambia ese código por un access token. Sin embargo, si un atacante intercepta el código de autorización, podría usarlo para obtener el access token y acceder a recursos protegidos.
PKCE aborda este riesgo introduciendo un mecanismo de proof key. Los componentes clave de PKCE son:
- Code Verifier: cadena aleatoria de alta entropía generada por la aplicación cliente al inicio del flujo OAuth. El verifier debe tener al menos 43 caracteres y como mucho 128, usando caracteres no reservados (A-Z, a-z, 0-9, "-", ".", "_", "~").
- Code Challenge: versión derivada del code verifier, creada mediante un método de transformación. El método de transformación suele ser "S256", que indica un hash SHA-256, pero también puede ser "plain", en cuyo caso el code challenge coincide con el code verifier.
El flujo PKCE funciona así:
- La aplicación cliente genera un code verifier y deriva el code challenge a partir de él.
- La aplicación cliente inicia la petición de autorización OAuth incluyendo el code challenge y el método de code challenge (plain o S256).
- El servidor de autorización envía el código de autorización al cliente una vez que el usuario concede el acceso.
- Cuando la aplicación cliente envía el código de autorización al endpoint de token para intercambiarlo por un access token, también incluye el code verifier.
- El servidor de autorización verifica el code verifier aplicando el mismo método de transformación usado para crear el code challenge y comprueba si coincide con el code challenge almacenado.
- Si la verificación es correcta, el servidor de autorización emite el access token; en caso contrario, la petición se rechaza.
Este mecanismo garantiza que sólo el cliente con el code verifier original pueda intercambiar correctamente el código de autorización por un access token, aportando una capa robusta de seguridad a los flujos OAuth.
Cliente OAuth2 en Delphi
El componente TsgcHTTP_OAuth2_Client admite el flujo Authorization Code + PKCE. Para usar este tipo de autorización, configura la propiedad GrantType al valor auth2CodePKCE.
oAuth2 := TsgcHTTP2_OAuth2.Create(nil);
oAuth2.LocalServerOptions.Host := '127.0.0.1';
oAuth2.LocalServerOptions.Port := 8080;
oAuth2.AuthorizationServerOptions.AuthURL := 'https://accounts.google.com/o/oauth2/auth';
oAuth2.AuthorizationServerOptions.TokenURL := 'https://accounts.google.com/o/oauth2/token';
oAuth2.AuthorizationServerOptions.Scope.Add('https://mail.google.com/');
oAuth2.OAuth2Options.ClientId := '180803918357-eqjtn20gqfhcs6gjkebbrrenh022mqqc.apps.googleusercontent.com';
oAuth2.OAuth2Options.ClientSecret := '_by0iYYrvVHxC2Z8TbtNEYQN';
oAuth2.OAuth2Options.GrantType := auth2CodePKCE;
procedure OnOAuth2AfterAccessToken(Sender: TObject; const Access_Token, Token_Type, Expires_In,
Refresh_Token, Scope, RawParams: string; var Handled: Boolean);
begin
<...>
<...>
end;
oAuth2.OnAfterAccessToken := OnOAuth2AfterAccessToken;
oAuth2.Start;
Servidor OAuth2 en Delphi
El componente TsgcHTTP_OAuth2_Server admite PKCE por defecto (aunque se puede deshabilitar en la propiedad OAuth2Options.PKCE). Cuando el servidor detecta que el cliente OAuth2 está usando PKCE, validará que los valores PKCE son correctos; si no lo son, la respuesta devolverá un error.
A continuación tienes un enlace sobre cómo usar el servidor OAuth2 en Delphi.
