اگرچه اعتبارنامههای FIDO مانند کلیدهای عبور، جایگزینی برای رمزهای عبور هستند، اما اکثر آنها میتوانند کاربر را از تایپ نام کاربری بینیاز کنند. این امر به کاربران امکان میدهد تا با انتخاب یک حساب کاربری از لیست کلیدهای عبوری که برای وبسایت فعلی دارند، احراز هویت کنند.
نسخههای اولیه کلیدهای امنیتی به عنوان روشهای احراز هویت دو مرحلهای طراحی شده بودند و به شناسههای اعتبارنامههای احتمالی نیاز داشتند، بنابراین ورود نام کاربری الزامی بود. اعتبارنامههایی که یک کلید امنیتی میتواند بدون دانستن شناسههای آنها پیدا کند، اعتبارنامههای قابل کشف نامیده میشوند. اکثر اعتبارنامههای FIDO که امروزه ایجاد میشوند، اعتبارنامههای قابل کشف هستند؛ به ویژه کلیدهای عبور ذخیره شده در یک مدیر رمز عبور یا روی یک کلید امنیتی مدرن.
برای اطمینان از اینکه اعتبارنامههای شما به عنوان کلیدهای عبور (اعتبارنامههای قابل کشف) ایجاد میشوند، هنگام ایجاد اعتبارنامه residentKey و requireResidentKey را مشخص کنید.
طرفهای وابسته (RP) میتوانند با حذف allowCredentials در طول احراز هویت کلید عبور، از اعتبارنامههای قابل کشف استفاده کنند. در این موارد، مرورگر یا سیستم لیستی از کلیدهای عبور موجود را که توسط ویژگی user.name تنظیم شده در زمان ایجاد مشخص شدهاند، به کاربر نشان میدهد. اگر کاربر یکی را انتخاب کند، مقدار user.id در امضای حاصل گنجانده میشود. سپس سرور میتواند از آن یا شناسه اعتبارنامه برگردانده شده برای جستجوی حساب به جای نام کاربری تایپ شده استفاده کند.
رابطهای کاربری انتخابکننده حساب، مانند مواردی که قبلاً مورد بحث قرار گرفتند، هرگز اعتبارنامههای غیرقابل کشف را نشان نمیدهند.
requireResidentKey و residentKey
برای ایجاد یک کلید عبور، authenticatorSelection.residentKey و authenticatorSelection.requireResidentKey را در navigator.credentials.create() با مقادیر مشخص شده به شرح زیر مشخص کنید.
async function register () {
// ...
const publicKeyCredentialCreationOptions = {
// ...
authenticatorSelection: {
authenticatorAttachment: 'platform',
residentKey: 'required',
requireResidentKey: true,
}
};
const credential = await navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
residentKey :
-
'required': یک اعتبارنامه قابل کشف باید ایجاد شود. اگر ایجاد آن امکانپذیر نباشد،NotSupportedErrorبرگردانده میشود. -
'preferred': RP ترجیح میدهد یک اعتبارنامه قابل کشف ایجاد کند، اما اعتبارنامه غیرقابل کشف را نیز میپذیرد. -
'discouraged': RP ترجیح میدهد یک اعتبارنامه غیرقابل کشف ایجاد کند، اما اعتبارنامه قابل کشف را میپذیرد.
requireResidentKey :
- این ویژگی برای سازگاری با نسخههای قبلی WebAuthn سطح ۱، که نسخه قدیمیتر این مشخصات است، حفظ شده است. اگر
residentKey'required'است، این مقدار را رویtrueتنظیم کنید، در غیر این صورت آن را رویfalseتنظیم کنید.
allowCredentials
RPها میتوانند allowCredentials در navigator.credentials.get() برای کنترل تجربه احراز هویت با کلید عبور استفاده کنند. معمولاً سه نوع تجربه احراز هویت با کلید عبور وجود دارد:
نمایش یک انتخابگر حساب کاربری مودال
با اعتبارنامههای قابل کشف، RPها میتوانند یک انتخابگر حساب کاربری را برای کاربر نمایش دهند تا یک حساب کاربری را برای ورود انتخاب کند و پس از آن تأیید کاربر انجام شود. این برای جریان احراز هویت با کلید عبور که با فشار دادن دکمهای که به احراز هویت با کلید عبور اختصاص داده شده است، آغاز میشود، مناسب است.
برای دستیابی به این تجربه کاربری، پارامتر allowCredentials را در تابع navigator.credentials.get() حذف یا یک آرایه خالی به آن ارسال کنید.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
نمایش تکمیل خودکار فرم رمز عبور
انتخابگر حساب کاربری مودال که در بالا توضیح داده شد، در صورتی که اکثر کاربران از کلیدهای عبور استفاده کنند و آنها را در دستگاه محلی در دسترس داشته باشند، به خوبی کار میکند. برای کاربری که کلیدهای عبور محلی ندارد، کادر محاورهای مودال همچنان ظاهر میشود و به کاربر پیشنهاد میدهد که یک کلید عبور از دستگاه دیگری ارائه دهد. هنگام انتقال کاربران خود به کلیدهای عبور، ممکن است بخواهید از آن رابط کاربری برای کاربرانی که هنوز آن را تنظیم نکردهاند، اجتناب کنید.
در عوض، انتخاب کلید عبور میتواند در کنار نامهای کاربری و رمزهای عبور ذخیره شده، در فرمهای تکمیل خودکار فیلدها در فرم ورود به سیستم سنتی قرار گیرد. به این ترتیب، کاربری که کلید عبور دارد میتواند با انتخاب کلید عبور خود فرم ورود را "پر" کند، کاربرانی که جفت نام کاربری/رمز عبور ذخیره شده دارند میتوانند آنها را انتخاب کنند و کاربرانی که هیچکدام را ندارند، همچنان میتوانند نام کاربری و رمز عبور خود را تایپ کنند.
این تجربه کاربری زمانی ایدهآل است که RP در حال انتقال با استفاده ترکیبی از رمزهای عبور و کلیدهای عبور باشد.
برای دستیابی به این تجربه کاربری، علاوه بر ارسال یک آرایه خالی به ویژگی allowCredentials یا حذف پارامتر، mediation: 'conditional' در navigator.credentials.get() مشخص کنید و یک فیلد ورودی username HTML را با autocomplete="username webauthn" یا یک فیلد ورودی password را با autocomplete="password webauthn" حاشیهنویسی کنید.
فراخوانی navigator.credentials.get() باعث نمایش هیچ رابط کاربری نمیشود، اما اگر کاربر روی فیلد ورودی حاشیهنویسیشده فوکوس کند، هر کلید عبور موجود در گزینههای تکمیل خودکار گنجانده میشود. اگر کاربر یکی را انتخاب کند، از طریق تأیید باز کردن قفل دستگاه معمولی عبور میکند و تنها در آن صورت است که promise برگردانده شده توسط .get() با نتیجهای حل میشود. اگر کاربر کلید عبوری را انتخاب نکند، promise هرگز حل نمیشود.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// You can omit `allowCredentials` as well:
allowCredentials: []
};
const cred = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal,
// Specify 'conditional' to activate conditional UI
mediation: 'conditional'
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
<input type="text" name="username" autocomplete="username webauthn" ...>
شما میتوانید نحوهی ایجاد این تجربهی کاربری را در «ورود با رمز عبور از طریق تکمیل خودکار فرم» و همچنین « پیادهسازی رمزهای عبور با تکمیل خودکار فرم در آزمایشگاه کد برنامهی وب» بیاموزید.
احراز هویت مجدد
در برخی موارد، مانند استفاده از کلیدهای عبور برای احراز هویت مجدد، شناسه کاربر از قبل مشخص است. در این حالت، ما میخواهیم از یک کلید عبور استفاده کنیم بدون اینکه مرورگر یا سیستم عامل هیچ شکلی از انتخابگر حساب را نشان دهد. این امر میتواند با ارسال لیستی از شناسههای اعتبارنامه در پارامتر allowCredentials حاصل شود.
در این صورت، اگر هر یک از اطلاعات احراز هویت نامبردهشده بهصورت محلی در دسترس باشند، از کاربر خواسته میشود که فوراً قفل دستگاه را باز کند. در غیر این صورت، از کاربر خواسته میشود دستگاه دیگری (تلفن یا کلید امنیتی) که دارای اطلاعات احراز هویت معتبر است را ارائه دهد.
برای دستیابی به این تجربه کاربری، فهرستی از شناسههای اعتبارنامه (credential IDs) را برای کاربر در حال ورود ارائه دهید. RP باید بتواند آنها را جستجو کند زیرا کاربر از قبل شناخته شده است. شناسههای اعتبارنامه را به عنوان اشیاء PublicKeyCredentialDescriptor در ویژگی allowCredentials در navigator.credentials.get() ارائه دهید.
async function authenticate() {
// ...
const publicKeyCredentialRequestOptions = {
// Server generated challenge:
challenge: ****,
// The same RP ID as used during registration:
rpId: 'example.com',
// Provide a list of PublicKeyCredentialDescriptors:
allowCredentials: [{
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, {
id: ****,
type: 'public-key',
transports: [
'internal',
'hybrid'
]
}, ...]
};
const credential = await navigator.credentials.get({
publicKey: publicKeyCredentialRequestOptions,
signal: abortController.signal
});
// This does not run until the user selects a passkey.
const credential = {};
credential.id = cred.id;
credential.rawId = cred.id; // Pass a Base64URL encoded ID string.
credential.type = cred.type;
// ...
}
یک شیء PublicKeyCredentialDescriptor شامل موارد زیر است:
-
id: شناسهی اعتبارنامهی کلید عمومی که RP در ثبت رمز عبور به دست آورده است. -
type: این فیلد معمولاً'public-key'است. -
transports: اشارهای به انتقالهای پشتیبانیشده توسط دستگاهی که این اعتبارنامه را در اختیار دارد، که توسط مرورگرها برای بهینهسازی رابط کاربری که از کاربر میخواهد یک دستگاه خارجی ارائه دهد، استفاده میشود. این لیست، در صورت ارائه، باید حاوی نتیجه فراخوانیgetTransports()در طول ثبت هر اعتبارنامه باشد.
خلاصه
اعتبارنامههای قابل کشف، با فراهم کردن امکان صرف نظر کردن از وارد کردن نام کاربری، تجربه ورود به سیستم با کلید عبور را بسیار کاربرپسندتر میکنند. با ترکیب residentKey ، requireResidentKey و allowCredentials ، کاربران RP میتوانند به تجربههای ورود به سیستمی دست یابند که:
- یک انتخابگر حساب کاربری مودال نمایش دهید.
- نمایش تکمیل خودکار فرم رمز عبور.
- احراز هویت مجدد.
از اعتبارنامههای قابل کشف عاقلانه استفاده کنید. با انجام این کار، میتوانید تجربیات ورود به سیستم با رمز عبور پیچیدهای را طراحی کنید که کاربران آن را یکپارچه یافته و احتمال بیشتری برای تعامل با آن داشته باشند.