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
- 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.
- 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.
- Validación de atestación basada en metadatos – La rutina
ValidateAttestationWithMDSverifica el modelo del autenticador, los informes de estado y las listas de revocación, garantizando que solo se registren dispositivos de confianza. - Aplicación estricta del contador de firmas –
AuthnSuccessrechaza respuestas que no incrementen estrictamente el contador del autenticador, detectando credenciales clonadas. - 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.
- Soporte de iframe cross-origin – Se activa con
AllowCrossOriginsy configurandoTopOrigins, lo que permite flujos WebAuthn iniciados desde frames incrustados (p. ej., un widget de inicio de sesión en un dominio distinto). - 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.
- 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.
