این راهنما جزئیات نحوه فعال کردن کاربران برای ثبت گذرکلید برای حسابشان را ارائه میدهد و یک جایگزین ورود به سیستم بدون گذرواژه بسیار امن و مقاوم دربرابر رمزگیری ارائه میدهد.
الزامات پایگاه داده
برای پشتیبانی از ثبت گذرکلید، جدول اطلاعات کاربری پایگاه داده شما باید فیلدهای زیر را ذخیره کند:
export interface StoredPasskeyCredential {
id: string; // Base64URL-encoded credential ID (unique lookup key)
passkeyUserId: string; // Associated application user ID
credentialPublicKey: string; // Base64URL-encoded public key used to verify assertion signatures
credentialType: "public-key";
credentialDeviceType: "singleDevice" | "multiDevice"; // Helps distinguish device-bound vs cloud-synced passkeys
credentialBackedUp: boolean; // Boolean backup state reported by the authenticator
aaguid: string; // Authenticator Attestation GUID
providerIcon?: string; // Provider icon derived from the AAGUID registry (dark or light theme URLs)
name: string; // Provider name derived from AAGUID registry
transports: string[]; // Array of transport names (e.g. 'internal', 'hybrid') necessary for exclusion options
lastUsedAt?: number; // Optional epoch timestamp of last sign-in
registeredAt: number; // Registration epoch timestamp
counter: number; // Authenticator sign-in signature counter used to prevent replay attacks
}
سمت سرور
تولید کردن گزینهها
نقطه پایانی ایجاد کنید که پارامترهای ایجاد WebAuthn را تولید کند. بهجای رمزنگاری دستی، به کتابخانه بررسیشده براساس استانداردهای دستهبندی تکیه کنید.
- استفاده از شناسه RP ازپیشتعریفشده: از شناسه RP مناسب ازپیشتعریفشده بهعنوان رشته ثابت استفاده کنید.
- ایجاد «چالش» ایمن: یک میانگیر تصادفی با آنتروپی بالا و ازنظر رمزنگاری ایمن در سرور ایجاد کنید، آن را بهطور ایمن در جلسه کاربر ذخیره کنید، و آن را بهعنوان Base64URL برای ارائه گزینهها کدگذاری کنید.
- اجتناب از گذرکلیدهای تکراری: شناسههای اطلاعات اعتباری پیشثبتشده موجود کاربر را به آرایه گزینههای
excludeCredentialsنگاشت کنید. این کار از ثبت اطلاعات کاربری تکراری توسط اصالتسنج در همان حساب ارائهدهنده گذرکلید جلوگیری میکند. - اجرای اعتبارنامههای قابلکشف:
requireResidentKey: trueوresidentKey: "required"را در گزینههایauthenticatorSelectionتنظیم کنید تا اعتبارنامه قابلکشف درخواست شود، که برای ورودهای قابلکشف ضروری است. - پیکربندی درستیسنجی کاربر:
userVerification: "preferred"یاuserVerification: "required"را مشخص کنید. بسیاری از موارد استفاده از رعایت مقررات (مثلاً امور مالی، مراقبتهای بهداشتی) به'required'نیاز دارند تا درستیسنجی کاربر را هنگام ایجاد اعمال کنند. - تعیین دامنه پیوست:
- جریان تبلیغ: هنگام پیشنهاد ایجاد گذرکلید بلافاصله پساز ورود به سیستم با گذرواژه استاندارد یا تبلیغات پساز ثبتنام،
authenticatorAttachment: "platform"را تنظیم کنید تا اصالتسنج پلاتفرم را اعمال کند و درخواستهای کلید امنیتی خارجی را دور بزند. - جریان مدیریت: وقتی از پانل تنظیمات یا امنیت اختصاصی که در آن کلیدهای امنیتی خارجی علاوهبر اصالتسنج پلاتفرم پشتیبانی میشود فراخوانی میشود، ویژگی
authenticatorAttachmentرا کاملاً حذف کنید. - نکته: پرچم درخواست
promotion: booleanرا بپذیرید تا هر دو جریان را بهطور مشروط با یک نقطه پایانی مدیریت کنید.
- جریان تبلیغ: هنگام پیشنهاد ایجاد گذرکلید بلافاصله پساز ورود به سیستم با گذرواژه استاندارد یا تبلیغات پساز ثبتنام،
// Options generation example
const options = {
challenge: serverGeneratedBase64UrlChallenge, // Cryptographically random challenge
rp: { id: "example.com", name: "Secure Application" },
user: {
id: userBase64UrlId, // Unique base64url string identifying the account
name: "user@example.com",
displayName: "Jane Doe",
},
pubKeyCredParams: [
{
type: "public-key",
alg: -7,
},
{
type: "public-key",
alg: -257,
},
],
excludeCredentials: userExistingCredentials.map((cred) => ({
type: "public-key",
id: cred.id,
transports: cred.transports,
})),
authenticatorSelection: {
residentKey: "required",
requireResidentKey: true,
userVerification: "preferred",
...(isPromotionFlow && { authenticatorAttachment: "platform" }),
},
};
درستیسنجی
- درستیسنجی چالش: چالش را بهطور ایمن دربرابر چالش محدود به جلسه موردانتظار درستیسنجی کنید.
- درستیسنجی حضور کاربر:
- مطمئن شوید پرچم User Present (UP) که در دادههای تجزیهشده اصالتسنج برگردانده شده است
trueباشد تا حضور فیزیکی کاربر در زمان ایجاد تأیید شود.
- مطمئن شوید پرچم User Present (UP) که در دادههای تجزیهشده اصالتسنج برگردانده شده است
- Relaxing Verification for 'preferred':
- وقتی گزینههای ایجاد
userVerification: "preferred"را مشخص کرد، تماس درستیسنجی سمت سرور باید باrequireUserVerification: falseپیکربندی شود. درغیراینصورت، اصالتسنجهایی که بدون درستیسنجی کاربر ثبت میشوند (مثلاً قفلهای صفحهنمایش غیرفعالشده) باعث ایجاد خطاهای درستیسنجی سرور کاذب میشوند.
- وقتی گزینههای ایجاد
منطق سمت کارخواه
- دروازه واسط کاربر در بارگیری صفحه:
- هنگام بار شدن صفحه،
PublicKeyCredential.getClientCapabilities()را فراخوانی کنید و اگرconditionalGetیاpasskeyPlatformAuthenticatorدردسترس نیست، دکمه «ایجاد گذرکلید» را غیرفعال کنید.
- هنگام بار شدن صفحه،
- فراخوانی ایجاد و سریالسازی: گزینههای سرور را با
PublicKeyCredential.parseCreationOptionsFromJSON()رمزگشایی کنید و پیکربندی حاصل را بهnavigator.credentials.create()ارسال کنید.- قبلاز واکشی نقطه پایانی درستیسنجی،
credential.toJSON()را فراخوانی کنید تاAuthenticatorAttestationResponseرا در یک شیء معتبر و قابلسریالسازی JSON کدبندی کند.
- قبلاز واکشی نقطه پایانی درستیسنجی،
- رسیدگی به استثناهای WebAuthn:
InvalidStateError: گذرکلید منطبقی ازقبل وجود دارد (منطبق باexcludeCredentials).NotAllowedError: کاربر کادر گفتگوی گذرکلید اصالتسنجی را لغو کرد یا زمان آن بهپایان رسید.AbortError: عملیات لغو شده است.SecurityError: مبدأهای امن (HTTPS) یا خطاهای عدم تطابق شناسه RP (مشکلات پیکربندی).
- Try/Catch Segregation for Signal API:
- Wrap server verification
fetch()call in a try/catch block. وقتی واکشی درستیسنجی سرور ناموفق بود (هر وضعیتresponse.ok === falseیا خطای شبکه)،signalUnknownCredential()را فراخوانی کنید.
- Wrap server verification
// optionsFetch and registerVerifyFetch are app-defined HTTP methods
import { optionsFetch, registerVerifyFetch } from "./api.js";
async function registerPasskey(isPromotion = false) {
// Verify passkey capability and conditional UI are available
const capabilities = await PublicKeyCredential.getClientCapabilities();
if (
!capabilities.passkeyPlatformAuthenticator ||
!capabilities.conditionalGet
) {
// Hide "Create passkey" buttons and fall back to password flows instead
showStandardPasswordFallbackUI();
return;
}
const creationOptionsJSON = await optionsFetch({ promotion: isPromotion });
const publicKey =
PublicKeyCredential.parseCreationOptionsFromJSON(creationOptionsJSON);
let credential;
try {
// passkey prompt execution
credential = await navigator.credentials.create({ publicKey });
} catch (err) {
if (err.name === "InvalidStateError") {
console.log("A passkey already exists for this account.");
alert("A passkey already exists for this account.");
} else if (err.name === "SecurityError") {
console.error("Configuration RP ID or Secure Context error.");
alert("Configuration RP ID or Secure Context error.");
} else if (err.name === "NotAllowedError") {
console.log("User cancelled the passkey dialog.");
} else if (err.name === "AbortError") {
console.log("The creation operation has been aborted.");
}
return; // Safe API exit, do not signal unknown for standard WebAuthn cancels
}
// Server Verification phase (Segregated Try/Catch)
let encodedResponse = credential.toJSON();
try {
const response = await registerVerifyFetch(encodedResponse);
if (!response.ok) {
// Server verification failed to verify/authenticate the credential (orphaned)
await PublicKeyCredential.signalUnknownCredential({
rpId, // RP ID must match the one defined on the server
credentialId: encodedResponse.id, // Base64URL-encoded credential ID
});
}
} catch (serverErr) {
console.error("Server verification network failure:", serverErr);
await publickeycredential.signalunknowncredential({
rpId, // RP ID must match the one defined on the server
credentialid: encodedresponse.id, // base64url-encoded credential id
});
}
}
راهبردهای جایگزین
جایگزین همگامسازی Signal API
WebAuthn Signal API (webauthn-signals) یک بهینهسازی پیشرونده است که برای همگام نگه داشتن مدیران گذرواژه با وضعیت اعتبارنامه سرور استفاده میشود.
- تجربه بازگشت: اگر
PublicKeyCredential.signalUnknownCredentialتوسط مرورگر پشتیبانی نشود، تماس باید بهطور ایمن ازطریق دروازه تشخیص ویژگی (if (PublicKeyCredential.signalUnknownCredential)) دور زده شود و درستیسنجی سمت سرور بهسادگی شکست را بدون راهاندازی بهروزرسانیهای مدیر ثبت میکند.
Easy JSON Serialization Fallback
همیشه «webauthn-polyfills» را نصب کنید و آن را در بافت وارد کنید.
درنظر بگیرید که تا زمانی که PublicKeyCredential پشتیبانی میشود، PublicKeyCredential.parseCreationOptionsFromJSON و PublicKeyCredential.prototype.toJSON نیز پشتیبانی میشوند.
import 'webauthn-polyfills';