Below is a more comprehensive Delphi example that demonstrates custom endpoints, challenge policies, database-backed credential storage, FIDO Metadata validation, and cross-origin iframe support. The code highlights advanced event handling to enforce security policies.
sgcWebSockets WebAuthn 서버 예제
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;
이벤트 구현
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;
주요 특징
- 챌린지 무작위성 – 모든 챌린지는 서버가 내부적으로 생성하는 32바이트의 암호학적으로 안전한 난수이며, 16진수로 인코딩돼요. 추가 설정 없이도 이미 재생 공격에 강해요.
- 커스텀 사용자 핸들 – 고유한 바이너리 사용자 핸들을 지정하면 인증자가 사용자 이름과 독립된 개인 정보 보호 식별자를 저장할 수 있어요.
- 메타데이터 기반 증명 검증 –
ValidateAttestationWithMDS루틴은 인증자 모델, 상태 보고서, 해지 목록을 교차 확인해 신뢰할 수 있는 디바이스만 등록되도록 해요. - 서명 카운터 적용 –
AuthnSuccess는 인증자의 카운터를 엄격하게 증가시키지 않는 응답을 거부해 복제된 자격 증명을 감지해요. - 데이터베이스 통합 – 자격 증명 데이터, 서명 카운터, 세션 토큰이 외부 지속성 함수를 통해 저장 및 업데이트되어 실제 백엔드와 컴포넌트를 통합하는 방법을 보여줘요.
- 교차 출처 iframe 지원 –
AllowCrossOrigins와 설정된TopOrigins를 통해 활성화되며, 내장 프레임에서 시작된 WebAuthn 흐름(예: 다른 도메인의 로그인 위젯)을 허용해요. - 증명 정책 – MDS와 결합된 직접 증명은 승인된 인증자만 등록할 수 있도록 해 엔터프라이즈 규정 준수 시나리오에 유용해요.
- 전송 선택 – 표시되지 않았지만 이벤트는 허용 가능한 전송(예:
USB,NFC,BLE)을 제한해 허용되는 인증자 유형을 조정할 수 있어요.
