یک رمز عبور برای ورود بدون رمز عبور ایجاد کنید

کلیدهای عبور حساب‌های کاربری را ایمن‌تر، ساده‌تر و استفاده آسان‌تر می‌کنند.

استفاده از کلیدهای عبور امنیت را افزایش می دهد، ورود به سیستم را ساده می کند و رمزهای عبور را جایگزین می کند. برخلاف رمزهای عبور معمولی که کاربران باید آن‌ها را به خاطر بسپارند و به صورت دستی وارد کنند، کلیدهای عبور از مکانیسم‌های قفل صفحه دستگاه مانند بیومتریک یا پین استفاده می‌کنند و خطرات فیشینگ و سرقت اعتبار را کاهش می‌دهند.

کلیدهای عبور با استفاده از ارائه دهندگان رمز عبور مانند Google Password Manager و iCloud Keychain در دستگاه‌ها همگام‌سازی می‌شوند.

یک رمز عبور باید ایجاد شود، کلید خصوصی را به‌طور ایمن در ارائه‌دهنده کلید عبور به همراه ابرداده‌های لازم و کلید عمومی آن برای احراز هویت در سرور شما ذخیره می‌کند. کلید خصوصی پس از تأیید کاربر در دامنه معتبر امضایی صادر می کند که کلیدهای عبور را در برابر فیشینگ مقاوم می کند. کلید عمومی بدون ذخیره اطلاعات کاربری حساس امضا را تأیید می کند و کلیدهای عبور را در برابر سرقت اعتبار مقاوم می کند.

چگونه ایجاد یک رمز عبور کار می کند

قبل از اینکه کاربر بتواند با یک رمز عبور وارد سیستم شود، باید کلید عبور را ایجاد کنید، آن را با یک حساب کاربری مرتبط کنید و کلید عمومی آن را در سرور خود ذخیره کنید.

می توانید از کاربران بخواهید که در یکی از شرایط زیر یک رمز عبور ایجاد کنند:

  • در حین یا پس از ثبت نام
  • پس از ورود به سیستم.
  • پس از ورود به سیستم با استفاده از کلید عبور از دستگاه دیگری (یعنی [authenticatorAttachment](https://web.dev/articles/passkey-form-autofill#authenticator-attachment) cross-platform است).
  • در یک صفحه اختصاصی که در آن کاربران می توانند رمز عبور خود را مدیریت کنند.

برای ایجاد یک رمز عبور، از WebAuthn API استفاده می کنید.

چهار جزء جریان ثبت رمز عبور عبارتند از:

  • Backend : جزئیات حساب کاربری، از جمله کلید عمومی را ذخیره می کند.
  • Frontend : با مرورگر ارتباط برقرار می کند و داده های لازم را از باطن دریافت می کند.
  • مرورگر : جاوا اسکریپت شما را اجرا می کند و با WebAuthn API تعامل دارد.
  • ارائه دهنده رمز عبور : رمز عبور را ایجاد و ذخیره می کند. این معمولاً یک مدیر رمز عبور مانند Google Password Manager یا یک کلید امنیتی است.
فرآیند ایجاد و ثبت رمز عبور
فرآیند ایجاد و ثبت رمز عبور.

قبل از ایجاد رمز عبور، مطمئن شوید که سیستم این پیش نیازها را برآورده می کند:

  • حساب کاربری از طریق یک روش امن (به عنوان مثال، ایمیل، تأیید تلفن یا فدراسیون هویت) در یک پنجره به طور معنی‌دار کوتاه تأیید می‌شود.

  • فرانت اند و باطن می توانند به طور ایمن برای تبادل داده های اعتباری ارتباط برقرار کنند.

  • مرورگر از ایجاد WebAuthn و رمز عبور پشتیبانی می کند.

ما می توانیم به شما نشان دهیم که چگونه بیشتر آنها را در بخش های زیر بررسی کنید.

هنگامی که سیستم این شرایط را برآورده می کند، فرآیند زیر برای ایجاد یک رمز عبور اتفاق می افتد:

  1. هنگامی که کاربر اقدام را آغاز می کند، سیستم فرآیند ایجاد رمز عبور را آغاز می کند (به عنوان مثال، کلیک کردن بر روی دکمه "ایجاد یک رمز عبور" در صفحه مدیریت رمز عبور خود یا پس از اتمام ثبت نام).
  2. فرانت‌اند داده‌های اعتبار لازم را از پشتیبان درخواست می‌کند، از جمله اطلاعات کاربر، چالش، و شناسه‌های اعتبار برای جلوگیری از تکرار.
  3. فرانت‌اند navigator.credentials.create() را فراخوانی می‌کند تا از ارائه‌دهنده رمز عبور دستگاه بخواهد با استفاده از اطلاعات پشتیبان یک کلید عبور تولید کند. توجه داشته باشید که این تماس یک وعده را برمی گرداند.
  4. دستگاه کاربر با استفاده از روش بیومتریک، پین یا الگوی برای ایجاد رمز عبور، کاربر را احراز هویت می کند.
  5. ارائه‌دهنده رمز عبور یک کلید عبور ایجاد می‌کند و یک اعتبار کلید عمومی را به جلویی باز می‌گرداند و وعده را حل می‌کند.
  6. فرانت اند اعتبار کلید عمومی تولید شده را به باطن ارسال می کند.
  7. Backend کلید عمومی و سایر داده های مهم را برای احراز هویت آینده ذخیره می کند.
  8. پشتیبان به کاربر اطلاع می دهد (به عنوان مثال، با استفاده از ایمیل) تا ایجاد رمز عبور را تأیید کند و دسترسی غیرمجاز احتمالی را شناسایی کند.

این فرآیند یک فرآیند ثبت نام رمز عبور امن و بدون درز را برای کاربران تضمین می کند.

سازگاری ها

اکثر مرورگرها از WebAuthn پشتیبانی می کنند، با برخی شکاف های جزئی. برای جزئیات سازگاری مرورگر و سیستم عامل به passkeys.dev مراجعه کنید.

یک رمز عبور جدید ایجاد کنید

برای ایجاد یک رمز عبور جدید، این فرآیندی است که frontend باید دنبال کند:

  1. سازگاری را بررسی کنید.
  2. واکشی اطلاعات از باطن
  3. برای ایجاد یک رمز عبور WebAuth API را فراخوانی کنید.
  4. کلید عمومی برگشتی را به باطن ارسال کنید.
  5. اعتبارنامه را ذخیره کنید.

بخش های زیر نشان می دهد که چگونه می توانید این کار را انجام دهید.

سازگاری را بررسی کنید

قبل از نمایش دکمه «ایجاد یک رمز عبور جدید»، بخش جلویی باید بررسی کند که آیا:

  • مرورگر از WebAuthn با PublicKeyCredential پشتیبانی می کند.

Browser Support

  • کروم: 67.
  • لبه: 18.
  • فایرفاکس: 60.
  • سافاری: 13.

Source

  • دستگاه از یک authenticator پلت فرم (می تواند یک رمز عبور ایجاد کند و با کلید عبور احراز هویت کند) با PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable() پشتیبانی می کند.

Browser Support

  • کروم: 67.
  • لبه: 18.
  • فایرفاکس: 60.
  • سافاری: 13.

Source

  • مرورگر از UI شرطی WebAuthn با PublicKeyCredenital.isConditionalMediationAvailable() پشتیبانی می کند.

Browser Support

  • کروم: 108.
  • لبه: 108.
  • فایرفاکس: 119.
  • سافاری: 16.

Source

قطعه کد زیر نشان می دهد که چگونه می توانید قبل از نمایش گزینه های مربوط به کلید عبور، سازگاری را بررسی کنید.

// Availability of `window.PublicKeyCredential` means WebAuthn is usable.  
// `isUserVerifyingPlatformAuthenticatorAvailable` means the feature detection is usable.  
// `isConditionalMediationAvailable` means the feature detection is usable.  
if (window.PublicKeyCredential &&  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable &&  
    PublicKeyCredential.isConditionalMediationAvailable) {  
  // Check if user verifying platform authenticator is available.  
  Promise.all([  
    PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable(),  
    PublicKeyCredential.isConditionalMediationAvailable(),  
  ]).then(results => {  
    if (results.every(r => r === true)) {  
      // Display "Create a new passkey" button  
    }  
  });  
}  

در این مثال، دکمه Create a new passkey تنها در صورتی باید نمایش داده شود که تمام شرایط وجود داشته باشد.

واکشی اطلاعات از باطن

هنگامی که کاربر روی دکمه کلیک کرد، اطلاعات مورد نیاز را از پشتیبان برای فراخوانی navigator.credentials.create() واکشی کنید.

قطعه کد زیر یک شی JSON را با اطلاعات مورد نیاز برای فراخوانی navigator.credentials.create() نشان می دهد:

// Example `PublicKeyCredentialCreationOptions` contents
{
  challenge: *****,
  rp: {
    name: "Example",
    id: "example.com",
  },
  user: {
    id: *****,
    name: "john78",
    displayName: "John",
  },
  pubKeyCredParams: [{
    alg: -7, type: "public-key"
  },{
    alg: -257, type: "public-key"
  }],
  excludeCredentials: [{
    id: *****,
    type: 'public-key',
    transports: ['internal'],
  }],
  authenticatorSelection: {
    authenticatorAttachment: "platform",
    requireResidentKey: true,
  }
}

جفت های کلید-مقدار در شی اطلاعات زیر را در خود دارند:

  • challenge : یک چالش ایجاد شده توسط سرور در ArrayBuffer برای این ثبت نام.
  • rp.id : شناسه RP (شناسه طرف متکی)، دامنه و وب سایت می توانند دامنه یا پسوند قابل ثبت آن را مشخص کنند. برای مثال، اگر مبدا یک RP https://login.example.com:1337 باشد، شناسه RP می تواند login.example.com یا example.com باشد. اگر شناسه RP به عنوان example.com مشخص شده باشد، کاربر می تواند در login.example.com یا در هر زیردامنه در example.com احراز هویت کند. ببینید، برای اطلاعات بیشتر در این مورد، اجازه استفاده مجدد از کلید عبور را در سایت‌های خود با درخواست‌های مبدا مرتبط بدهید .
  • rp.name : نام RP (حزب متکی). این در WebAuthn L3 منسوخ شده است اما به دلایل سازگاری گنجانده شده است.
  • user.id : یک شناسه کاربری منحصر به فرد در ArrayBuffer که پس از ایجاد حساب ایجاد می شود. برخلاف نام کاربری که ممکن است قابل ویرایش باشد، باید دائمی باشد. شناسه کاربر یک حساب را شناسایی می کند، اما نباید حاوی اطلاعات شناسایی شخصی (PII) باشد . احتمالاً قبلاً یک شناسه کاربری در سیستم خود دارید، اما در صورت نیاز، یک شناسه به طور خاص برای کلیدهای عبور ایجاد کنید تا آن را عاری از هرگونه PII نگه دارید.
  • user.name : یک شناسه منحصر به فرد برای حساب کاربری که کاربر آن را تشخیص می دهد، مانند آدرس ایمیل یا نام کاربری خود. این در انتخابگر حساب نمایش داده می شود.
  • user.displayName : نام مورد نیاز و کاربرپسندتر برای حساب. لازم نیست این نام منحصر به فرد باشد و می تواند نام انتخابی کاربر باشد. اگر سایت شما مقدار مناسبی برای درج در اینجا ندارد، یک رشته خالی ارسال کنید. این ممکن است بسته به مرورگر در انتخابگر حساب نمایش داده شود.
  • pubKeyCredParams : الگوریتم های کلید عمومی RP (طرف متکی) را مشخص می کند. توصیه می کنیم آن را روی [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}] تنظیم کنید. این پشتیبانی از ECDSA با P-256 و RSA PKCS#1 را مشخص می کند و پشتیبانی از آنها پوشش کاملی را ارائه می دهد.
  • excludeCredentials : فهرستی از شناسه‌های اعتبار قبلاً ثبت‌شده. با ارائه لیستی از شناسه های اعتبار ثبت شده قبلی از ثبت دوبار یک دستگاه جلوگیری می کند . عضو transports ، در صورت ارائه، باید حاوی نتیجه فراخوانی getTransports() در هنگام ثبت هر اعتبار باشد.
  • authenticatorSelection.authenticatorAttachment : اگر این ایجاد رمز عبور ارتقاء یک رمز عبور برای مثال در تبلیغات پس از ورود به سیستم باشد، این را روی "platform" به همراه hint: ['client-device'] تنظیم کنید. "platform" نشان می دهد که RP یک تأیید کننده پلتفرم (یک احراز هویت تعبیه شده در دستگاه پلتفرم) می خواهد که مثلاً از وارد کردن یک کلید امنیتی USB درخواست نکند. کاربر گزینه ساده تری برای ایجاد رمز عبور دارد.
  • authenticatorSelection.requireResidentKey : آن را روی یک true بولی تنظیم کنید. یک اعتبار قابل کشف (کلید مقیم) اطلاعات کاربر را در کلید عبور ذخیره می کند و به کاربران اجازه می دهد حساب را پس از احراز هویت انتخاب کنند.
  • authenticatorSelection.userVerification : نشان می دهد که آیا تأیید کاربر با استفاده از قفل صفحه دستگاه "required" ، "preferred" یا "discouraged" است. پیش‌فرض "preferred" است، به این معنی که احراز هویت ممکن است تأیید کاربر را رد کند. این را روی "preferred" تنظیم کنید یا ویژگی را حذف کنید.

توصیه می‌کنیم شی را روی سرور بسازید، ArrayBuffer را با Base64URL رمزگذاری کنید و آن را از قسمت جلویی واکشی کنید. به این ترتیب، می‌توانید با استفاده از PublicKeyCredential.parseCreationOptionsFromJSON() پیلود را رمزگشایی کنید و آن را مستقیماً به navigator.credentials.create() ارسال کنید.

قطعه کد زیر نشان می دهد که چگونه می توانید اطلاعات مورد نیاز برای ایجاد رمز عبور را واکشی و رمزگشایی کنید.

// Fetch an encoded `PubicKeyCredentialCreationOptions` from the server.
const _options = await fetch('/webauthn/registerRequest');

// Deserialize and decode the `PublicKeyCredentialCreationOptions`.
const decoded_options = JSON.parse(_options);
const options = PublicKeyCredential.parseCreationOptionsFromJSON(decoded_options);
...

برای ایجاد رمز عبور WebAuthn API را فراخوانی کنید

برای ایجاد یک رمز عبور جدید، navigator.credentials.create() را فراخوانی کنید. API یک وعده را برمی‌گرداند و منتظر تعامل کاربر با نمایش یک گفتگوی مدال است.

Browser Support

  • کروم: 60.
  • لبه: 18.
  • فایرفاکس: 60.
  • سافاری: 13.

Source

// Invoke WebAuthn to create a passkey.
const credential = await navigator.credentials.create({
  publicKey: options
});

اعتبار کلید عمومی بازگشتی را به باطن ارسال کنید

پس از اینکه کاربر با استفاده از قفل صفحه دستگاه تأیید شد، یک رمز عبور ایجاد می‌شود و وعده بازگشت یک شی PublicKeyCredential به frontend حل می‌شود.

قول به دلایل مختلف قابل رد است. با بررسی ویژگی name شیء Error می توانید این خطاها را کنترل کنید:

  • InvalidStateError : یک رمز عبور از قبل در دستگاه وجود دارد. هیچ گفتگوی خطایی به کاربر نشان داده نخواهد شد. سایت نباید این را به عنوان یک خطا در نظر بگیرد. کاربر می‌خواست دستگاه محلی ثبت شود و همینطور است.
  • NotAllowedError : کاربر عملیات را لغو کرده است.
  • AbortError : عملیات متوقف شده است.
  • استثناهای دیگر : اتفاق غیرمنتظره ای رخ داد. مرورگر یک گفتگوی خطا را به کاربر نشان می دهد.

شی اعتبار کلید عمومی حاوی ویژگی های زیر است:

  • id : یک شناسه کد شده Base64URL از کلید عبور ایجاد شده. این شناسه به مرورگر کمک می کند تا تشخیص دهد که آیا رمز عبور منطبق در دستگاه پس از احراز هویت وجود دارد یا خیر. این مقدار باید در پایگاه داده در backend ذخیره شود.
  • rawId : یک نسخه ArrayBuffer از شناسه اعتبار.
  • response.clientDataJSON : یک ArrayBuffer کدگذاری داده های مشتری.
  • response.attestationObject : یک شیء تأیید رمزگذاری شده ArrayBuffer. این شامل اطلاعات مهمی مانند شناسه RP، پرچم ها و کلید عمومی است.
  • authenticatorAttachment : وقتی این اعتبار روی دستگاهی با قابلیت کلید عبور ایجاد شود "platform" را برمی‌گرداند.
  • type : این فیلد همیشه روی "public-key" تنظیم می شود.

شی را با متد .toJSON() کدگذاری کنید، آن را با JSON.stringify() سریال کنید و سپس آن را به سرور ارسال کنید.

...

// Encode and serialize the `PublicKeyCredential`.
const _result = credential.toJSON();
const result = JSON.stringify(_result);

// Encode and send the credential to the server for verification.  
const response = await fetch('/webauthn/registerResponse', {
  method: 'post',
  credentials: 'same-origin',
  body: result
});
...

اعتبارنامه را ذخیره کنید

پس از دریافت اعتبار کلید عمومی در باطن، توصیه می کنیم به جای نوشتن کد خود برای پردازش اعتبار کلید عمومی، از یک کتابخانه سمت سرور یا یک راه حل استفاده کنید .

سپس می توانید اطلاعات بازیابی شده از اعتبارنامه را برای استفاده بعدی در پایگاه داده ذخیره کنید.

لیست زیر شامل خواص توصیه شده برای ذخیره است:

  • شناسه اعتبار : شناسه اعتبار با اعتبار کلید عمومی بازگردانده می شود.
  • نام اعتبار : نام اعتبار. نام آن را به نام ارائه‌دهنده کلید عبوری که ایجاد شده است، نامگذاری کنید که توسط AAGUID قابل شناسایی است .
  • شناسه کاربری : شناسه کاربری که برای ایجاد رمز عبور استفاده می شود.
  • کلید عمومی : کلید عمومی با اعتبار کلید عمومی بازگردانده می شود. این مورد برای تأیید ادعای کلید عبور لازم است.
  • تاریخ و زمان ایجاد : تاریخ و زمان ایجاد کلید عبور را ثبت کنید. این برای شناسایی رمز عبور مفید است.
  • تاریخ و زمان آخرین استفاده : آخرین تاریخ و زمانی را که کاربر از کلید عبور برای ورود به سیستم استفاده کرده است را ثبت می کند. این برای تعیین اینکه کاربر از کدام رمز عبور استفاده کرده است (یا استفاده نکرده است) مفید است.
  • AAGUID : یک شناسه منحصر به فرد ارائه دهنده کلید عبور.
  • پرچم واجد شرایط بودن پشتیبان : اگر دستگاه واجد شرایط همگام‌سازی کلید عبور باشد، درست است. این اطلاعات به کاربران کمک می‌کند تا کلیدهای عبور قابل همگام‌سازی و کلیدهای عبور متصل به دستگاه (غیر قابل همگام‌سازی) را در صفحه مدیریت کلید عبور شناسایی کنند.

دستورالعمل های دقیق تر را در ثبت نام رمز عبور سمت سرور دنبال کنید

در صورت عدم موفقیت ثبت نام، سیگنال دهید

اگر ثبت نام رمز عبور ناموفق باشد، ممکن است باعث سردرگمی کاربر شود. اگر کلید عبوری در ارائه‌دهنده رمز عبور وجود داشته باشد و برای کاربر در دسترس باشد، اما کلید عمومی مرتبط در سمت سرور ذخیره نشود، تلاش‌های ورود به سیستم با استفاده از کلید عبور هرگز موفق نمی‌شوند و عیب‌یابی آن دشوار است. اطمینان حاصل کنید که در صورت وجود این موضوع به کاربر اطلاع دهید.

برای جلوگیری از چنین شرایطی، می‌توانید با استفاده از Signal API یک رمز عبور ناشناخته را به ارائه‌دهنده رمز عبور ارسال کنید . با فراخوانی PublicKeyCredential.signalUnknownCredential() با شناسه RP و شناسه اعتبار، RP می تواند به ارائه دهنده کلید عبور اطلاع دهد که اعتبار مشخص شده حذف شده یا وجود ندارد. نحوه برخورد با این سیگنال به ارائه‌دهنده رمز عبور بستگی دارد، اما در صورت پشتیبانی، انتظار می‌رود رمز عبور مرتبط حذف شود.

// Detect authentication failure due to lack of the credential
if (response.status === 404) {
  // Feature detection
  if (PublicKeyCredential.signalUnknownCredential) {
    await PublicKeyCredential.signalUnknownCredential({
      rpId: "example.com",
      credentialId: "vI0qOggiE3OT01ZRWBYz5l4MEgU0c7PmAA" // base64url encoded credential ID
    });
  } else {
    // Encourage the user to delete the passkey from the password manager nevertheless.
    ...
  }
}

برای کسب اطلاعات بیشتر در مورد Signal API، با Signal API، کلیدهای عبور را با اعتبارنامه‌های موجود در سرور خود حفظ کنید .

یک اعلان برای کاربر ارسال کنید

ارسال یک اعلان (مانند یک ایمیل) هنگام ثبت رمز عبور به کاربران کمک می کند دسترسی غیرمجاز به حساب را شناسایی کنند. اگر مهاجم بدون اطلاع کاربر یک رمز عبور ایجاد کند، حتی پس از تغییر رمز عبور، برای سوء استفاده های بعدی در دسترس باقی می ماند. اعلان به کاربر هشدار می دهد و به جلوگیری از این امر کمک می کند.

چک لیست

  • قبل از اجازه دادن به کاربر برای ایجاد رمز عبور، کاربر را تأیید کنید (ترجیحاً با استفاده از ایمیل یا روش ایمن).
  • با استفاده از excludeCredentials از ایجاد رمزهای عبور تکراری برای همان ارائه دهنده رمز عبور جلوگیری کنید.
  • AAGUID را ذخیره کنید تا ارائه‌دهنده رمز عبور را شناسایی کنید و اعتبار کاربر را نام‌گذاری کنید.
  • اگر تلاش برای ثبت رمز عبور با PublicKeyCredential.signalUnknownCredential() ناموفق بود، سیگنال دهید.
  • پس از ایجاد و ثبت رمز عبور برای حساب کاربری، یک اعلان برای کاربر ارسال کنید.

منابع

مرحله بعدی: با یک کلید عبور از طریق تکمیل خودکار فرم وارد شوید .