Genel Bakış
Geçiş anahtarı kaydıyla ilgili temel adımlara genel bir bakış:

- Geçiş anahtarı oluşturma seçeneklerini tanımlayın. Bunları istemciye göndererek geçiş anahtarı oluşturma çağrınıza iletebilirsiniz: Web'de WebAuthn API çağrısı
navigator.credentials.createve Android'decredentialManager.createCredential. Kullanıcı geçiş anahtarının oluşturulduğunu onayladıktan sonra geçiş anahtarı oluşturma çağrısı çözümlenir ve bir kimlik bilgisiPublicKeyCredentialdöndürülür. - Kimlik bilgilerini doğrulayıp sunucuda saklayın.
Aşağıdaki bölümlerde her adımın ayrıntıları ele alınmaktadır.
Kimlik bilgisi oluşturma seçenekleri
Sunucuda yapmanız gereken ilk işlem, bir PublicKeyCredentialCreationOptions nesnesi oluşturmaktır.
Bunun için FIDO sunucu tarafı kitaplığınızı kullanın. Genellikle bu seçenekleri sizin için oluşturabilecek bir hizmet işlevi sunar. Örneğin, SimpleWebAuthn generateRegistrationOptions sunar.
PublicKeyCredentialCreationOptions, geçiş anahtarı oluşturmak için gereken her şeyi içermelidir: kullanıcı ve bağlı taraf hakkındaki bilgiler ve oluşturduğunuz kimlik bilgilerinin özellikleri için bir yapılandırma. Tüm bunları tanımladıktan sonra, FIDO sunucu tarafı kitaplığınızda PublicKeyCredentialCreationOptions nesnesini oluşturmaktan sorumlu işleve gerektiği şekilde iletin.
PublicKeyCredentialCreationOptions alanlarından bazıları sabit olabilir. Diğerleri sunucuda dinamik olarak tanımlanmalıdır:
rpId: Sunucuda RP kimliğini doldurmak için web uygulamanızın ana makine adını sağlayan sunucu tarafı işlevleri veya değişkenleri (ör.example.com) kullanın.user.nameveuser.displayName: Bu alanları doldurmak için oturum açmış kullanıcınızın oturum bilgilerini (veya kullanıcı kaydolurken geçiş anahtarı oluşturuyorsa yeni kullanıcı hesabı bilgilerini) kullanın.user.namegenellikle bir e-posta adresidir ve RP için benzersizdir.user.displayName, kullanıcı dostu bir addır. Tüm platformlarındisplayNamekullanmayacağını unutmayın.user.id: Hesap oluşturulduğunda oluşturulan rastgele, benzersiz bir dize. Düzenlenebilir bir kullanıcı adının aksine kalıcı olmalıdır. Kullanıcı kimliği bir hesabı tanımlar ancak kişisel veri (PII) içermemelidir. Sisteminizde muhtemelen bir kullanıcı kimliği vardır ancak gerekirse kimliği tanımlayabilecek bilgiler içermemesi için geçiş anahtarlarına özel bir kimlik oluşturun.excludeCredentials: Geçiş anahtarı sağlayıcıdan alınan geçiş anahtarının kopyalanmasını önlemek için mevcut kimlik bilgilerinin kimliklerinin listesi. Bu alanı doldurmak için veritabanınızda bu kullanıcının mevcut kimlik bilgilerini arayın. Ayrıntıları Mevcut bir geçiş anahtarı varsa yeni geçiş anahtarı oluşturulmasını engelleme bölümünde bulabilirsiniz.challenge: Kimlik bilgisi kaydı için sorgulama, geçiş anahtarı sağlayıcısının kimliğini ve yaydığı verileri doğrulamak için daha gelişmiş bir teknik olan onaylama yöntemini kullanmadığınız sürece geçerli değildir. Ancak onaylama kullanmasanız bile sorgu zorunlu bir alandır. Kimlik doğrulama için güvenli bir sorgulama oluşturma talimatlarını Sunucu tarafı geçiş anahtarı kimlik doğrulaması bölümünde bulabilirsiniz.
Kodlama ve kod çözme
Sunucu tarafından gönderilen PublicKeyCredentialCreationOptions. challenge ve user.id gibi ikili alanlar, seçeneklerin HTTPS üzerinden JSON olarak sunulabilmesi için sunucu tarafında base64URL olarak kodlanır.Standart WebAuthn PublicKeyCredentialCreationOptions nesnesi, ArrayBuffer olan ve JSON.stringify() ile doğrudan serileştirilemeyen alanlar içerir. Bu seçenekleri HTTPS üzerinden göndermek için ikili alanlar base64URL dizesi olarak kodlanmalıdır:
- Sunucuda, FIDO sunucu tarafı kitaplığınız (ör.SimpleWebAuthn), Base64URL ile kodlanmış alanlar içeren JSON ile serileştirilebilir bir seçenekler nesnesi (ör.
PublicKeyCredentialCreationOptionsJSON) otomatik olarak oluşturur. - İstemcide, modern tarayıcılar JSON seçeneklerini doğrudan
PublicKeyCredentialCreationOptionsbiçimine dönüştürmek içinPublicKeyCredential.parseCreationOptionsFromJSON()yöntemini destekler.@simplewebauthn/browsergibi istemci tarafı kitaplıkları kullanırkenstartRegistration({ optionsJSON: options })gibi işlevler bu dönüşümü otomatik olarak gerçekleştirir.
Örnek kod: Kimlik bilgisi oluşturma seçenekleri oluşturma
Örneklerimizde SimpleWebAuthn kitaplığını kullanıyoruz. Burada, ortak anahtar kimlik bilgisi seçeneklerinin oluşturulmasını generateRegistrationOptions işlevine devrediyoruz.
import {
generateRegistrationOptions,
verifyRegistrationResponse,
} from '@simplewebauthn/server';
import { isoBase64URL, isoUint8Array } from '@simplewebauthn/server/helpers';
router.post('/registerRequest', csrfCheck, sessionCheck, async (req, res) => {
const { user } = res.locals;
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// `excludeCredentials` prevents users from re-registering existing
// credentials for a given passkey provider
const excludeCredentials = [];
const credentials = Credentials.findByUserId(user.id);
if (credentials.length > 0) {
for (const cred of credentials) {
excludeCredentials.push({
id: cred.id,
type: 'public-key',
transports: cred.transports,
});
}
}
// Generate registration options for WebAuthn create
const options = await generateRegistrationOptions({
rpName: process.env.RP_NAME,
rpID: process.env.HOSTNAME,
userID: isoUint8Array.fromUTF8String(user.id),
userName: user.username,
userDisplayName: user.displayName || '',
attestationType: 'none',
excludeCredentials,
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
userVerification: 'preferred',
},
});
// Keep the challenge in the session
req.session.challenge = options.challenge;
return res.json(options);
} catch (e) {
console.error(e);
return res.status(400).send({ error: e.message });
}
});
Ortak anahtarı depolama
navigator.credentials.create, bir PublicKeyCredential nesnesi döndürür.navigator.credentials.create, istemcide başarıyla çözümlendiğinde geçiş anahtarı başarıyla oluşturulmuş demektir. Bir PublicKeyCredential nesnesi döndürülür.
PublicKeyCredential nesnesi, geçiş anahtarı sağlayıcının istemcinin geçiş anahtarı oluşturma talimatına verdiği yanıtı temsil eden bir AuthenticatorAttestationResponse nesnesi içerir. Kullanıcının kimliğini daha sonra doğrulamak için güvenen taraf olarak ihtiyaç duyduğunuz yeni kimlik bilgisiyle ilgili bilgileri içerir. AuthenticatorAttestationResponse hakkında daha fazla bilgiyi Ek: AuthenticatorAttestationResponse bölümünde bulabilirsiniz.
PublicKeyCredential nesnesini sunucuya gönderin. Kodu aldıktan sonra doğrulayın.
Bu doğrulama adımını FIDO sunucu tarafı kitaplığınıza devredin. Bu amaçla genellikle bir hizmet işlevi sunar. Örneğin, SimpleWebAuthn verifyRegistrationResponse sunar. Ek: Kayıt yanıtının doğrulanması bölümünde arka planda neler olduğunu öğrenebilirsiniz.
Doğrulama başarılı olduktan sonra, kullanıcının daha sonra bu kimlik bilgisiyle ilişkili geçiş anahtarıyla kimlik doğrulaması yapabilmesi için kimlik bilgilerini veritabanınızda saklayın.
Geçiş anahtarlarıyla ilişkili ortak anahtar kimlik bilgileri için özel bir tablo kullanın. Kullanıcıların yalnızca bir şifresi olabilir ancak birden fazla geçiş anahtarı olabilir. Örneğin, Apple iCloud Anahtar Zinciri ve Google Şifre Yöneticisi aracılığıyla senkronize edilen birer geçiş anahtarı olabilir.
Kimlik bilgilerini depolamak için kullanabileceğiniz örnek bir şemayı aşağıda bulabilirsiniz:

- Kullanıcılar tablosu:
user_id: Birincil kullanıcı kimliği. Kullanıcı için rastgele, benzersiz ve kalıcı bir kimlik. Bunu Kullanıcılar tablonuzun birincil anahtarı olarak kullanın.username: Kullanıcı tarafından tanımlanan ve düzenlenebilen bir kullanıcı adı.passkey_user_id: Kayıt seçeneklerinizdeuser.idile temsil edilen, geçiş anahtarına özel ve kimliği tanımlayabilecek bilgiler içermeyen kullanıcı kimliği. Kullanıcı daha sonra kimlik doğrulamaya çalıştığında, kimlik doğrulayıcı bupasskey_user_iddeğeriniuserHandleiçindeki kimlik doğrulama yanıtında kullanılabilir hale getirir.passkey_user_idsütununu birincil anahtar olarak ayarlamamanızı öneririz. Birincil anahtarlar, yaygın olarak kullanıldıkları için sistemlerde fiili olarak kimliği tanımlayabilecek bilgiler haline gelir.
- Ortak anahtar kimlik bilgileri tablosu:
id: Kimlik bilgisi kimliği. Bunu, Ortak anahtar kimlik bilgileri tablonuzun birincil anahtarı olarak kullanın.public_key: Kimlik bilgisinin ortak anahtarı.passkey_user_id: Kullanıcılar tablosuyla bağlantı oluşturmak için bunu yabancı anahtar olarak kullanın.backed_up: Geçiş anahtarı, geçiş anahtarı sağlayıcı tarafından senkronize edilirse yedeklenir. Yedekleme durumunu saklamak, gelecektebacked_upgeçiş anahtarı olan kullanıcılar için şifreleri kaldırmayı düşünüyorsanız faydalı olur. Geçiş anahtarının yedeklenip yedeklenmediğini kontrol etmek içinauthenticatorDataiçindeki BE işaretini inceleyebilir veya bu bilgilere kolayca erişmenizi sağlayan bir FIDO sunucu tarafı kitaplığı özelliğini kullanabilirsiniz. Yedekleme uygunluğunu saklamak, olası kullanıcı sorularını yanıtlamanıza yardımcı olabilir.name: İsteğe bağlı olarak, kullanıcıların kimlik bilgilerine özel adlar vermesini sağlamak için kimlik bilgisi için bir görünen ad.transports: Taşıma yöntemleri dizisi. Taşıma yöntemlerini depolamak, kimlik doğrulama kullanıcı deneyimi açısından faydalıdır. Taşıma yöntemleri mevcut olduğunda tarayıcı buna göre davranabilir ve geçiş anahtarı sağlayıcının istemcilerle iletişim kurmak için kullandığı taşıma yöntemine uygun bir kullanıcı arayüzü gösterebilir. Bu, özellikleallowCredentialsdeğerinin boş olmadığı yeniden kimlik doğrulama kullanım alanları için geçerlidir.
Geçiş anahtarı sağlayıcı, kimlik bilgisi oluşturma zamanı ve son kullanım zamanı gibi diğer bilgiler, kullanıcı deneyimi açısından faydalı olabilir. Geçiş anahtarları kullanıcı arayüzü tasarımı başlıklı makaleden daha fazla bilgi edinebilirsiniz.
Örnek kod: Kimlik bilgisini depolama
Örneklerimizde SimpleWebAuthn kitaplığını kullanıyoruz.
Burada, kayıt yanıtı doğrulamasını verifyRegistrationResponse işlevine devrediyoruz.
import { isoBase64URL } from '@simplewebauthn/server/helpers';
router.post('/registerResponse', csrfCheck, sessionCheck, async (req, res) => {
const expectedChallenge = req.session.challenge;
const expectedOrigin = getOrigin(req.get('User-Agent'));
const expectedRPID = process.env.HOSTNAME;
const response = req.body;
// This sample code is for registering a passkey for an existing,
// signed-in user
// Ensure you nest verification function calls in try/catch blocks.
// If something fails, throw an error with a descriptive error message.
// Return that message with an appropriate error code to the client.
try {
// Verify the credential
const { verified, registrationInfo } = await verifyRegistrationResponse({
response,
expectedChallenge,
expectedOrigin,
expectedRPID,
requireUserVerification: false,
});
if (!verified) {
throw new Error('Verification failed.');
}
const {
aaguid,
credential,
credentialBackedUp
} = registrationInfo;
// Name the credential based on AAGUID
const name =
aaguid === undefined ||
aaguid === '00000000-0000-0000-0000-000000000000' ?
req.useragent?.platform : aaguids[aaguid]?.name;
const base64PublicKey = isoBase64URL.fromBuffer(credential.publicKey);
// Existing, signed-in user
const { user } = res.locals;
// Save the credential
await Credentials.update({
id: credential.id,
passkey_user_id: user.passkey_user_id,
publicKey: base64PublicKey,
name,
aaguid,
transports: credential.transports || response.response.transports,
backed_up: credentialBackedUp,
registered_at: new Date().getTime()
});
// Kill the challenge for this session
delete req.session.challenge;
return res.json(user);
} catch (e) {
delete req.session.challenge;
console.error(e);
return res.status(400).send({ error: e.message });
}
});
Ek: AuthenticatorAttestationResponse
AuthenticatorAttestationResponse iki önemli nesne içerir:
response.clientDataJSON, istemci verilerinin JSON sürümüdür. Web'de bu veriler, tarayıcı tarafından görülen verilerdir. RP kaynağını, sorgulamayı ve istemci bir Android uygulamasıysaandroidPackageNamedeğerini içerir. RP olarakclientDataJSONdeğerini okumak, tarayıcınıncreateisteği sırasında gördüğü bilgilere erişmenizi sağlar.response.attestationObjectiki bilgi içerir:attestationStatement(Onaylama kullanmıyorsanız alakalı değildir.)authenticatorData, geçiş anahtarı sağlayıcı tarafından görülen verilerdir. Geçiş anahtarı tarafı olarak,authenticatorDataokuma işlemi, geçiş anahtarı sağlayıcı tarafından görülen vecreateisteği sırasında döndürülen verilere erişmenizi sağlar.
authenticatorData, yeni oluşturulan geçiş anahtarıyla ilişkili ortak anahtar kimlik bilgisi hakkında önemli bilgiler içerir:
- Ortak anahtar kimlik bilgisinin kendisi ve bunun için benzersiz bir kimlik bilgisi kimliği.
- Kimlik bilgisiyle ilişkili RP kimliği.
- Geçiş anahtarı oluşturulduğunda kullanıcı durumunu açıklayan işaretler: Kullanıcının gerçekten mevcut olup olmadığı ve kullanıcının başarıyla doğrulanıp doğrulanmadığı (userVerification ayrıntılı incelemesi bölümüne bakın).
- AAGUID, Google Şifre Yöneticisi gibi geçiş anahtarı sağlayıcıları için bir tanımlayıcıdır. AAGUID'ye göre geçiş anahtarı sağlayıcısını tanımlayabilir ve adı geçiş anahtarı yönetim sayfasında görüntüleyebilirsiniz. (AAGUID ile geçiş anahtarı sağlayıcısını belirleme bölümüne bakın)
authenticatorData, attestationObject içinde iç içe yerleştirilmiş olsa da içerdiği bilgiler, onaylama kullanıp kullanmadığınızdan bağımsız olarak geçiş anahtarı uygulamanız için gereklidir. authenticatorData kodlanmıştır ve ikili biçimde kodlanmış alanlar içerir. Ayrıştırma ve kod çözme işlemleri genellikle sunucu tarafı kitaplığınız tarafından gerçekleştirilir. Sunucu tarafı kitaplığı kullanmıyorsanız sunucu tarafında ayrıştırma ve kod çözme işlemlerinden tasarruf etmek için istemci tarafında getAuthenticatorData() kullanabilirsiniz.
Ek: Kayıt yanıtının doğrulanması
Kayıt yanıtını doğrulama işlemi, arka planda aşağıdaki kontrollerden oluşur:
- RP kimliğinin sitenizle eşleştiğinden emin olun.
- İsteğin kaynağının siteniz için beklenen bir kaynak (ana site URL'si, Android uygulaması) olduğundan emin olun.
- Kullanıcı doğrulaması gerekiyorsa kullanıcı doğrulama işaretinin
authenticatorData.uvtrueolduğundan emin olun. - Kullanıcı varlığı işaretinin
authenticatorData.upgenellikletrueolması beklenir ancak kimlik bilgisi koşullu olarak oluşturulmuşsafalseolması beklenir. - İstemcinin, verdiğiniz sorguyu sağlayabildiğinden emin olun. Onay kullanmıyorsanız bu kontrol önemli değildir. Ancak bu kontrolü uygulamak en iyi uygulamalardan biridir. Bu sayede, gelecekte onay kullanmaya karar verirseniz kodunuz hazır olur.
- Kimlik bilgisi kimliğinin henüz herhangi bir kullanıcı için kaydedilmediğinden emin olun.
- Geçiş anahtarı sağlayıcının kimlik bilgisini oluşturmak için kullandığı algoritmanın, listelediğiniz bir algoritma olduğunu doğrulayın (
publicKeyCredentialCreationOptions.pubKeyCredParamsöğesinin her biralgalanında. Bu alan genellikle sunucu tarafı kitaplığınızda tanımlanır ve sizin tarafınızdan görülemez). Bu sayede, kullanıcılar yalnızca izin vermeyi seçtiğiniz algoritmalarla kaydolabilir.
Daha fazla bilgi edinmek için SimpleWebAuthn'un verifyRegistrationResponse için kaynak koduna göz atın veya teknik özelliklerdeki doğrulamaların tam listesini inceleyin.