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

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

ایجی کیتامورا
ایجی کیتامورا

استفاده از کلیدهای عبور به جای گذرواژه یک راه عالی برای وب سایت ها است تا حساب های کاربری خود را ایمن تر، ساده تر، استفاده آسان تر و بدون رمز عبور کنند. با یک رمز عبور، کاربر می تواند تنها با استفاده از اثر انگشت، چهره یا پین دستگاه خود وارد یک وب سایت یا برنامه شود.

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

چگونه کار می کند

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

  • زمانی که کاربر با استفاده از رمز عبور وارد سیستم می شود.
  • هنگامی که کاربر با استفاده از کلید عبور از دستگاه دیگری وارد سیستم می شود (یعنی authenticatorAttachment cross-platform است).
  • در یک صفحه اختصاصی که در آن کاربران می توانند رمز عبور خود را مدیریت کنند.

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

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

  • Backend : سرور باطن شما که پایگاه داده حساب ها را نگه می دارد و کلید عمومی و سایر ابرداده های مربوط به کلید عبور را ذخیره می کند.
  • Frontend : نمای ظاهری شما که با مرورگر ارتباط برقرار می کند و درخواست های واکشی را به باطن ارسال می کند.
  • مرورگر : مرورگر کاربر که جاوا اسکریپت شما را اجرا می کند.
  • Authenticator : احراز هویت کاربر که کلید عبور را ایجاد و ذخیره می کند. این ممکن است در همان دستگاه مرورگر (مثلاً هنگام استفاده از Windows Hello) یا در دستگاه دیگری مانند تلفن باشد.
نمودار ثبت رمز عبور

مسیر افزودن یک رمز عبور جدید به حساب کاربری موجود به شرح زیر است:

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

سازگاری ها

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

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

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

تشخیص ویژگی

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

  • این مرورگر از WebAuthn پشتیبانی می کند.
  • دستگاه از احراز هویت پلت فرم پشتیبانی می کند (می تواند یک رمز عبور ایجاد کند و با کلید عبور احراز هویت کند).
  • مرورگر از رابط کاربری شرطی WebAuthn پشتیبانی می کند.
// 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  
    }  
  });  
}  

تا زمانی که همه شرایط برآورده نشود، کلیدهای عبور در این مرورگر پشتیبانی نمی شوند. دکمه "ایجاد رمز عبور جدید" نباید تا آن زمان نمایش داده شود.

اطلاعات مهم را از باطن دریافت کنید

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

  • challenge : یک چالش ایجاد شده توسط سرور در ArrayBuffer برای این ثبت نام. این مورد ضروری است اما در هنگام ثبت نام استفاده نمی شود مگر اینکه گواهینامه انجام دهید - موضوع پیشرفته ای که در اینجا پوشش داده نمی شود.
  • user.id : شناسه منحصر به فرد کاربر. این مقدار باید یک ArrayBuffer باشد که شامل اطلاعات شناسایی شخصی، به عنوان مثال، آدرس‌های ایمیل یا نام‌های کاربری نباشد. یک مقدار تصادفی 16 بایتی ایجاد شده در هر حساب به خوبی کار خواهد کرد.
  • user.name : این فیلد باید یک شناسه منحصر به فرد برای حساب داشته باشد که کاربر آن را تشخیص می دهد، مانند آدرس ایمیل یا نام کاربری خود. این در انتخابگر حساب نمایش داده می شود. (اگر از نام کاربری استفاده می کنید، از همان مقداری که در احراز هویت رمز عبور استفاده می کنید استفاده کنید.)
  • user.displayName : این فیلد یک نام ضروری و کاربرپسندتر برای حساب است. لازم نیست این نام منحصر به فرد باشد و می تواند نام انتخابی کاربر باشد. اگر سایت شما مقدار مناسبی برای درج در اینجا ندارد، یک رشته خالی ارسال کنید. این ممکن است بسته به مرورگر در انتخابگر حساب نمایش داده شود.
  • excludeCredentials : با ارائه فهرستی از شناسه‌های اعتبار قبلاً ثبت‌شده، از ثبت یک دستگاه جلوگیری می‌کند. عضو transports ، در صورت ارائه، باید حاوی نتیجه فراخوانی getTransports() در هنگام ثبت هر اعتبار باشد.

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

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

const publicKeyCredentialCreationOptions = {
  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,
  }
};

const credential = await navigator.credentials.create({
  publicKey: publicKeyCredentialCreationOptions
});

// Encode and send the credential to the server for verification.  

پارامترهایی که در بالا توضیح داده نشده اند عبارتند از:

  • 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.

  • pubKeyCredParams : این فیلد الگوریتم های کلید عمومی پشتیبانی شده توسط RP را مشخص می کند. توصیه می کنیم آن را روی [{alg: -7, type: "public-key"},{alg: -257, type: "public-key"}] تنظیم کنید. این پشتیبانی از ECDSA با P-256 و RSA PKCS#1 را مشخص می کند و پشتیبانی از آنها پوشش کاملی را ارائه می دهد.

  • authenticatorSelection.authenticatorAttachment : اگر این ایجاد رمز عبور ارتقاء یک رمز عبور است، مثلاً در تبلیغات پس از ورود به سیستم، این را روی "platform" تنظیم کنید. "platform" نشان می دهد که RP یک تأیید کننده پلت فرم (یک احراز هویت تعبیه شده در دستگاه پلت فرم) می خواهد که به عنوان مثال یک کلید امنیتی USB را درج نمی کند. کاربر گزینه ساده تری برای ایجاد رمز عبور دارد.

  • authenticatorSelection.requireResidentKey : آن را روی "true" بولی تنظیم کنید. یک اعتبار قابل کشف (کلید مقیم) اطلاعات کاربر را در کلید عبور ذخیره می کند و به کاربران اجازه می دهد حساب را پس از احراز هویت انتخاب کنند.

  • authenticatorSelection.userVerification : نشان می دهد که آیا تأیید کاربر با استفاده از قفل صفحه دستگاه "required" ، "preferred" یا "discouraged" است. پیش‌فرض "preferred" است، به این معنی که احراز هویت ممکن است تأیید کاربر را رد کند. این را روی "preferred" تنظیم کنید یا ویژگی را حذف کنید.

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

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

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

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

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

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

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

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

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

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

  • شناسه اعتبار (کلید اصلی)
  • شناسه کاربر
  • کلید عمومی

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

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

منابع