Delphi'de Passkeys: WebAuthn ile Parolasız Giriş

· Bileşenler
Delphi'de Passkeys: WebAuthn ile Parolasız Giriş

Uygulamanızın kabul ettiği her parola tahmin edilebilir, başka bir sitede yeniden kullanılabilir, sahte bir giriş sayfasına yazılabilir veya bir veritabanı yedeğinden sızdırılabilir. Passkey'ler bu dört sorunu birden ortadan kaldırır. Kullanıcı, telefonu veya dizüstü bilgisayarı zaten kilidini açan parmak izi, yüz veya PIN ile oturum açar ve sunucunuzda çalmaya değer bir sır kalmaz.

Yeni giriş bileşenlerine genel bakış yazısında passkey'ler yalnızca beş madde aldı, SAML yazısı ise kendi identity provider'ını işleten şirketler için oturum açmayı ele aldı. Bu yazı parolasız tarafı anlatıyor: TsgcWSAPIServer_WebAuthn passkey'leri nasıl kaydeder, kullanıcıları kullanıcı adı olmadan nasıl oturum açtırır, passkey'leri tarayıcının otomatik doldurma listesinde nasıl gösterir ve her credential'ı kendi veritabanınızda nasıl saklar.

Passkey Nedir

Passkey, kullanıcının authenticator'ı tarafından oluşturulan bir anahtar çiftidir: Windows Hello, iCloud Anahtar Zinciri, Google Şifre Yöneticisi, bir parola yöneticisi veya bir FIDO2 güvenlik anahtarı. Özel anahtar hiçbir zaman authenticator'dan çıkmaz. Sunucunuz yalnızca genel anahtarı saklar, bu yüzden sızdırılan bir passkey tablosu kimsenin oturum açmasına izin vermez. Her imza sitenizin domainine bağlıdır, bu yüzden benzer görünümlü bir oltalama domaini kullanabileceği hiçbir şey elde edemez. Burada kimlik avına dayanıklı ifadesinin anlamı budur.

WebAuthn terimleriyle bir passkey, keşfedilebilir bir credentialdir, resident key olarak da adlandırılır. Authenticator, userHandle'ı özel anahtarın yanında tutar; bu yüzden kullanıcı bir kullanıcı adı yazmadan oturum açabilir ve tarayıcı sitenizin passkey'lerini kendi başına listeleyebilir.

Keşfedilebilir Credential'lar İsteme

WebAuthn güvenli bir bağlam gerektirir, bu yüzden sayfalarınızı https üzerinden, geliştirme sırasında ise localhost'tan sunun ve WebAuthnOptions.RelyingParty değerini tarayıcının gösterdiği host adına ayarlayın. Kayıt seçeneklerinin istediği residentKey, WebAuthnOptions.DefaultOptions.Registration.DiscoverableCredential değerinden gelir:

Tek bir kayıt isteği, discoverable_credential alanını required, preferred veya discouraged olarak ayarlayarak varsayılan değeri yine de geçersiz kılabilir.

Kullanıcı Adı Olmadan Oturum Açma

Kimlik doğrulama seçeneklerini boş bir kullanıcı adıyla isteyin. Bu durumda seçenekler herhangi bir allowCredentials listesi taşımaz, tarayıcı relying party'niz için sahip olduğu passkey'leri gösterir ve kullanıcı bunlardan birini seçer. Yazılacak hiçbir şey olmadığından yanlış yazılacak hiçbir şey de yoktur.

Bu kez credential'ı sunucu seçmediği için daha fazla kontrol yapar. Yanıt userHandle'ı içermelidir, userHandle imzalayan credential'a ait olmalıdır ve uygulamanızın tanımadığı bir credential reddedilir.

Otomatik Doldurma Listesindeki Passkey'ler

Otomatik doldurma, yani conditional mediation, sitenizin passkey'lerini kayıtlı parolaların yanında kullanıcı adı alanının öneri listesine yerleştirir. Bu, kullanıcıları geçirmenin yumuşak yoludur: giriş sayfası parolası olan kişiler için çalışmaya devam eder, passkey'i olan kişiler ise listeden seçer.

Otomatik doldurma, conditional mediation'ı destekleyen bir tarayıcı gerektirir; bu da bugün için Chrome, Edge ve Safari'nin güncel sürümleri anlamına gelir. browserSupportsWebAuthnAutofill() diğerlerinde False döndürür, bu yüzden sayfada ayrıca bir “Passkey ile giriş yap” düğmesi de bulundurun.

Birden Çok Passkey, Tek Bir userHandle

Gerçek kullanıcıların birden fazla passkey'i vardır: dizüstü bilgisayarda biri, telefonda biri, belki ikisinin de kaybolduğu gün için bir güvenlik anahtarı. Her birini aynı kullanıcı adıyla kaydedin. Bu kullanıcı adının sunucunun zaten bildiği credential'ları varsa, yeni kayıt onların userHandle'ını (user.id) yeniden kullanır, böylece hesabın her passkey'i tek bir userHandle'ı paylaşır ve hepsi aynı kullanıcıya götürür.

Sunucu, çalışırken kaydedilen credential'ları ve AddCredential ile eklediklerinizi bilir. Passkey'leriniz bir veritabanında yaşıyorsa, her hesabın tek bir userHandle'ı korumasını sağlamak için bunları başlangıçta ekleyin. Bir kullanıcı gerçekten bir kullanıcı adı yazdığında, kimlik doğrulama seçenekleri o kullanıcının her passkey'ini allowCredentials içinde listeler ve authenticator elindekini kullanır.

Passkey'leri Kendi Veritabanınızda Saklayın

Bileşen credential'ları kalıcı hale getirmez. Passkey'leriniz kullanıcılar tablonuzun yanında yer alır ve dört olay ikisini birbirine bağlar:

Bir passkey'i kaydetmek ve geri yüklemek iki kısa handler'dan oluşur:

uses
  sgcWebAuthn_Classes;

// registration: store the whole record, keyed by its credential id
procedure TForm1.WebAuthnWebAuthnRegistrationSuccessful(Sender: TObject;
  const aRegistration: TsgcWebAuthn_Registration;
  const aCredentialRecord: TsgcWebAuthn_CredentialRecord; var Accept: Boolean);
begin
  DBInsertPasskey(aCredentialRecord.CredentialId, aCredentialRecord.Username,
    aCredentialRecord.AsJSON);
end;

// usernameless and autofill sign-in: the browser chose the passkey,
// find it by its credential id and hand it back to the server
procedure TForm1.WebAuthnWebAuthnAuthenticationGetCredential(Sender: TObject;
  const aCredentialId: string;
  const aCredentialRecord: TsgcWebAuthn_CredentialRecord; var Found: Boolean);
var
  vJSON: string;
begin
  Found := DBFindPasskey(aCredentialId, vJSON);
  if Found then
    aCredentialRecord.ReadJSON(vJSON);
end;

DBInsertPasskey ve DBFindPasskey, kendi veri erişim kodunuzu temsil eder. Döndürdüğünüz kayıt istenen CredentialId'yi ve ceremony bir kullanıcı adıyla başladıysa aynı Username'i taşımalıdır, aksi halde oturum açma başarısız olur. Sunucu, authenticator'ın gönderdiği userHandle ile karşılaştırdığından, saklanan kayıtta UserId'yi de tutun. Olaylar sunucunun bağlantı thread'lerinde çalışır, bu yüzden paylaşılan kaynakları sunucunun başka herhangi bir yerinde koruduğunuz gibi koruyun.

Senkronize mi, Cihaza Bağlı mı

Authenticator verisindeki bayraklar aldığınız passkey türünü söyler; credential kaydı bunları BackupEligible (BE bayrağı) ve BackupState (BS bayrağı) olarak saklar:

Politikanız bunlara farklı davranabilir, örneğin yönetici hesaplarında yalnızca cihaza bağlı güvenlik anahtarlarını kabul edebilir. Her oturum açmada sunucu, BS bayrağı ayarlanmış ve BE bayrağı ayarlanmamış bir yanıtı reddeder; ayrıca BE bayrağı saklanan BackupEligible değerinden farklı olan bir yanıtı da reddeder, çünkü bir credential'ın eligibility'si hiçbir zaman değişmez. Yeni BS bayrağı BackupState'e kopyalanır ve bunu kaydedeceğiniz yer OnWebAuthnAuthenticationSuccessful'dır.

İmza Sayacı ve Klonlanmış Authenticator'lar

Bazı authenticator'lar her oturum açmada bir imza sayacını artırır. Yanıttaki sayaç veya saklanan SignCount sıfır değilse, yanıttaki sayaç saklanan değerden büyük olmalıdır. Değilse oturum açma reddedilir, çünkü aynı anahtarla yanıt veren iki authenticator, tam olarak klonlanmış bir authenticator'ın görünümüdür.

Bu kontrol yalnızca sayacı her oturum açmadan sonra kaydederseniz ve saklanan değer yalnızca ileri doğru ilerlerse çalışır. Senkronize passkey'ler genellikle her seferinde 0 bildirir, bu da onlar için kontrolü devre dışı bırakır. Sayacı güvenilir biçimde artırmayan authenticator'larınız varsa, onları kabul etmek için WebAuthnOptions.AllowSignCountLessOrEqualStoredValue değerini True olarak ayarlayın. Saklanan değer yine de asla düşürülmez.

Demoyu Deneyin

Demo Demos\26.Authentication\01.Passkeys, eksiksiz bir relying party'dir: TsgcWSAPIServer_WebAuthn bağlı bir TsgcWebSocketHTTPServer, https://localhost:5443 üzerinde küçük bir giriş sayfası sunar. Yukarıdaki dört olay aracılığıyla her passkey'i kendi passkeys.json dosyasında saklar.

  1. Demoyu derleyin ve libcrypto-3.dll ile libssl-3.dll dosyalarını çalıştırılabilir dosyanın yanında tutun. Bunlar demo klasöründe bulunur.
  2. Host'u 127.0.0.1, portu 5443 ve relying party'yi localhost olarak bırakın, ardından Start'a tıklayın.
  3. Open Browser'a tıklayın ve kendinden imzalı test sertifikasını kabul edin.
  4. Bir kullanıcı adı yazın ve Register passkey'e tıklayın. Aynı kullanıcı adı için ikinci bir passkey kaydedin. Form, her passkey'i türüyle (senkronize veya cihaza bağlı) ve imza sayacıyla birlikte listeler.
  5. Sign in without user name'a tıklayın ve bir passkey seçin. Sunucu onu OnWebAuthnAuthenticationGetCredential aracılığıyla bulur ve günlük kullanıcıyı gösterir.
  6. Sayfayı yeniden yükleyin ve kullanıcı adı kutusuna tıklayın. Passkey'ler otomatik doldurma listesinde görünür. Oturum açmak için birini seçin.
  7. Uygulamayı yeniden başlatın. Passkey'ler passkeys.json dosyasından yeniden yüklenir; bu da depolamanın bileşene değil uygulamanıza ait olduğunu gösterir.

Belgeler

Nereden Edinilir

TsgcWSAPIServer_WebAuthn, Delphi ve C++ Builder için sgcWebSockets'in Enterprise ve All-Access sürümlerinde bulunur ve aynı bileşen sgcWebSockets .NET'in de bir parçasıdır. Yalnızca kimlik doğrulamaya ihtiyacınız varsa, sgcAuth paketi onu diğer giriş bileşenleriyle birlikte içerir. SGC Auth paletinde bulabilirsiniz ve bir forma sürükleyene kadar mevcut bir uygulamada hiçbir şey değişmez.

Sırada Ne Var

İzleyin

eSeGeCe kanalında “Passkeys in Delphi: passwordless login with WebAuthn” başlıklı kısa bir video var. Video, IDE'deki kodu, yedekleme bayraklarının ve imza sayacının size neler anlattığını ve https://localhost üzerinde çalışan demoyu gösteriyor: bir kullanıcı iki passkey kaydediyor, ardından bir kullanıcı adı yazmadan oturum açıyor.

Sorularınız mı var, geri bildiriminiz mi var, yoksa giriş sayfanıza passkey eklemek için yardıma mı ihtiyacınız var? Bize ulaşın. Kodu yazan kişilerden yanıt alacaksınız.