Voici un exemple Delphi plus complet qui démontre des endpoints personnalisés, des politiques de challenge, le stockage d'identifiants en base de données, la validation des métadonnées FIDO, et la prise en charge des iframes cross-origin. Le code met en avant une gestion avancée des événements pour appliquer des politiques de sécurité.
sgcWebSockets serveur WebAuthn Exemple
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;
Implémentations d'événements
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;
Points clés
- Aléa du challenge – Chaque challenge est généré en interne par le serveur sous forme de 32 octets aléatoires cryptographiquement sûrs, encodés en hexadécimal, ce qui résiste déjà aux attaques par rejeu sans configuration supplémentaire.
- Identifiants utilisateur personnalisés – Attribuer un identifiant utilisateur binaire unique permet à l'authenticator de store a privacy-preserving identifier independent de usernames.
- Metadata-Based Attestation Validation – Le
ValidateAttestationWithMDSroutine cross-checks authenticator model, status reports, et revocation lists, ensuring seulement trusted devices are registered. - Sign Counter Enforcement –
AuthnSuccessrejects responses que ne pas strictly increment le authenticator's counter, detecting cloned credentials. - Base de données Integration – Credential data, sign counters, et session tokens are stored et updated via external persistence functions, demonstrating comment integrate le composant avec un real-world backend.
- Cross-Origin Iframe Support – Enabled through
AllowCrossOriginset configuredTopOrigins, allowing WebAuthn flows initiated depuis embedded frames (par ex. login widget on different domain). - Attestation Policy – Direct attestation coupled avec MDS ensures seulement approved authenticators peut register, useful for enterprise compliance scenarios.
- Transport Selection – Though not shown, événements peut constrain acceptable transports (par ex.
USB,NFC,BLE) to tailor qui types de authenticators are permitted.
