WebAuthn: ejemplo de uso avanzado

· Componentes
WebAuthn: ejemplo de uso avanzado | Blog eSeGeCe

A continuación se muestra un ejemplo más completo en Delphi que demuestra endpoints personalizados, políticas de challenge, almacenamiento de credenciales en base de datos, validación con FIDO Metadata y soporte de iframes cross-origin. El código resalta el manejo avanzado de eventos para aplicar políticas de seguridad. 

Ejemplo de servidor WebAuthn con sgcWebSockets

procedure TForm1.ConfigureWebAuthn;
begin
  // Component setup
  FWebAuthn := TsgcWSServer_API_WebAuthn.Create(nil);
  FWebAuthn.Server := FHTTPServer;
  FWebAuthn.Enabled := True;
  // Endpoint remapping
  FWebAuthn.EndpointsOptions.AuthenticationOptions.Endpoint := '/auth/options';
  FWebAuthn.EndpointsOptions.AuthenticationVerify.Endpoint  := '/auth/verify';
  FWebAuthn.EndpointsOptions.RegistrationOptions.Endpoint   := '/reg/options';
  FWebAuthn.EndpointsOptions.RegistrationVerify.Endpoint    := '/reg/verify';
  // Relying-party definition
  with FWebAuthn.WebAuthnOptions do
  begin
    RelyingParty := 'secure.example.com';
    Origins.Origins.Text      := 'https://app.example.com'#13#10'https://login.example.net';
    Origins.TopOrigins.Text   := 'https://host.example.org';
    Origins.AllowCrossOrigins := True;
    // Cryptographic & UX policies
    Algorithms                                   := [waunalgES256, waunalgRS256];
    DefaultOptions.Registration.UserVerification := waunuvPreferred;
    DefaultOptions.Registration.Attestation      := waunaDirect;
    Timeout                                      := 60000;
    // Challenge: 32 CSPRNG-random bytes, hex-encoded, generated internally by
    // the server; not configurable. Override Response.Challenge instead, in
    // OnWebAuthnRegistrationOptionsResponse / OnWebAuthnAuthenticationOptionsResponse.
    // Metadata Service configuration
    MDS.Enabled            := True;
    MDS.MDS_FileName       := 'mds.json';
    MDS.RootCert_FileName  := 'root.pem';
  end;
  // Hook events
  FWebAuthn.OnWebAuthnRegistrationOptionsRequest := AuthnRegOptionsRequest;
  FWebAuthn.OnWebAuthnRegistrationOptionsResponse := AuthnRegOptionsResponse;
  FWebAuthn.OnWebAuthnRegistrationValidateCertificate := AuthnRegVerify;
  FWebAuthn.OnWebAuthnRegistrationSuccessful     := AuthnRegSuccess;
  FWebAuthn.OnWebAuthnAuthenticationOptionsRequest := AuthnOptionsRequest;
  FWebAuthn.OnWebAuthnAuthenticationSuccessful     := AuthnSuccess;
end;

Implementaciones de eventos

procedure TForm1.AuthnRegOptionsRequest(Sender: TObject;
  const Request: TsgcWebAuthn_RegistrationOptions_Request; var Accept: Boolean);
begin
  // Verify user is eligible for registration
  Accept := not UserExists(Request.Username);
end;
procedure TForm1.AuthnRegOptionsResponse(Sender: TObject;
  const Request: TsgcWebAuthn_RegistrationOptions_Request;
  const Response: TsgcWebAuthn_RegistrationOptions_Response);
begin
  // Optionally assign a user handle (binary identifier)
  Response.User.Id := HexToBin(UserGUIDToHex(GenerateGUID));
  Response.AuthenticatorSelection.AuthenticatorAttachment := 'platform';
end;
procedure TForm1.AuthnRegVerify(Sender: TObject;
  const Request: TsgcWebAuthn_RegistrationVerify_Request;
  const Validate: TsgcWebAuthnValidateAttestationStatement; var Accept: Boolean);
begin
  // Perform extra attestation validation against MDS entries
  Accept := ValidateAttestationWithMDS(Validate);
end;
procedure TForm1.AuthnRegSuccess(Sender: TObject;
  const Registration: TsgcWebAuthn_Registration;
  const CredentialRecord: TsgcWebAuthn_CredentialRecord; var Accept: Boolean);
begin
  // Persist credential details in database
  SaveCredentialToDB(
    CredentialRecord.Username,
    CredentialRecord.CredentialId,
    CredentialRecord.PublicKey,
    CredentialRecord.SignCount,
    CredentialRecord.UserId
  );
  Accept := True;
end;
procedure TForm1.AuthnOptionsRequest(Sender: TObject;
  const Request: TsgcWebAuthn_AuthenticationOptions_Request;
  var CredentialRecords: TsgcWebAuthn_CredentialRecords; var Accept: Boolean);
begin
  // Retrieve all credential records for user
  CredentialRecords := LoadCredentialRecordsFromDB(Request.Username);
  Accept := True;
end;
procedure TForm1.AuthnSuccess(Sender: TObject;
  const Request: TsgcWebAuthn_AuthenticationVerify_Request;
  const Authentication: TsgcWebAuthn_Authentication; var Accept: Boolean);
var
  StoredCounter: Cardinal;
begin
  // Ensure sign counter increases
  StoredCounter := GetSignCounterFromDB(Authentication.Credential.CredentialRecord.CredentialId);
  Accept := Authentication.Credential.CredentialRecord.SignCount > StoredCounter;
  if Accept then
  begin
    UpdateSignCounterInDB(Authentication.Credential.CredentialRecord.CredentialId,
      Authentication.Credential.CredentialRecord.SignCount);
    IssueSessionToken(Authentication.Credential.CredentialRecord.Username);
  end;
end;

Puntos destacados

  1. Aleatoriedad del challenge – Cada challenge se genera internamente en el servidor como 32 bytes aleatorios criptográficamente seguros, codificados en hexadecimal, lo que ya resiste los ataques de replay sin configuración adicional.
  2. User handles personalizados – Asignar un user handle binario único permite que el autenticador almacene un identificador respetuoso con la privacidad, independiente de los nombres de usuario.
  3. Validación de atestación basada en metadatos – La rutina ValidateAttestationWithMDS verifica el modelo del autenticador, los informes de estado y las listas de revocación, garantizando que solo se registren dispositivos de confianza.
  4. Aplicación estricta del contador de firmas – AuthnSuccess rechaza respuestas que no incrementen estrictamente el contador del autenticador, detectando credenciales clonadas.
  5. Integración con base de datos – Los datos de credenciales, los contadores de firmas y los tokens de sesión se almacenan y actualizan mediante funciones externas de persistencia, mostrando cómo integrar el componente con un backend real.
  6. Soporte de iframe cross-origin – Se activa con AllowCrossOrigins y configurando TopOrigins, lo que permite flujos WebAuthn iniciados desde frames incrustados (p. ej., un widget de inicio de sesión en un dominio distinto).
  7. Política de atestación – La atestación directa junto con MDS asegura que solo se puedan registrar autenticadores aprobados, útil para escenarios de cumplimiento empresarial.
  8. Selección de transporte – Aunque no se muestra, los eventos pueden restringir los transportes aceptables (p. ej., USB,NFC,BLE) para acotar qué tipos de autenticadores se permiten.