Kimlik doğrulama etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Kimlik doğrulama etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

10 Ekim 2025 Cuma

Passkeys ile Şifresiz Giriş: WebAuthn + FIDO2 ile Adım Adım Uygulama Rehberi

Passkey nedir ve neden şimdi?

Parola sızıntıları, oltalama (phishing) ve zayıf parola alışkanlıkları yıllardır güvenlik ekosisteminin en zayıf halkası. Passkey, FIDO2 standartları ve WebAuthn API’si üzerine inşa edilen, kullanıcıların yalnızca cihazlarındaki biyometrik doğrulama (parmak izi, Face ID, Windows Hello) veya PIN ile oturum açmasını sağlayan şifresiz bir yöntemdir. Parolalar yok, tek kullanımlık SMS kodları yok; kriptografik anahtar çifti ve tarayıcı desteği var. Apple, Google ve Microsoft’un ekosistemlerinde senkronize edilebilen passkey’ler hem güvenliği hem de dönüşüm oranlarını artırır.

Bu rehberde, modern bir web uygulamasına passkey tabanlı kayıt ve giriş akışını nasıl ekleyeceğinizi, hangi teknik ayrıntılara dikkat etmeniz gerektiğini ve yaygın hataları nasıl önleyeceğinizi anlatıyorum. Anlatım sade, adımlar somut; odak noktamız uygulanabilirlik.

Mimariye hızlı bakış

WebAuthn, üç aktörle çalışır: Relying Party (siteniz), istemci (tarayıcı) ve authenticator (platform veya harici anahtar). Kayıt sırasında site, tarayıcıya bir challenge ve ayarlar gönderir; cihazda bir anahtar çifti oluşturulur, siteniz genel anahtarı güvenli şekilde kaydeder. Girişte, site bir challenge ile imza ister; cihaz, kullanıcı doğrulaması sonrası imzayı üretir ve siteniz bunu doğrular. Parola asla yok; kimlik doğrulama domain’e (rpId) bağlı olduğu için oltalama büyük ölçüde engellenir.

Önkoşullar ve kurulum gereksinimleri

- HTTPS zorunlu: WebAuthn yalnızca güvenli origin’lerde çalışır. Geliştirme için localhost istisnadır.

- rpId ve origin: rpId genellikle alan adınızdır (ör. example.com). Alt alanlardan çağırıyorsanız bunu planlayın.

- Session ve CSRF: Challenge değerlerini oturumda tutun; her istek için taze ve tekil challenge üretin. SameSite=Lax/Strict çerezleri tercih edin.

- Tarayıcı desteği: Chrome, Edge, Safari ve Firefox güncel sürümlerde passkey destekliyor. iOS 16+, Android 9+ geniş kapsama sahip.

Kayıt akışı: Sunucu tarafı

1) Kullanıcı kayıt butonuna bastığında sunucu benzersiz bir challenge üretir ve oturumda saklar. Ardından istemciye PublicKeyCredentialCreationOptions döndürür: { rp: { name, id }, user: { id, name, displayName }, challenge, pubKeyCredParams, authenticatorSelection, attestation }.

2) user.id değeri kararlı ve benzersiz olmalı (ör. 16-32 baytlık bir UUID veya key). Kullanıcı adını değiştirse bile user.id sabit kalmalıdır.

3) Attestation’ı çoğu senaryoda "none" olarak ayarlayın; gizlilik ve uyumluluk açısından yeterlidir.

4) İstemciden dönen attestationObject ve clientDataJSON alanlarını doğrulayın: challenge eşleşmesi, origin kontrolü ve attestation formatı. Başarılıysa credentialId, publicKey ve signCount’ı veritabanında kullanıcıyla eşleştirerek saklayın.

Giriş akışı: Sunucu ve istemci

1) Sunucu, giriş başlatıldığında yine tekil bir challenge üretir ve PublicKeyCredentialRequestOptions döndürür: { challenge, rpId, allowCredentials?, userVerification }. Passkey-first deneyimi için discoverable credentials (resident key) kullanımını tercih edebilirsiniz; bu durumda allowCredentials boş bırakılabilir.

2) İstemci tarafında, kayıt için navigator.credentials.create({ publicKey }), giriş için ise navigator.credentials.get({ publicKey }) çağrıları yapılır. Mobilde ve masaüstünde tarayıcı, sistem düzeyi biyometri istemini kendisi yönetir.

3) Dönen authenticatorData, clientDataJSON ve signature sunucuya gönderilir. Sunucu, ilgili publicKey ile imzayı doğrular, signCount artışını kontrol eder ve oturumu başlatır.

Conditional UI ve kullanıcı adı olmadan giriş

Chrome ve Android’de Conditional UI ile otomatik doldurma benzeri bir passkey deneyimi sunabilirsiniz. navigator.credentials.get({ publicKey, mediation: "conditional" }) şeklinde çağrıldığında kullanıcı adı alanına odaklanıldığında tarayıcı passkey önerir. Bu, “username-less” akışlarla birleştiğinde form sürtünmesini ciddi şekilde azaltır.

En iyi uygulamalar

- Resident key desteğini açın: authenticatorSelection: { residentKey: "preferred", userVerification: "required" }. Böylece kullanıcı adı olmadan giriş mümkün olur.

- Base64url dönüşümlerine dikkat: Tarayıcı ArrayBuffer döndürür; sunucuya gönderirken ve doğrularken URL-safe kodlama kullanın.

- Çoklu cihaz stratejisi: Passkey’ler iCloud Anahtar Zinciri ve Google Password Manager ile eşzamanlanabilir. Kullanıcıların ikinci cihaz eklemesini ve donanımsal anahtarları (YubiKey) desteklemeyi düşünün.

- Geri kazanım planı: Cihaz kaybında kilitlenme yaşanmaması için e-posta bağlantısı veya destek kanıtı gibi güvenli kurtarma akışları tasarlayın. Parolaya dönmek yerine sınırlı ayrıcalıklı, denetimli akışlar tercih edin.

Test ve hata ayıklama

- Chrome DevTools’ta Virtual Authenticator ile farklı authenticator türlerini ve UV/UP kombinasyonlarını simüle edin. chrome://webauthn üzerinden test kolaydır.

- Origin ve rpId uyuşmazlıkları en yaygın sorundur. Üretimde www ve kök alan adı tutarsızlıklarını önleyin.

- Sunucu saat senkronizasyonu, proxy ve CDN başlıkları (X-Forwarded-Proto) için yapılandırmalarınızı kontrol edin; HTTPS algısı bozulursa WebAuthn başarısız olabilir.

Güvenlik ve uyumluluk notları

Passkey’ler kimlik bilgilerinin etki alanına bağlanması sayesinde oltalamaya dirençlidir. Ortadaki adam saldırıları, parolalara göre anlamlı ölçüde zorlaşır. Kurumsal ortamlarda cihaz yönetimi, anahtar yedekleme politikaları ve regülasyon (KVKK/GDPR) gerekliliklerini değerlendirin. Attestation’a yalnızca gerçekten cihaz tedarik zinciri doğrulaması gerekiyorsa başvurun; aksi halde gizlilik dostu none yeterlidir.

Sonuç: Şifresiz geleceğe bugünden geçin

Passkey, kullanıcılar için sürtünmeyi azaltırken güvenliği yükselten nadir teknoloji kırılımlarından biri. Kayıt ve giriş akışlarında WebAuthn’u doğru kurguladığınızda, dönüşüm oranlarınız artar ve destek yükünüz azalır. Adımları küçükten büyüğe taşıyın: önce HTTPS ve rpId düzeni, sonra resident key ve conditional UI, en sonunda çoklu cihaz ve kurtarma planları. Bir kez doğru kurguladığınızda, şifresiz girişin kullanıcı memnuniyetine ve güvenliğe etkisini doğrudan göreceksiniz.

8 Ekim 2025 Çarşamba

Next.js Projenize Passkey (WebAuthn) ile Parolasız Giriş Ekleme: SimpleWebAuthn ile Adım Adım

Parolasız kimlik doğrulama, hem güvenliği hem de kullanıcı deneyimini aynı anda iyileştiren güncel bir yaklaşım. Bu yazıda Next.js tabanlı bir web uygulamasına Passkey (FIDO2/WebAuthn) ile giriş özelliğini nasıl ekleyebileceğinizi, SimpleWebAuthn kütüphanesinden yararlanarak adım adım anlatıyorum. Amaç; phishing’e dayanıklı, cihazlar arası senkronize olabilen ve kullanıcıya tek dokunuşla giriş sağlayan bir çözüm kurmak.

Passkey nedir? Kısaca, kullanıcı adı-parola yerine cihazın güvenli donanımında (veya güvenli modülde) saklanan anahtar çifti ile giriş yapma yöntemidir. Tarayıcı ve cihaz (ör. iPhone, Android, Windows Hello, güvenlik anahtarı) iş birliğiyle çalışır ve WebAuthn standardını uygular.

Gereksinimler ve Kurulum

Başlamadan önce Node.js 18+, Next.js 13+ (App Router veya Pages), HTTPS (geliştirme için localhost’ta istisna), ve bir veritabanına (PostgreSQL, MongoDB, vb.) ihtiyacınız var. Sunucuda SimpleWebAuthn’in server paketi, istemcide ise browser paketi kullanılacak.

npm install @simplewebauthn/server @simplewebauthn/browser

Prod ortamında RP ID (Relying Party ID) alan adınız olmalı (ör. example.com). RP Origin ise protokol + alan adıdır (ör. https://example.com). Local geliştirmede rpID “localhost”, origin ise “http://localhost:3000” olabilir.

Kayıt (Registration) Akışı

Kullanıcı yeni bir passkey oluştururken, sunucu bir “challenge” üretir ve tarayıcıya kayıt seçeneklerini (PublicKeyCredentialCreationOptions) gönderir. Tarayıcı, cihazın güvenli modülünde anahtar çifti oluşturur ve sonucu sunucuya geri yollar. Sunucu, yanıtı doğrular ve kimlik bilgisini (credential) veritabanına kaydeder.

1) Sunucu: Kayıt seçeneklerini üret

generateRegistrationOptions({ rpName, rpID, userID, userName, attestationType: 'none', authenticatorSelection: { residentKey: 'preferred', userVerification: 'preferred' } })

Burada userID rastgele ve stabil bir kimlik olmalı (ör. UUID). Üretilen challenge değerini oturumda saklayın. rpID, alan adınızla birebir uyumlu olmalıdır; alt alan adı farkları doğrulamayı bozabilir.

2) İstemci: navigator.credentials.create()

const att = await startRegistration(options)

@simplewebauthn/browser içindeki startRegistration, tarayıcı API’sini sarmalar. Kullanıcı Touch ID/Face ID/Pin ile onay verir.

3) Sunucu: Kayıt doğrulama

verifyRegistrationResponse({ response, expectedChallenge, expectedOrigin, expectedRPID })

Doğrulama başarılıysa credentialId, publicKey, signCount gibi alanları kullanıcıya bağlı şekilde veritabanınıza kaydedin. Aynı kullanıcıya birden fazla credential tanımlanabilir; cihaz değiştirme senaryoları için faydalıdır.

Giriş (Authentication) Akışı

Giriş için süreç benzer: Sunucu challenge üretir, istemci bir imza üretir, sunucu imzayı doğrular. Burada kullanılacak seçenekler PublicKeyCredentialRequestOptions’tır.

1) Sunucu: Giriş seçenekleri

generateAuthenticationOptions({ rpID, userVerification: 'preferred', allowCredentials: [{ id: credentialId, type: 'public-key' }] })

allowCredentials ile ilgili kullanıcının credentialId’lerini gönderebilirsiniz. Challenge değeri yine oturumda tutulmalı.

2) İstemci: navigator.credentials.get()

const assertion = await startAuthentication(options)

Kullanıcı cihazında biyometrik/doğrulama adımı gerçekleşir ve tarayıcı imzalı yanıtı döner.

3) Sunucu: Giriş doğrulama

verifyAuthenticationResponse({ response, expectedChallenge, expectedOrigin, expectedRPID, authenticator: storedCredential })

Başarılı doğrulamada signCount artışı izlenmeli. Beklenmedik düşüş, olası klonlanmış bir anahtara işaret edebilir.

Next.js’te İstemci Tarafı ve Oturum

Next.js’te App Router kullanıyorsanız /app/api altında iki rota belirlemek (register ve login için “options” ve “verify”) işleri düzenli kılar. İstemci tarafında butona tıklanınca önce “options” endpoint’ine istek atın, ardından dönen opsiyonları startRegistration veya startAuthentication fonksiyonuna verin. Doğrulama başarılıysa sunucudan bir HttpOnly, Secure cookie (ör. JWT veya session id) ayarlayarak oturumu başlatın. Cookie için SameSite=Strict ve kısa ömür tercih edin.

Güvenlik ve Üretim İpuçları

- Origin ve rpID eşleşmesine çok dikkat edin. Port, protokol ve alt alan adı hataları en yaygın sorundur.
- Attestation genellikle “none” seçilir; cihaz tedarikçi doğrulaması gerektiren kurum uygulamalarında “direct” düşünülebilir.
- Kullanıcılara birden fazla passkey kaydetme imkânı verin. Telefon kaybında erişim kapanmasın.
- SSRF, CSRF ve rate limit gibi genel güvenlik önlemlerini ihmal etmeyin.
- Üretimde her zaman HTTPS kullanın; WebAuthn birçok tarayıcıda güvenli bağ zorunludur.

Hata Ayıklama ve Uyumluluk

Chrome, Safari ve Firefox’un güncel sürümlerinde passkey desteği olgunlaştı. Android 14 ve iOS 17 ile birlikte platform passkey’leri cihazlar arası senkronize edilebiliyor. Test sırasında about://webauthn (Chrome) üzerinden sanal güvenlik anahtarı oluşturabilir, geliştirici seçenekleriyle akışı simüle edebilirsiniz. Hata alırsanız tarayıcı konsolundaki NotAllowedError, SecurityError ve InvalidStateError mesajları size yön gösterecektir.

Sonuç

Passkey, modern web uygulamaları için güçlü ve kullanıcı dostu bir kimlik doğrulama yöntemi. Next.js ve SimpleWebAuthn ile birkaç endpoint yazarak hızlıca devreye alabilirsiniz. Doğru rpID/origin ayarı, güvenli cookie yönetimi ve çoklu credential desteği ile hem güvenlik ekibinizi hem kullanıcılarınızı mutlu edecek bir parolasız giriş deneyimi sunabilirsiniz.

2 Ekim 2025 Perşembe

Passkey (FIDO2/WebAuthn) ile Şifresiz Giriş: Node.js Üzerinde Adım Adım Kurulum ve En İyi Uygulamalar

Passkey ve WebAuthn Nedir?

Passkey, FIDO2 ve WebAuthn standartları üzerine kurulu, şifre gerektirmeyen modern bir kimlik doğrulama yöntemidir. Kullanıcılar parolayı ezberlemek yerine, cihazlarının biyometrik sensörlerini (parmak izi, yüz tanıma) veya bir ekran kilidini kullanarak giriş yapar. Kriptografik anahtarlar cihazda güvenle saklanır ve çoğu ekosistemde (Apple, Google, Microsoft) bulut üzerinden yedeklenip eşitlenebilir. Bu sayede hem güvenlik artar hem de giriş deneyimi tek dokunuşa iner.

Neden Passkey Kullanmalısınız?

Şifreler kimlik avı, sızan veri setleri ve tekrar kullanım sorunları nedeniyle saldırı yüzeyini genişletir. Passkey ise tarayıcı ve cihaz düzeyinde kimlik bağlamı (origin + rp.id) zorunluluğu ile phishing’e kapıyı kapatır. Ayrıca hızlıdır, kullanıcı memnuniyetini artırır ve destekleyen tarayıcılarda ek yazılım gerektirmeden çalışır. Kısacası güvenlik, hız ve dönüşüm oranı açısından net bir kazanım sağlar.

Mimarinin Özeti

WebAuthn iki ana akıştan oluşur: kayıt (registration/attestation) ve giriş (authentication/assertion). Sunucu benzersiz bir challenge üretir, istemci bunu güvenli donanımda imzalar ve sunucu doğrular. Başarılı kayıt sonunda kullanıcıya ait credentialId, publicKey ve signCount gibi meta veriler veritabanında saklanır. Girişte de benzer şekilde sunucu yeni bir challenge üretir, istemcinin imzasını doğrular ve sayacı günceller.

Gereksinimler ve Hazırlık

- Etki alanınız HTTPS üzerinde çalışmalıdır. Geliştirme için https://localhost istisnai olarak geçerlidir.
- rp.id (relying party id) genellikle alan adınızın eTLD+1 karşılığıdır (ör. example.com). Alt alan adında çalışsanız bile rp.id çoğunlukla kök alan olmalıdır.
- Node.js tarafında popüler kütüphane olarak @simplewebauthn/server ve istemci için @simplewebauthn/browser tercih edebilirsiniz.

Adım Adım Kurulum (Node.js)

Adım 1 – Proje kurulumu: Sunucu için Express veya Fastify kullanabilirsiniz. Temel bağımlılıklar: @simplewebauthn/server, oturum yönetimi için bir middleware ve kalıcı saklama için bir veritabanı (ör. PostgreSQL).

Adım 2 – Kayıt seçeneklerini üretin: /register/generate-options uç noktasında PublicKeyCredentialCreationOptions üretin. rp.name ve rp.id, user.id, user.name, pubKeyCredParams ve authenticatorSelection alanlarını doldurun. authenticatorSelection.userVerification için “required” seçimi güvenliği artırır. Üretilen challenge’ı kullanıcı oturumuna yazın.

Adım 3 – Kayıt doğrulama: İstemci tarafından dönen navigator.credentials.create() sonucu ile /register/verify uç noktasında verifyRegistrationResponse çağrısını yapın. Başarılıysa credentialId, publicKey, counter ve transports bilgilerini veritabanında kullanıcıya bağlayın.

Adım 4 – Giriş seçeneklerini üretin: /login/generate-options uç noktasında PublicKeyCredentialRequestOptions döndürün. allowCredentials alanına kullanıcının kayıtlı credentialId’lerini ekleyin. Tek tık deneyimi için residentKey destekliyorsanız discovery senaryosunu da tasarlayın.

Adım 5 – Giriş doğrulama: İstemcinin navigator.credentials.get() yanıtını /login/verify uç noktasına gönderip verifyAuthenticationResponse ile kontrol edin. İmza geçerliyse oturumu başlatın ve signCount değerini güncelleyin.

İstemci (Tarayıcı) Akışı

Kayıt sırasında sunucudan aldığınız creationOptions ile navigator.credentials.create({ publicKey: creationOptions }) çağrısı yapın. Sonucu sunucuya POST edin. Girişte ise requestOptions ile navigator.credentials.get({ publicKey: requestOptions }) çağrısı yapın. Bu çağrılar kullanıcıyı biyometrik sensör veya cihaz kilidiyle onay vermeye yönlendirir.

Test, Hata Ayıklama ve Uyumluluk

Chrome DevTools’ta “WebAuthn” paneliyle sanal authenticator ekleyebilir, platform ve çapraz platform seçeneklerini simüle edebilirsiniz. Sık karşılaşılan hatalar: NotAllowedError (kullanıcı iptal etti veya zaman aşımı), DOMException: SecurityError (rp.id ve origin uyumsuz), Constraint hataları (ör. residentKey politikası). Üretimde hem platform (telefon, laptop) hem de harici güvenlik anahtarlarını test edin.

Güvenlik ve En İyi Uygulamalar

- Bütünleşik phishing direnci için rp.id ve site origin eşleşmesine dikkat edin.
- Challenge değerini kriptografik olarak güvenli rastgelelik ile üretin ve tek kullanımlık olarak saklayın.
- userVerification’ı “required” kullanmak; başkasının cihazı üzerinden kötüye kullanım riskini azaltır.
- Birden fazla cihaz senkronizasyonunu desteklemek için kullanıcıya birden çok credential eklemeye izin verin.
- Güvenlik anahtarı kaybı için kurtarma akışları (ikinci passkey, e-posta linki, müşteri desteği) tasarlayın.

UX Önerileri

Passkey’i bir opsiyon olarak sunmak yerine “Passkey ile giriş yap” butonunu ön plana alın. Uyumlu tarayıcı ve cihazlarda otomatik doldurma istemini tetiklemek için form alanlarınızı sade tutun. Kayıt sırasında cihaz adını kullanıcıdan alarak (ör. “Mert’in iPhone’u”) hesap ayarlarında listelemeyi kolaylaştırın. Passkey bulunmazsa parolasız alternatif olarak sihirli bağlantı (magic link) sunmak terk oranını düşürür.

Dağıtım ve Aşamalı Geçiş

Mevcut oturum açma sisteminizi bozmadan aşamalı geçiş yapabilirsiniz. Önce kayıtlı kullanıcılarınıza ek kimlik doğrulama metodu olarak passkey tanımlama imkanı verin. Kullanıcı davranışı oturursa parolayı isteğe bağlı hale getirin ve yeni kullanıcılara “passkey-öncelikli” deneyim sunun. CDN veya ters proxy katmanında HTTPS ve HSTS ayarlarının doğru olduğundan emin olun.

Sonuç

Passkey (FIDO2/WebAuthn), şifrelerin yarattığı güvenlik risklerini ve kullanıcı sürtünmesini önemli ölçüde azaltır. Node.js ekosistemindeki olgun kütüphaneler sayesinde entegrasyon birkaç uç noktayı uygulamak kadar basit hale geldi. Doğru rp.id yapılandırması, güvenli challenge yönetimi ve iyi bir UX ile dakikalar içinde modern, phishing dayanıklı ve tek dokunuşla giriş deneyimini hayata geçirebilirsiniz.

20 Eylül 2025 Cumartesi

Parolasız Gelecek: WebAuthn Passkey Entegrasyonu ile Güvenli Giriş (Next.js Örneği)

Parolasız Gelecek: WebAuthn Passkey Entegrasyonu ile Güvenli Giriş (Next.js Örneği)

Parolalar, yıllardır sızıntıların ve kimlik avı saldırılarının baş aktörü oldu. Passkey (WebAuthn + FIDO2) yaklaşımı, biyometrik doğrulama (Touch ID, Windows Hello, Android Biometrics) veya donanım anahtarı ile tek dokunuşla güvenli oturum açmayı mümkün kılar. Bu yazıda, güncel tarayıcılar ve işletim sistemleriyle uyumlu passkey altyapısını nasıl kuracağınızı, geliştirici bakışıyla adım adım anlatıyorum. Örnek teknoloji olarak Next.js kullanacağız ancak anlatım, API uç noktaları olan her yığını kapsar.

Passkey Nedir? Passkey, kullanıcının cihazında güvenli bir şekilde saklanan asimetrik anahtar çifti ile çalışır. Sunucu yalnızca genel anahtarı tutar, gizli anahtar cihazdan çıkmaz. Oturum açma akışı; origin, RP ID (Relying Party ID) ve kullanıcı doğrulaması gibi bağlamlarla sınırlandırıldığı için kimlik avı ve kimlik bilgisi doldurma saldırılarına karşı son derece dirençlidir.

Neden Passkey?

- Kimlik avına dayanıklı: İmzalama süreci etki alanına (origin) bağlıdır, sahte sitelerde işe yaramaz.
- Kullanıcı deneyimi: Tek dokunuş, yüz tanıma ya da PIN ile saniyeler içinde giriş.
- Çoklu cihaz desteği: iCloud Keychain, Google Password Manager gibi kasalarla cihazlar arası senkronizasyon.

Mimari Özet ve Gereksinimler

Sunucu tarafında challenge üretir, saklar ve istemciye gönderirsiniz. İstemci bu challenge ile cihazdaki authenticator üzerinden kayıt (registration) veya giriş (assertion) akışını tamamlar; dönen yanıtı sunucuya iletir ve sunucu WebAuthn kurallarına göre doğrular. Sunucunuzda TLS zorunlu olmalı (localhost geliştirmenin istisnasıdır). RP ID genellikle alan adınızın köküdür (ör. example.com). Veritabanında kullanıcı, keyId, publicKey, alg, signCount gibi alanlar saklanır.

Kayıt (Registration) Akışı Adımları

1) Kullanıcı e-postasını veya benzersiz kimliğini alıp sunucunuza gönderin. Sunucu, PublicKeyCredentialCreationOptions üretir: challenge (base64url), rp.id, rp.name, user.id, user.name, pubKeyAlgo listesi (örn. -7 ES256, -257 RS256), authenticatorSelection (residentKey, userVerification) ve timeout gibi alanları içerir.

2) İstemci tarafında navigator.credentials.create() ile native WebAuthn API’sini çağırın. Dönen yanıt, attestationObject ve clientDataJSON içerir.

3) Bu verileri base64url ile sunucuya POST edin. Sunucu, attestation’ı doğrular; origin, challenge eşleşmesi, RP ID hash kontrolü ve sertifika zinciri doğrulaması yapar. Başarılıysa kullanıcıya ait publicKey, keyId ve signCount’ı veritabanına kaydeder.

Giriş (Authentication) Akışı Adımları

1) Sunucu, PublicKeyCredentialRequestOptions üretir: challenge, rpId, allowCredentials (kayıtlı anahtarlar) ve userVerification.

2) İstemci, navigator.credentials.get() çağırır ve authenticator’dan imzalı assertion alır: authenticatorData, clientDataJSON ve signature.

3) Sunucu; challenge, origin, rpIdHash doğrular; publicKey ile imzayı denetler ve signCount güncellenir. Ardından oturum açma token’ı veya session başlatılır.

Next.js ile Minimal Örnek Mantığı

- /api/webauthn/register/options: Kullanıcı kimliği ile çağrılır, creationOptions döner ve server-side Session’a challenge yazılır.
- /api/webauthn/register/verify: İstemciden gelen attestation yanıtını doğrular ve anahtarı kaydeder.
- /api/webauthn/login/options: Kullanıcının kayıtlı keyId’lerine göre requestOptions üretir, challenge’ı saklar.
- /api/webauthn/login/verify: Assertion’ı doğrular, session veya JWT üretir.

Doğrulama adımları için community tarafından desteklenen simplewebauthn gibi kütüphaneler süreci kolaylaştırır. İstemci tarafında base64url dönüştürmeleri (ArrayBuffer ⇄ base64url) dikkat ister; hataların çoğu burada çıkar.

En İyi Uygulamalar ve Güvenlik İpuçları

- Origin ve RP ID tutarlılığı: www ile çıplak alan adı karışıklığı yaşamamak için tek tercih belirleyin.
- User Verification: “required” seçeneği güvenliği yükseltir (biyometrik/PIN zorunlu).
- Resident Key (Discoverable Credentials): Kullanıcı adı sormadan doğrudan passkey ile giriş akışı sağlar; UX’i iyileştirir.
- Attestation politikası: Genellikle “none” yeterlidir; donanım güveni gerekiyorsa “indirect” veya belirli CA’lar ile doğrulayın.
- signCount ve Clone Detection: signCount düşerse potansiyel klon tespitine karşı hesabı işaretleyin.
- Yedekleme: Kullanıcıya birden fazla passkey ekletin ve acil kurtarma için e-posta linki veya destek kanalı sunun (parolaya geri dönüş önermeyin).

Sık Karşılaşılan Hatalar

- TypeError: create() ya da get() için beklenen ArrayBuffer yerine base64 string gönderildi. Çözüm: Base64url’ü Uint8Array’e çevirin.
- DOMException NotAllowedError: Kullanıcı iptal etti veya sayfa güvenli değil. HTTPS kullanın ve UI’de açık bilgi verin.
- InvalidStateError: Aynı kullanıcı için aynı authenticator’da ikinci kez kayıt deneniyor. allowCredentials stratejisini gözden geçirin.

SEO ve Üretim Notları

Passkey, WebAuthn ve FIDO2 anahtar kelimelerini sayfadaki başlık ve açıklamalara ekleyin. Schema.org Person ve WebSite şemaları ile login sayfasını işaretlemek, arama motorlarına daha net sinyaller verir. Üretimde HSTS etkinleştirin, doğru CORS politikası tanımlayın ve CSRF koruması kullanın. Reverse proxy arkasında çalışıyorsanız X-Forwarded-Proto başlığının doğruluğunu garanti edin; aksi halde origin eşleşmeleri başarısız olur.

Sonuç

Passkey entegrasyonu, modern web uygulamalarında güvenliği yükseltirken kullanıcı deneyimini ciddi ölçüde iyileştirir. Next.js veya benzeri bir yığınla, birkaç API uç noktası ve iyi kurgulanmış bir doğrulama katmanı ile parolasız girişe geçebilirsiniz. Küçük bir POC ile başlayın, kayıt ve giriş akışlarını uçtan uca test edin, ardından çoklu cihaz ve kurtarma senaryolarını ekleyerek üretime taşıyın. Parolasız gelecek, bugün erişilebilir durumda.

19 Eylül 2025 Cuma

Web Uygulamana Passkey (WebAuthn) Ekleme: Node.js ile Şifresiz Giriş Rehberi 2025

Giriş

Şifresiz kimlik doğrulama, son yılların en önemli güvenlik dönüşümlerinden biri. Passkey (FIDO2/WebAuthn) sayesinde kullanıcılar, karmaşık şifrelerle uğraşmadan biyometri, güvenli donanım anahtarları veya cihaz kilidi ile giriş yapabiliyor. Bu rehberde, modern bir web uygulamasına Node.js ve tarayıcı WebAuthn API kullanarak passkey ekleme sürecini adım adım anlatıyorum. Odak noktamız: kolay kurulum, sağlam güvenlik ve güncel tarayıcı desteği.

Ön Koşullar

- Alan adınız ve HTTPS etkin (localhost için https://localhost da çalışır, ancak gerçek kullanıcılar için zorunlu HTTPS gereklidir).
- Node.js 18+ (WebCrypto ve fetch desteği için önerilir).
- Basit bir kullanıcı veritabanı (PostgreSQL, MongoDB ya da SQLite).
- Sunucu tarafında WebAuthn doğrulaması için bir kütüphane (örneğin simplewebauthn).
- RP ID (Relying Party ID) olarak genellikle kök alan adınız: example.com. Origin ise https://app.example.com gibi tam kaynak adresidir.

Mimari ve Akış

WebAuthn iki ana akıştan oluşur: Kayıt (Registration) ve Giriş (Authentication). Her ikisi de sunucunun ürettiği rastgele bir challenge değeriyle başlar.

1) Kayıt: Sunucu kullanıcıyı tanımlar, PublicKeyCredentialCreationOptions oluşturur ve challenge döner. Tarayıcı navigator.credentials.create() ile kullanıcıdan attestation üretir. Sunucu attestation’ı doğrular, credentialId ve publicKey gibi özet bilgileri veritabanına kaydeder.

2) Giriş: Sunucu PublicKeyCredentialRequestOptions döner. Tarayıcı navigator.credentials.get() ile assertion (imzalı kanıt) üretir. Sunucu imzayı ve sayaç değerini doğrular, oturumu açar.

Frontend: Kayıt Akışı

Kullanıcı giriş yaptıktan (veya e-posta doğruladıktan) sonra passkey kaydı başlatın. İstemci tarafında tipik istek:

const regOpts = await fetch('/webauthn/register/options').then(r => r.json());
const credential = await navigator.credentials.create({ publicKey: regOpts });
await fetch('/webauthn/register/verify', { method: 'POST', body: JSON.stringify(credential) });

SEO açısından önemli noktalar: “passkey kaydı”, “WebAuthn tarayıcı API”, “şifresiz kimlik doğrulama” gibi anahtar kelimeleri akışa doğal yerleştirin.

Backend: Kayıt Doğrulama

Sunucuda challenge değerini kullanıcıya özel ve tek kullanımlık olarak üretin. @simplewebauthn/server kullanıyorsanız generateRegistrationOptions ile seçenekleri üretir, verifyRegistrationResponse ile attestation doğrularsınız. Doğrulama sonrası şu alanları saklayın:

- credentialId: Kimlik.
- publicKey: İmza doğrulaması için gereken anahtar.
- signCount: Yeniden oynatma saldırılarına karşı sayaç.
- transports ve aaguid gibi meta bilgiler.

Frontend: Giriş (Authentication) Akışı

Kullanıcı giriş sayfasına geldiğinde, eğer passkey kayıtlıysa “Tek tıkla şifresiz giriş” sunabilirsiniz:

const authOpts = await fetch('/webauthn/auth/options?username=ali').then(r => r.json());
const assertion = await navigator.credentials.get({ publicKey: authOpts });
await fetch('/webauthn/auth/verify', { method: 'POST', body: JSON.stringify(assertion) });

Chrome’un Conditional UI özelliğiyle, kullanıcı adı alanına odaklanıldığında passkey önerisi otomatik çıkar. Bunun için mediation: 'conditional' kullanın ve sayfada autocomplete="username" bulunan bir alan bulundurun.

Güvenlik ve En İyi Uygulamalar

- Origin ve rpId kesin eşleşmeli. Ters proxy (Cloudflare, Nginx) arkası dağıtıma dikkat edin.
- Challenge benzersiz ve kısa ömürlü olsun; kullanıldıktan sonra silin.
- userVerification değerini tehdit modelinize göre belirleyin: required (yüksek güvenlik) veya preferred (daha iyi uyumluluk).
- residentKey (discoverable credentials) ile kullanıcı adı girmeden giriş deneyimi sağlayabilirsiniz. Bunun için residentKey: 'required' ve authenticatorSelection.requireResidentKey = true.
- Çoklu cihaz senkronizasyonu (iCloud Keychain, Google Password Manager) sayesinde passkey’ler cihazlar arasında taşınabilir; ancak kurumsal ortamda donanım güvenlik anahtarlarını (YubiKey vb.) zorunlu kılmak isteyebilirsiniz.

Test ve Hata Ayıklama

Chrome DevTools > More Tools > Virtual Authenticator ile fiziksel cihaz olmadan test yapabilirsiniz. Buradan platform/harici anahtar seçebilir, kullanıcı doğrulamasını simüle edebilirsiniz. Sık görülen hatalar: “Invalid RP ID” (alan adınız uyuşmuyor), “DOMException: The operation is insecure” (HTTPS yok), “Challenge mismatch” (eski veya farklı kullanıcıya ait challenge).

Veri Modeli ve Uyum

Bir kullanıcı birden fazla passkey’e sahip olabilir. Veritabanında users, credentials şeklinde ayrıştırın. Girişte birden çok allowCredentials döndürebilir veya discoverable credential ile boş gönderip tarayıcının seçmesini izleyebilirsiniz. KV veya bellek içi önbellek ile challenge yönetimini hızlandırın. KV kullansanız bile kalıcılık için veritabanına yedekleyin.

Dağıtım İpuçları

Sunucunuz HTTP/2 veya HTTP/3 arkasındaysa, Origin başlığının ve CF-Connecting-IP / X-Forwarded-Proto gibi başlıkların framework’ünüz tarafından doğru işlendiğinden emin olun. Serverless (Vercel, Cloudflare Workers) üzerinde de WebAuthn rahatlıkla çalışır; sadece rpId ve origin sabit ve tutarlı olmalı.

Sonuç

Passkey (WebAuthn) ile şifresiz kimlik doğrulama, hem güvenliği hem kullanıcı deneyimini ciddi biçimde iyileştiriyor. Node.js ve WebAuthn API sayesinde birkaç uç noktayı doğru kurgulayarak dakikalar içinde prototip çıkabilir, Conditional UI ile tek dokunuşla giriş deneyimi sunabilirsiniz. Doğru RP ID, benzersiz challenge yönetimi ve kapsamlı doğrulama kontrolleriyle, 2025’in güvenlik standartlarına uygun modern bir “şifresiz giriş” altyapısını bugün projelerinize ekleyin.

13 Eylül 2025 Cumartesi

Passkey (WebAuthn) ile Şifresiz Giriş Entegrasyonu: Adım Adım Rehber

Passkey nedir ve neden önemli?

Geleneksel parolalar hem kullanıcı deneyimi açısından sorunlu hem de güvenlik zaafları nedeniyle verimsizdir. Passkey, FIDO2 ve WebAuthn standartlarına dayalı, phishing’e dayanıklı ve cihaz tabanlı bir kimlik doğrulama yöntemidir. Kullanıcılar artık “123456” gibi zayıf parolalarla uğraşmak yerine, platformlarının (iOS, Android, Windows, macOS) yerleşik biyometrik doğrulamasını veya donanım anahtarını kullanır. Bu yazıda, modern bir web uygulamasına passkey ile şifresiz girişin nasıl ekleneceğini, mimari prensipleri ve dikkat edilmesi gereken güvenlik detaylarını anlatıyorum.

Temel mimari ve kavramlar

WebAuthn iki temel akıştan oluşur: Kayıt (Registration) ve Giriş (Authentication). Kayıt sırasında tarayıcı bir anahtar çifti üretir ve sunucuya sadece public key ve credentialId gibi meta veriler iletilir. Girişte, sunucu tarafından üretilen tek kullanımlık challenge imzalanarak doğrulama yapılır.

Önemli alanlar: rpId (Relying Party ID, genellikle alan adınız), origin (tam köken, ör. https://app.siteniz.com), userHandle (kullanıcının uygulama içi benzersiz kimliği), signCount (anti-rollback sayacı). Her doğrulamada challenge rastgele üretilir ve tek seferliktir.

Önkoşullar ve teknoloji seçimi

Üretimde HTTPS zorunludur. Geliştirme için localhost istisnası vardır. Sunucu tarafında doğrulama için hazır kütüphaneler tercih edin: Node.js için SimpleWebAuthn, Go için duo-labs/webauthn, Java için WebAuthn4J, Python için webauthn. İstemci tarafında tarayıcı API’si navigator.credentials üzerinden erişilir. Veritabanında her kullanıcı için birden fazla credential saklamaya hazır olun (cihaz kaybı senaryosu).

Kayıt (Registration) akışı

1. Sunucu hazırlığı: Kullanıcı hesabı oluşturulduğunda veya “Passkey ekle” tıklandığında sunucu bir PublicKeyCredentialCreationOptions üretir. İçerik: rp (name, id), user (id, name, displayName), challenge (kriptopratik rastgele dizi), pubKeyCredParams (genelde -7 ES256), authenticatorSelection (ör. residentKey: "preferred", userVerification: "required"), attestation ("none" çoğu senaryo için yeterli).

2. İstemci isteği: Tarayıcıda navigator.credentials.create({ publicKey: options }) çağrılır. Kullanıcı, biyometrik veya PIN ile onaylar. Tarayıcı size attestation yanıtını döner.

3. Sunucu doğrulaması: İstemciden dönen cevabı sunucuda kütüphane ile doğrulayın. Origin ve rpId eşleşmeli, challenge doğru olmalı. Başarılıysa şu verileri saklayın: credentialId (base64url), publicKey, signCount, transports (ör. "internal", "usb", "ble"), userId. attestation politikanıza göre sertifika zinciri doğrulamasını atlayabilir veya sıkı modda açabilirsiniz.

Giriş (Authentication) akışı

1. Sunucu challenge üretimi: Giriş sayfasında kullanıcı e-posta veya kullanıcı adını girince sunucu PublicKeyCredentialRequestOptions döner: challenge, rpId, allowCredentials (ilgili credentialId listesi) ve userVerification ("required" önerilir).

2. İstemci doğrulaması: navigator.credentials.get({ publicKey: options }) çağrılır. Tarayıcı kullanıcıdan biyometrik onay ister ve assertion döner.

3. Sunucu doğrulaması: İmza ve authenticatorData kontrol edilir; rpIdHash ve origin eşleşmeli. signCount daha büyükse güncellenir, geriye düşüyorsa potansiyel klon/hatalı cihaz işareti olarak reddedilir. Başarılıysa güvenli bir session veya token üretin.

Kullanıcı deneyimi: Conditional UI ve otomatik doldurma

Conditional UI (Chromium) ile kullanıcı adını sormadan doğrudan mediation: "conditional" parametresiyle passkey önerisini tarayıcıda tetikleyebilirsiniz. iOS ve Safari tarafında sistem otomatik doldurma panelindeki “Anahtarlar” akışı devreye girer. Parola yerine “Devam etmek için cihazınızı doğrulayın” gibi net, güven veren metinler kullanın ve OTP/eposta doğrulamayı sadece kurtarma senaryosu olarak bırakın.

Güvenlik ve en iyi uygulamalar

- HTTPS zorunlu; Secure, HttpOnly, SameSite cookie bayraklarını doğru ayarlayın. CSRF için same-site veya token stratejisi uygulayın.

- rpId alan adınızla birebir ilişkili olmalı. Üretimde app.example.com kullanıyorsanız origin tam olarak bu olmalı; ters proxy kullanıyorsanız X-Forwarded-Proto/Host başlıklarını doğru iletin.

- Discoverable credentials (resident keys) açıldığında kullanıcı adı girmeden giriş mümkün olur. Ancak veritabanında kullanıcı başına çoklu credential yönetimini kurgulayın.

- Cihaz kaybı ve kurtarma: Kullanıcının birden fazla passkey ekleyebilmesini sağlayın (telefon, laptop, güvenlik anahtarı). Eski credential’ları listeden kaldırma (revoke) imkanı verin.

- Hata yönetimi: Timeout, NotAllowedError, InvalidStateError gibi hataları kullanıcı dostu mesajlarla ele alın. Geri dönüş yolunda asla parola istemeyin; kurtarma akışını ayrı doğrulamalarla çalıştırın.

Test, uyumluluk ve dağıtım

Geliştirme sırasında Chrome DevTools’taki Virtual Authenticator Environment ile farklı platformları simüle edin. iOS 17+, Android 14+, Windows Hello ve macOS/iCloud Keychain ile pratik testler yapın. Google Password Manager ve iCloud senkronizasyon farklarını (cihazlar arası passkey paylaşımı) göz önünde bulundurun.

Üretime geçerken alan adı stratejinizi belirleyin: rpId olarak kök alan adını (example.com) seçip alt alanlarda tutarlılık sağlayın. CDN ve WAF arkasında origin doğru raporlanıyor mu kontrol edin. İzleme için kayıt/giriş başarı oranı, kullanıcı başına credential sayısı, hataya düşen challenge sayısı gibi metrikler tutun.

Sonuç

Passkey (WebAuthn) ile şifresiz giriş, hem güvenliği yükselten hem de kullanıcı deneyimini sadeleştiren bir yaklaşım. Doğru rpId/origin eşlemesi, sıkı challenge doğrulaması ve sağlam bir oturum yönetimiyle phishing’e dirençli bir kimlik doğrulama katmanı elde edersiniz. Üstelik conditional UI ve discoverable credentials sayesinde “parola” kavramını kullanıcıdan tamamen gizleyerek tek dokunuşla giriş deneyimi sunabilirsiniz. Küçük bir POC ile başlayıp, çoklu credential ve kurtarma senaryolarını da kapsayacak şekilde adım adım genellemek en pragmatik yol olacaktır.