একটি নিরাপত্তা কী (WebAuthn) দিয়ে দ্বি-ফ্যাক্টর প্রমাণীকরণের মাধ্যমে আপনার সাইটকে সুরক্ষিত করুন

1. আপনি কি তৈরি করবেন

আপনি একটি মৌলিক ওয়েব অ্যাপ্লিকেশন দিয়ে শুরু করবেন যা পাসওয়ার্ড-ভিত্তিক লগইন সমর্থন করে।

তারপরে আপনি WebAuthn-এর উপর ভিত্তি করে একটি নিরাপত্তা কী-এর মাধ্যমে দ্বি-ফ্যাক্টর প্রমাণীকরণের জন্য সমর্থন যোগ করবেন। এটি করার জন্য, আপনি নিম্নলিখিতগুলি বাস্তবায়ন করবেন:

  • একটি WebAuthn শংসাপত্র নিবন্ধন করার জন্য একটি ব্যবহারকারীর জন্য একটি উপায়৷
  • একটি দ্বি-ফ্যাক্টর-প্রমাণিকরণ প্রবাহ যেখানে ব্যবহারকারীকে তাদের দ্বিতীয় ফ্যাক্টর-একটি WebAuthn শংসাপত্রের জন্য জিজ্ঞাসা করা হয়-যদি তারা একটি নিবন্ধন করে থাকে।
  • একটি শংসাপত্র ব্যবস্থাপনা ইন্টারফেস: শংসাপত্রগুলির একটি তালিকা যা ব্যবহারকারীদের শংসাপত্রগুলি পুনঃনামকরণ এবং মুছে ফেলতে সক্ষম করে৷

16ce77744061c5f7.png

সমাপ্ত ওয়েব অ্যাপটি একবার দেখুন এবং এটি চেষ্টা করে দেখুন।

2. WebAuthn সম্পর্কে

WebAuthn বেসিক

কেন WebAuthn?

ফিশিং হল ওয়েবে একটি বিশাল নিরাপত্তা সমস্যা: বেশিরভাগ অ্যাকাউন্ট লঙ্ঘন দুর্বল বা চুরি করা পাসওয়ার্ডগুলিকে কাজে লাগায় যা সাইট জুড়ে পুনরায় ব্যবহার করা হয়। এই সমস্যার জন্য শিল্পের সম্মিলিত প্রতিক্রিয়া বহু-ফ্যাক্টর প্রমাণীকরণ হয়েছে, কিন্তু বাস্তবায়নগুলি খণ্ডিত এবং অনেকে এখনও ফিশিংকে পর্যাপ্তভাবে সম্বোধন করে না।

ওয়েব প্রমাণীকরণ API, বা WebAuthn হল একটি প্রমিত ফিশিং-প্রতিরোধী প্রোটোকল যা যেকোনো ওয়েব অ্যাপ্লিকেশন ব্যবহার করতে পারে।

কিভাবে এটা কাজ করে

সূত্র: webauthn.guide

WebAuthn সার্ভারকে পাসওয়ার্ডের পরিবর্তে পাবলিক কী ক্রিপ্টোগ্রাফি ব্যবহার করে ব্যবহারকারীদের নিবন্ধন ও প্রমাণীকরণ করতে দেয়। ওয়েবসাইটগুলি একটি প্রাইভেট-পাবলিক কীপেয়ার সমন্বিত একটি শংসাপত্র তৈরি করতে পারে৷

  • ব্যক্তিগত কী ব্যবহারকারীর ডিভাইসে নিরাপদে সংরক্ষণ করা হয়।
  • সর্বজনীন কী এবং এলোমেলোভাবে তৈরি করা শংসাপত্র আইডি স্টোরেজের জন্য সার্ভারে পাঠানো হয়।

সার্ভার ব্যবহারকারীর পরিচয় প্রমাণ করতে পাবলিক কী ব্যবহার করে। এটি গোপন নয়, কারণ এটি সংশ্লিষ্ট ব্যক্তিগত কী ছাড়া অকেজো।

সুবিধা

WebAuthn এর দুটি প্রধান সুবিধা রয়েছে:

  • কোন ভাগ গোপন: সার্ভার কোন গোপন সঞ্চয়. এটি হ্যাকারদের কাছে ডেটাবেসগুলিকে কম আকর্ষণীয় করে তোলে, কারণ পাবলিক কীগুলি তাদের জন্য উপযোগী নয়।
  • স্কোপড শংসাপত্র: site.example জন্য নিবন্ধিত একটি শংসাপত্র evil-site.example এ ব্যবহার করা যাবে না। এটি WebAuthn ফিশিং-প্রমাণ করে।

ব্যবহারের ক্ষেত্রে

WebAuthn-এর জন্য একটি ব্যবহারের ক্ষেত্রে একটি নিরাপত্তা কী সহ দ্বি-ফ্যাক্টর প্রমাণীকরণ। এটি এন্টারপ্রাইজ ওয়েব অ্যাপ্লিকেশনের জন্য বিশেষভাবে প্রাসঙ্গিক হতে পারে।

ব্রাউজার সমর্থন

এটি W3C এবং FIDO দ্বারা লেখা, Google, Mozilla, Microsoft, Yubico এবং অন্যান্যদের অংশগ্রহণে।

শব্দকোষ

  • প্রমাণীকরণকারী: একটি সফ্টওয়্যার বা হার্ডওয়্যার সত্তা যা একজন ব্যবহারকারীকে নিবন্ধন করতে পারে এবং পরে নিবন্ধিত শংসাপত্রের অধিকার নিশ্চিত করতে পারে। দুটি ধরণের প্রমাণীকরণ রয়েছে:
  • রোমিং প্রমাণীকরণকারী: ব্যবহারকারী সাইন-ইন করার চেষ্টা করছেন এমন যেকোনো ডিভাইসে ব্যবহারযোগ্য একটি প্রমাণীকরণকারী। উদাহরণ: একটি USB নিরাপত্তা কী, একটি স্মার্টফোন৷
  • প্ল্যাটফর্ম প্রমাণীকরণকারী: একটি প্রমাণীকরণকারী যা ব্যবহারকারীর ডিভাইসে তৈরি করা হয়। উদাহরণ: অ্যাপলের টাচ আইডি।
  • শংসাপত্র: ব্যক্তিগত-পাবলিক কী-পেয়ার
  • নির্ভরকারী পক্ষ: (সার্ভারের জন্য) ওয়েবসাইট যা ব্যবহারকারীকে প্রমাণীকরণ করার চেষ্টা করছে
  • FIDO সার্ভার: সার্ভার যা প্রমাণীকরণের জন্য ব্যবহৃত হয়। FIDO হল FIDO জোট দ্বারা তৈরি প্রোটোকলের একটি পরিবার; এই প্রোটোকলগুলির মধ্যে একটি হল WebAuthn.

এই কর্মশালায়, আমরা একটি রোমিং প্রমাণীকরণকারী ব্যবহার করব।

3. আপনি শুরু করার আগে

আপনি কি প্রয়োজন হবে

এই কোডল্যাবটি সম্পূর্ণ করতে আপনার প্রয়োজন হবে:

  • WebAuthn এর একটি প্রাথমিক ধারণা।
  • জাভাস্ক্রিপ্ট এবং HTML এর প্রাথমিক জ্ঞান।
  • একটি আপ-টু-ডেট ব্রাউজার যা WebAuthn সমর্থন করে।
  • একটি নিরাপত্তা কী যা U2F- সম্মত

আপনি নিরাপত্তা কী হিসাবে নিম্নলিখিতগুলির মধ্যে একটি ব্যবহার করতে পারেন:

  • Android>=7 (Nougat) সহ একটি Android ফোন যা Chrome চালায়। এই ক্ষেত্রে, আপনার একটি উইন্ডোজ, ম্যাকওএস, বা ব্লুটুথ সহ Chrome OS মেশিনেরও প্রয়োজন হবে৷
  • একটি USB কী, যেমন একটি YubiKey

6539dc7ffec2538c.png

সূত্র: https://www.yubico.com/products/security-key/

dd56e2cfe0f7ced2.png

আপনি কি শিখবেন

✅ শিখবেন

  • WebAuthn প্রমাণীকরণের জন্য দ্বিতীয় ফ্যাক্টর হিসাবে কীভাবে একটি নিরাপত্তা কী নিবন্ধন এবং ব্যবহার করবেন।
  • কিভাবে এই প্রক্রিয়াটি ব্যবহারকারী-বান্ধব করা যায়।

তুমি শিখবে না ❌

  • কিভাবে একটি FIDO সার্ভার তৈরি করবেন—যে সার্ভারটি প্রমাণীকরণের জন্য ব্যবহৃত হয়। এটি ঠিক কারণ সাধারণত, একটি ওয়েব অ্যাপ্লিকেশন বা সাইট বিকাশকারী হিসাবে, আপনি বিদ্যমান FIDO সার্ভার বাস্তবায়নের উপর নির্ভর করবেন৷ আপনি যে সার্ভার বাস্তবায়নের উপর নির্ভর করেন তার কার্যকারিতা এবং গুণমান সর্বদা যাচাই করতে ভুলবেন না। এই কোডল্যাবে, FIDO সার্ভার SimpleWebAuthn ব্যবহার করে। অন্যান্য বিকল্পের জন্য, FIDO জোটের অফিসিয়াল পৃষ্ঠাটি দেখুন। ওপেন সোর্স লাইব্রেরির জন্য, webauthn.io বা AwesomeWebAuthn দেখুন।

দাবিত্যাগ

সাইন ইন করার জন্য ব্যবহারকারীকে অবশ্যই একটি পাসওয়ার্ড লিখতে হবে৷ তবে, এই কোডল্যাবে সরলতার জন্য পাসওয়ার্ডটি সংরক্ষণ বা চেক করা হয় না৷ একটি বাস্তব অ্যাপ্লিকেশনে, আপনি পরীক্ষা করবেন যে এটি সঠিক সার্ভার-সাইড।

সিএসআরএফ চেক , সেশন ভ্যালিডেশন, এবং ইনপুট স্যানিটাইজিংয়ের মতো মৌলিক নিরাপত্তা পরীক্ষাগুলি এই কোডল্যাবে প্রয়োগ করা হয়। যাইহোক, অনেক নিরাপত্তা ব্যবস্থা নয়—উদাহরণস্বরূপ, পাশবিক আক্রমণ প্রতিরোধ করার জন্য পাসওয়ার্ডের কোনো ইনপুট সীমা নেই। এটি এখানে কোন ব্যাপার না কারণ পাসওয়ার্ডগুলি সংরক্ষণ করা হয় না, তবে নিশ্চিত করুন যে এই কোডটি উৎপাদনের মতো ব্যবহার করা হচ্ছে না৷

4. আপনার প্রমাণীকরণকারী সেট আপ করুন৷

আপনি যদি একটি প্রমাণীকরণকারী হিসাবে একটি Android ফোন ব্যবহার করছেন

  • আপনার ডেস্কটপ এবং ফোন উভয়েই Chrome আপ টু ডেট আছে তা নিশ্চিত করুন৷
  • আপনার ডেস্কটপ এবং আপনার ফোন উভয়েই, Chrome খুলুন এবং একই প্রোফাইল দিয়ে সাইন ইন করুন⏤ আপনি এই কর্মশালার জন্য যে প্রোফাইলটি ব্যবহার করতে চান৷
  • আপনার ডেস্কটপ এবং ফোনে এই প্রোফাইলের জন্য সিঙ্ক চালু করুন। এর জন্য chrome://settings/syncSetup ব্যবহার করুন।
  • আপনার ডেস্কটপ এবং আপনার ফোন উভয়েই ব্লুটুথ চালু করুন।
  • ক্রোম ডেস্কটপে একই প্রোফাইলে লগ-ইন করুন, webauthn.io খুলুন।
  • একটি সাধারণ ব্যবহারকারীর নাম লিখুন। সত্যায়নের ধরন এবং প্রমাণীকরণকারীর ধরনটি None এবং অনির্দিষ্ট (ডিফল্ট) মানগুলিতে ছেড়ে দিন। নিবন্ধন ক্লিক করুন.

6b49ff0298f5a0af.png

  • একটি ব্রাউজার উইন্ডো খোলা উচিত, আপনাকে আপনার পরিচয় যাচাই করতে বলবে। তালিকা থেকে আপনার ফোন নির্বাচন করুন.

ffebe58ac826eaf2.png852de328fcd4eb42.png

  • আপনার ফোনে, আপনি আপনার পরিচয় যাচাই করুন শিরোনামে একটি বিজ্ঞপ্তি পাবেন। টোকা দিন.
  • আপনার ফোনে, আপনাকে আপনার ফোনের পিন কোড (বা ফিঙ্গারপ্রিন্ট সেন্সর স্পর্শ করার জন্য) চাওয়া হবে। এটি প্রবেশ করান।
  • আপনার ডেস্কটপে webauthn.io-এ, একটি "সফল" সূচক উপস্থিত হওয়া উচিত।

fc0acf00a4d412fa.png

  • আপনার ডেস্কটপে webauthn.io-এ, লগইন বোতামে ক্লিক করুন।
  • আবার, একটি ব্রাউজার উইন্ডো খোলা উচিত; তালিকা থেকে আপনার ফোন নির্বাচন করুন.
  • আপনার ফোনে, পপ আপ হওয়া বিজ্ঞপ্তিতে আলতো চাপুন এবং আপনার পিন লিখুন (বা ফিঙ্গারপ্রিন্ট সেন্সর স্পর্শ করুন)।
  • webauthn.io আপনাকে জানাতে হবে যে আপনি লগ ইন করেছেন। আপনার ফোন একটি নিরাপত্তা কী হিসাবে সঠিকভাবে কাজ করছে; আপনি কর্মশালার জন্য প্রস্তুত!

আপনি যদি প্রমাণীকরণকারী হিসাবে একটি USB নিরাপত্তা কী ব্যবহার করেন

  • Chrome ডেস্কটপে, webauthn.io খুলুন।
  • একটি সাধারণ ব্যবহারকারীর নাম লিখুন। সত্যায়নের ধরন এবং প্রমাণীকরণকারীর ধরনটি None এবং অনির্দিষ্ট (ডিফল্ট) মানগুলিতে ছেড়ে দিন। নিবন্ধন ক্লিক করুন.
  • একটি ব্রাউজার উইন্ডো খোলা উচিত, আপনাকে আপনার পরিচয় যাচাই করতে বলবে। তালিকায় USB নিরাপত্তা কী নির্বাচন করুন।

ffebe58ac826eaf2.png9fe75f04e43da035.png

  • আপনার ডেস্কটপে আপনার নিরাপত্তা কী প্রবেশ করান এবং এটি স্পর্শ করুন।

923d5adb8aa8286c.png

  • আপনার ডেস্কটপে webauthn.io-এ, একটি "সফল" সূচক উপস্থিত হওয়া উচিত।

fc0acf00a4d412fa.png

  • আপনার ডেস্কটপে webauthn.io-এ, লগইন বোতামে ক্লিক করুন।
  • আবার, একটি ব্রাউজার উইন্ডো খোলা উচিত; তালিকায় USB নিরাপত্তা কী নির্বাচন করুন।
  • কী স্পর্শ করুন।
  • Webauthn.io আপনাকে জানাতে হবে যে আপনি লগ ইন করেছেন। আপনার USB নিরাপত্তা কী সঠিকভাবে কাজ করছে; আপনি কর্মশালার জন্য প্রস্তুত!

7e1c0bb19c9f3043.png

5. সেট আপ করুন

এই কোডল্যাবে, আপনি Glitch ব্যবহার করবেন, একটি অনলাইন কোড সম্পাদক যা স্বয়ংক্রিয়ভাবে এবং অবিলম্বে আপনার কোড স্থাপন করে।

স্টার্টার কোড ফোর্ক করুন

স্টার্টার প্রকল্প খুলুন।

রিমিক্স বোতামে ক্লিক করুন।

এটি স্টার্টার কোডের একটি অনুলিপি তৈরি করে। আপনি এখন সম্পাদনা করার জন্য আপনার নিজস্ব কোড আছে. আপনার কাঁটা (গ্লিচ-এ "রিমিক্স" বলা হয়) যেখানে আপনি এই কোডল্যাবের জন্য সমস্ত কাজ করবেন৷

cf2b9f552c9809b6.png

স্টার্টার কোড অন্বেষণ করুন

স্টার্টার কোডটি অন্বেষণ করুন যা আপনি কিছুক্ষণের জন্য কাঁটাচামচ করেছেন।

লক্ষ্য করুন যে libs এর অধীনে, auth.js নামে একটি লাইব্রেরি ইতিমধ্যেই সরবরাহ করা হয়েছে। এটি একটি কাস্টম লাইব্রেরি যা সার্ভার-সাইড প্রমাণীকরণ যুক্তির যত্ন নেয়। এটি একটি নির্ভরতা হিসাবে fido লাইব্রেরি ব্যবহার করে।

6. শংসাপত্র নিবন্ধন বাস্তবায়ন

শংসাপত্র নিবন্ধন বাস্তবায়ন

একটি নিরাপত্তা কী দিয়ে দ্বি-ফ্যাক্টর প্রমাণীকরণ সেট আপ করার জন্য আমাদের প্রথম জিনিসটি হল ব্যবহারকারীকে একটি শংসাপত্র তৈরি করতে সক্ষম করা৷

আসুন প্রথমে একটি ফাংশন যোগ করি যা আমাদের ক্লায়েন্ট-সাইড কোডে এটি করে।

public/auth.client.js , মনে রাখবেন যে registerCredential() নামে একটি ফাংশন আছে যা এখনও কিছু করে না। এটিতে নিম্নলিখিত কোড যোগ করুন:

async function registerCredential() {
  // Fetch the credential creation options from the backend
  const credentialCreationOptionsFromServer = await _fetch(
    "/auth/credential-options",
    "POST"
  );
  // Decode the credential creation options
  const credentialCreationOptions = decodeServerOptions(
    credentialCreationOptionsFromServer
  );
  // Create a credential via the browser API; this will prompt the user to touch their security key or tap a button on their phone
  const credential = await navigator.credentials.create({
    publicKey: {
      ...credentialCreationOptions,
    }
  });
  // Encode the newly created credential to send it to the backend
  const encodedCredential = encodeCredential(credential);
  // Send the encoded credential to the backend for storage
  return await _fetch("/auth/credential", "POST", encodedCredential);
}

মনে রাখবেন যে এই ফাংশনটি ইতিমধ্যে আপনার জন্য রপ্তানি করা হয়েছে।

registerCredential ক্রেডেনশিয়াল যা করে তা এখানে:

  • এটি সার্ভার থেকে শংসাপত্র তৈরির বিকল্পগুলি নিয়ে আসে ( /auth/credential-options )
  • যেহেতু সার্ভারের বিকল্পগুলি এনকোড করে ফিরে আসে, এটি তাদের ডিকোড করতে ইউটিলিটি ফাংশন decodeServerOptions সার্ভার বিকল্প ব্যবহার করে।
  • এটি ওয়েব API navigator.credential.create কল করে একটি শংসাপত্র তৈরি করে। যখন navigator.credential.create করা হয়, ব্রাউজারটি দখল করে নেয় এবং ব্যবহারকারীকে একটি নিরাপত্তা কী বেছে নিতে অনুরোধ করে।
  • এটি নতুন তৈরি শংসাপত্রকে ডিকোড করে
  • এটি এনকোডেড শংসাপত্র ধারণ করে /auth/credential এ একটি অনুরোধ করে নতুন শংসাপত্র সার্ভার-সাইড নিবন্ধন করে।

একপাশে: সার্ভার কোডটি দেখুন

registerCredential() সার্ভারে দুটি কল করে, তাই ব্যাকএন্ডে কী ঘটছে তা দেখার জন্য একটু সময় নেওয়া যাক।

শংসাপত্র তৈরির বিকল্প

যখন ক্লায়েন্ট ( /auth/credential-options ) এর কাছে একটি অনুরোধ করে, তখন সার্ভার একটি অপশন অবজেক্ট তৈরি করে এবং ক্লায়েন্টের কাছে ফেরত পাঠায়।

এই বস্তুটি ক্লায়েন্ট দ্বারা প্রকৃত শংসাপত্র তৈরি কলে ব্যবহৃত হয়:

navigator.credentials.create({
    publicKey: {
    // Options generated server-side
    ...credentialCreationOptions
// ...
}

তাহলে, এই credentialCreationOptions এ কী আছে যা শেষ পর্যন্ত ক্লায়েন্ট-সাইড registerCredential ক্রেডেনশিয়ালে ব্যবহার করা হয়েছে যা আপনি আগের ধাপে প্রয়োগ করেছেন?

router.post("/credential-options", ... এর অধীনে সার্ভার কোডটি দেখুন।

আসুন প্রতিটি একক সম্পত্তির দিকে তাকাই না, তবে এখানে কয়েকটি আকর্ষণীয় বিষয় রয়েছে যা আপনি সার্ভার কোডের বিকল্প অবজেক্টে দেখতে পাবেন, যা fido2 লাইব্রেরি ব্যবহার করে তৈরি করা হয়েছে এবং শেষ পর্যন্ত ক্লায়েন্টের কাছে ফিরে এসেছে:

  • rpName এবং rpId সেই সংস্থাকে বর্ণনা করে যা ব্যবহারকারীকে নিবন্ধন করে এবং প্রমাণীকরণ করে। মনে রাখবেন যে WebAuthn-এ, শংসাপত্রগুলি একটি নির্দিষ্ট ডোমেনে স্কোপ করা হয়, যা একটি নিরাপত্তা সুবিধা; এখানে rpName এবং rpId শংসাপত্রের সুযোগ দিতে ব্যবহৃত হয়। একটি বৈধ rpId হল আপনার সাইটের হোস্টনাম। আপনি স্টার্টার প্রজেক্ট শুরু করার সাথে সাথে কীভাবে এগুলি স্বয়ংক্রিয়ভাবে আপডেট হবে তা নোট করুন 🧘🏻‍♀️
  • excludeCredentials হল শংসাপত্রের একটি তালিকা; নতুন শংসাপত্রটি একটি প্রমাণীকরণকারীতে তৈরি করা যাবে না যাতে excludeCredentials এ তালিকাভুক্ত শংসাপত্রগুলির একটিও রয়েছে। আমাদের কোডল্যাবে, excludeCredentials হল এই ব্যবহারকারীর জন্য বিদ্যমান শংসাপত্রের একটি তালিকা। এটি এবং user.id এর সাহায্যে, আমরা নিশ্চিত করছি যে ব্যবহারকারীর তৈরি প্রতিটি শংসাপত্র একটি ভিন্ন প্রমাণীকরণকারীতে (নিরাপত্তা কী) লাইভ হবে। এটি একটি ভাল অভ্যাস কারণ এর মানে হল যে যদি একজন ব্যবহারকারী একাধিক শংসাপত্র নিবন্ধন করে থাকে, তাহলে তারা বিভিন্ন প্রমাণীকরণকারী (নিরাপত্তা কী) এ থাকবে, তাই একটি নিরাপত্তা কী হারানো ব্যবহারকারীকে তাদের অ্যাকাউন্ট থেকে লক করবে না।
  • authenticatorSelection আপনি আপনার ওয়েব অ্যাপ্লিকেশনে অনুমোদন করতে চান এমন প্রমাণীকরণের ধরন সংজ্ঞায়িত করে। আসুন authenticatorSelection এ ঘনিষ্ঠভাবে নজর দেওয়া যাক:
    • residentKey: preferred মানে হল এই অ্যাপ্লিকেশনটি ক্লায়েন্ট-সাইড আবিষ্কারযোগ্য শংসাপত্র প্রয়োগ করে না। একটি ক্লায়েন্ট-সাইড আবিষ্কারযোগ্য শংসাপত্র হল একটি বিশেষ ধরনের শংসাপত্র যা একজন ব্যবহারকারীকে প্রথমে তাদের সনাক্ত করার প্রয়োজন ছাড়াই প্রমাণীকরণ করা সম্ভব করে। এখানে, আমরা preferred সেট আপ করেছি কারণ এই কোডল্যাবটি মৌলিক বাস্তবায়নের উপর ফোকাস করে; আবিষ্কারযোগ্য শংসাপত্রগুলি আরও উন্নত প্রবাহের জন্য।
    • ResidentKey শুধুমাত্র requireResidentKey এর সাথে ব্যাকওয়ার্ড-কম্প্যাটিবিলিটির জন্য উপস্থিত।
    • userVerification: preferred এর মানে হল যে যদি প্রমাণীকরণকারী ব্যবহারকারীর যাচাইকরণ সমর্থন করে-উদাহরণস্বরূপ, যদি এটি একটি বায়োমেট্রিক নিরাপত্তা কী বা একটি অন্তর্নির্মিত PIN বৈশিষ্ট্য সহ একটি কী-প্রমাণপত্র তৈরি করার সময় নির্ভরকারী পক্ষ এটির অনুরোধ করবে৷ যদি প্রমাণীকরণকারী না-মৌলিক নিরাপত্তা কী-তাহলে সার্ভার ব্যবহারকারী যাচাইয়ের অনুরোধ করবে না।
  • ​​pubKeyCredParam , পছন্দ অনুসারে, শংসাপত্রের পছন্দসই ক্রিপ্টোগ্রাফিক বৈশিষ্ট্য বর্ণনা করে।

এই সমস্ত বিকল্পগুলি হল সিদ্ধান্ত যা ওয়েব অ্যাপ্লিকেশনটিকে তার নিরাপত্তা মডেলের জন্য করতে হবে৷ লক্ষ্য করুন যে সার্ভারে, এই বিকল্পগুলি একটি একক authSettings অবজেক্টে সংজ্ঞায়িত করা হয়েছে।

চ্যালেঞ্জ

এখানে আরেকটি আকর্ষণীয় বিষয় হল req.session.challenge = options.challenge; .

যেহেতু WebAuthn একটি ক্রিপ্টোগ্রাফিক প্রোটোকল, এটি রিপ্লে আক্রমণ এড়াতে এলোমেলো চ্যালেঞ্জের উপর নির্ভর করে-যখন একজন আক্রমণকারী প্রমাণীকরণ পুনরায় প্লে করার জন্য একটি পেলোড চুরি করে, যখন তারা প্রাইভেট কী এর মালিক না হয় যা প্রমাণীকরণ সক্ষম করবে।

এটি প্রশমিত করার জন্য, সার্ভারে একটি চ্যালেঞ্জ তৈরি করা হয় এবং ফ্লাইতে স্বাক্ষর করা হবে; স্বাক্ষর তারপর প্রত্যাশিত সঙ্গে তুলনা করা হবে. এটি যাচাই করে যে ব্যবহারকারী শংসাপত্র তৈরির সময় ব্যক্তিগত কী আটকে রাখে।

শংসাপত্র নিবন্ধন কোড

router.post("/credential", ... এর অধীনে সার্ভার কোডটি দেখুন।

এখানেই শংসাপত্রটি সার্ভার-সাইড নিবন্ধিত হয়।

সুতরাং, সেখানে কি হচ্ছে?

এই কোডের সবচেয়ে উল্লেখযোগ্য বিটগুলির মধ্যে একটি হল যাচাইকরণ কল, fido2.verifyAttestationResponse এর মাধ্যমে :

  • স্বাক্ষরিত চ্যালেঞ্জ চেক করা হয়েছে, এবং এটি নিশ্চিত করে যে শংসাপত্রটি এমন একজনের দ্বারা তৈরি করা হয়েছে যিনি প্রকৃতপক্ষে নির্মাণের সময় ব্যক্তিগত কী আটকে রেখেছিলেন।
  • নির্ভরকারী পক্ষের আইডি, তার মূলের সাথে আবদ্ধ, যাচাই করা হয়। এটি নিশ্চিত করে যে শংসাপত্রটি এই ওয়েব অ্যাপ্লিকেশনের সাথে আবদ্ধ (এবং শুধুমাত্র এই ওয়েব অ্যাপ্লিকেশন)।

UI এ এই কার্যকারিতা যোগ করুন

এখন যেহেতু আপনার একটি শংসাপত্র তৈরি করার ফাংশন, ``registerCredential() , প্রস্তুত, চলুন এটি ব্যবহারকারীর জন্য উপলব্ধ করা যাক।

আপনি অ্যাকাউন্ট পৃষ্ঠা থেকে এটি করতে যাচ্ছেন, কারণ এটি প্রমাণীকরণ পরিচালনার জন্য একটি সাধারণ অবস্থান।

account.html এর মার্কআপে, ব্যবহারকারীর নামের নীচে, একটি লেআউট ক্লাস class="flex-h-between" সহ এখন পর্যন্ত একটি খালি div রয়েছে। আমরা এই div UI উপাদানগুলির জন্য ব্যবহার করব যা 2FA কার্যকারিতার সাথে সম্পর্কিত।

এই ডিভিতে যোগ করুন:

  • একটি শিরোনাম যা বলে "টু-ফ্যাক্টর প্রমাণীকরণ"
  • একটি শংসাপত্র তৈরি করার জন্য একটি বোতাম
 <div class="flex-h-between">
    <h3>
        Two-factor authentication
    </h3>
    <button class="create" id="registerButton" raised>
        ➕ Add a credential
    </button>
</div>

এই ডিভের নীচে, একটি শংসাপত্র ডিভ যুক্ত করুন যা আমাদের পরে প্রয়োজন হবে:

<div class="flex-h-between">
(HTML you've just added)
</div>
<div id="credentials"></div>

account.html ইনলাইন স্ক্রিপ্টে, আপনি যে ফাংশনটি তৈরি করেছেন তা আমদানি করুন এবং এটিকে কল করার জন্য একটি ফাংশন register যোগ করুন, সেইসাথে আপনি যে বোতামটি তৈরি করেছেন তার সাথে একটি ইভেন্ট হ্যান্ডলার সংযুক্ত করুন৷

// Set up the handler for the button that registers credentials
const registerButton = document.querySelector('#registerButton');
registerButton.addEventListener('click', register);

// Register a credential
async function register() {
  let user = {};
  try {
    const user = await registerCredential();
  } catch (e) {
    // Alert the user that something went wrong
    if (Array.isArray(e)) {
      alert(
        // `msg` not `message`, this is the key's name as per the express validator API
        `Registration failed. ${e.map((err) => `${err.msg} (${err.param})`)}`
      );
    } else {
      alert(`Registration failed. ${e}`);
    }
  }
}

ব্যবহারকারীর দেখার জন্য শংসাপত্রগুলি প্রদর্শন করুন

এখন যেহেতু আপনি একটি শংসাপত্র তৈরি করার কার্যকারিতা যোগ করেছেন, ব্যবহারকারীদের তাদের যোগ করা শংসাপত্রগুলি দেখতে একটি উপায় প্রয়োজন৷

অ্যাকাউন্ট পৃষ্ঠা এই জন্য একটি ভাল জায়গা.

account.html এ, updateCredentialList() নামক ফাংশনটি সন্ধান করুন।

এটিতে নিম্নলিখিত কোডটি যুক্ত করুন যা বর্তমানে লগ-ইন করা ব্যবহারকারীর জন্য সমস্ত নিবন্ধিত শংসাপত্রগুলি আনার জন্য একটি ব্যাকএন্ড কল করে এবং এটি ফিরে আসা শংসাপত্রগুলি প্রদর্শন করে:

// Update the list that displays credentials
async function updateCredentialList() {
  // Fetch the latest credential list from the backend
  const response = await _fetch('/auth/credentials', 'GET');
  const credentials = response.credentials || [];
  // Generate the credential list as HTML and pass remove/rename functions as args
  const credentialListHtml = getCredentialListHtml(
    credentials,
    removeEl,
    renameEl
  );
  // Display the list of credentials in the DOM
  const list = document.querySelector('#credentials');
  render(credentialListHtml, list);
}    

আপাতত, removeEl এবং renameEl করতে কিছু মনে করবেন না; আপনি এই কোডল্যাবে পরে তাদের সম্পর্কে শিখবেন।

account.html এর মধ্যে আপনার ইনলাইন স্ক্রিপ্টের শুরুতে updateCredentialList করতে একটি কল যোগ করুন। এই কলের মাধ্যমে, উপলভ্য শংসাপত্রগুলি আনা হয় যখন ব্যবহারকারী তাদের অ্যাকাউন্টের পৃষ্ঠায় আসে।

<script type="module">
    // ... (imports)
    // Initialize the credential list by updating it once on page load
    updateCredentialList();

এখন, registerCredential ক্রেডেনশিয়াল সফলভাবে সম্পন্ন হলে updateCredentialList কল করুন, যাতে তালিকাগুলি নতুন তৈরি শংসাপত্র প্রদর্শন করে:

async function register() {
  let user = {};
  try {
    // ...
  } catch (e) {
    // ...
  }
  // Refresh the credential list to display the new credential
  await updateCredentialList();
}

চেষ্টা কর! 👩🏻‍💻

আপনার শংসাপত্র নিবন্ধন সম্পন্ন! ব্যবহারকারীরা এখন নিরাপত্তা কী-ভিত্তিক শংসাপত্র তৈরি করতে পারে, এবং তাদের অ্যাকাউন্ট পৃষ্ঠায় তাদের কল্পনা করতে পারে।

চেষ্টা কর:

  • সাইন আউট.
  • লগ ইন করুন—যেকোনো ব্যবহারকারী এবং পাসওয়ার্ড দিয়ে। আগেই উল্লেখ করা হয়েছে, এই কোডল্যাবে জিনিসগুলি সহজ রাখার জন্য পাসওয়ার্ডটি আসলে সঠিকতার জন্য পরীক্ষা করা হয় না। কোনো অ-খালি পাসওয়ার্ড লিখুন.
  • আপনি একবার অ্যাকাউন্ট পৃষ্ঠায় গেলে, একটি শংসাপত্র যোগ করুন ক্লিক করুন।
  • আপনাকে একটি নিরাপত্তা কী ঢোকাতে এবং স্পর্শ করতে বলা উচিত। এটা কর.
  • সফল শংসাপত্র তৈরি করার পরে, শংসাপত্রটি অ্যাকাউন্টের পৃষ্ঠায় প্রদর্শিত হবে।
  • অ্যাকাউন্ট পৃষ্ঠাটি পুনরায় লোড করুন। শংসাপত্রগুলি প্রদর্শন করা উচিত।
  • আপনার কাছে দুটি কী উপলব্ধ থাকলে, শংসাপত্র হিসাবে দুটি ভিন্ন নিরাপত্তা কী যোগ করার চেষ্টা করুন। তারা উভয় প্রদর্শন করা উচিত.
  • একই প্রমাণীকরণকারী (কী) দিয়ে দুটি শংসাপত্র তৈরি করার চেষ্টা করুন; আপনি লক্ষ্য করবেন যে সমর্থন করা হবে না. এটা ইচ্ছাকৃত—এটি ব্যাকএন্ডে আমাদের excludeCredentials ব্যবহারের কারণে।

7. দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ সক্ষম করুন

আপনার ব্যবহারকারীরা শংসাপত্রগুলি নিবন্ধন এবং নিবন্ধনমুক্ত করতে পারে, তবে শংসাপত্রগুলি কেবল প্রদর্শিত হয় এবং প্রকৃতপক্ষে এখনও ব্যবহার করা হয়নি৷

এখন তাদের ব্যবহার করার সময়, এবং প্রকৃত দ্বি-ফ্যাক্টর প্রমাণীকরণ সেট আপ করুন।

এই বিভাগে, আপনি এই মৌলিক প্রবাহ থেকে আপনার ওয়েব অ্যাপ্লিকেশনে প্রমাণীকরণ প্রবাহ পরিবর্তন করবেন:

6ff49a7e520836d0.png

এই দুই-ফ্যাক্টর প্রবাহে:

e7409946cd88efc7.png

দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ প্রয়োগ করুন

আসুন প্রথমে আমাদের প্রয়োজনীয় কার্যকারিতা যোগ করি এবং ব্যাকএন্ডের সাথে যোগাযোগ বাস্তবায়ন করি; আমরা পরবর্তী ধাপে ফ্রন্টএন্ডে এটি যোগ করব।

আপনাকে এখানে প্রয়োগ করতে হবে এমন একটি ফাংশন যা ব্যবহারকারীকে একটি শংসাপত্রের সাথে প্রমাণীকরণ করে।

public/auth.client.js এ, খালি ফাংশন authenticateTwoFactor সন্ধান করুন এবং এতে নিম্নলিখিত কোড যোগ করুন:

async function authenticateTwoFactor() {
  // Fetch the 2F options from the backend
  const optionsFromServer = await _fetch("/auth/two-factor-options", "POST");
  // Decode them
  const decodedOptions = decodeServerOptions(optionsFromServer);
  // Get a credential via the browser API; this will prompt the user to touch their security key or tap a button on their phone
  const credential = await navigator.credentials.get({
    publicKey: decodedOptions
  });
  // Encode the credential
  const encodedCredential = encodeCredential(credential);
  // Send it to the backend for verification
  return await _fetch("/auth/authenticate-two-factor", "POST", {
    credential: encodedCredential
  });
}

মনে রাখবেন যে এই ফাংশনটি ইতিমধ্যে আপনার জন্য রপ্তানি করা হয়েছে; আমরা পরবর্তী ধাপে এটি প্রয়োজন হবে.

এখানে authenticateTwoFactor কি করে:

  • এটি সার্ভার থেকে দুটি ফ্যাক্টর প্রমাণীকরণ বিকল্পের জন্য অনুরোধ করে। আপনি পূর্বে দেখেছেন এমন শংসাপত্র তৈরির বিকল্পগুলির মতোই, এগুলি সার্ভারে সংজ্ঞায়িত করা হয়েছে এবং ওয়েব অ্যাপ্লিকেশনের সুরক্ষা মডেলের উপর নির্ভর করে৷ router.post("/two-factors-options", ... বিস্তারিত জানার জন্য।
  • navigator.credentials.get এ কল করার মাধ্যমে, এটি ব্রাউজারটিকে দখল করতে দেয় এবং ব্যবহারকারীকে পূর্বে নিবন্ধিত একটি কী সন্নিবেশ ও স্পর্শ করতে অনুরোধ জানায়। এর ফলে এই নির্দিষ্ট দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ অপারেশনের জন্য একটি শংসাপত্র নির্বাচন করা হয়।
  • নির্বাচিত শংসাপত্রটি তারপরে ("/auth/authenticate-two-factor"` আনার জন্য একটি ব্যাকএন্ড অনুরোধে পাস করা হয়৷ যদি শংসাপত্রটি সেই ব্যবহারকারীর জন্য বৈধ হয়, তাহলে ব্যবহারকারীকে প্রমাণীকরণ করা হয়৷

একপাশে: সার্ভার কোডটি দেখুন

নোট করুন যে server.js ইতিমধ্যে কিছু নেভিগেশন এবং অ্যাক্সেসের যত্ন নেয়: এটি নিশ্চিত করে যে অ্যাকাউন্ট পৃষ্ঠাটি শুধুমাত্র প্রমাণীকৃত ব্যবহারকারীদের দ্বারা অ্যাক্সেস করা যেতে পারে এবং কিছু প্রয়োজনীয় পুনঃনির্দেশ সম্পাদন করে।

এখন, router.post("/initialize-authentication", ... এর অধীনে সার্ভার কোডটি দেখুন।

সেখানে দুটি আকর্ষণীয় পয়েন্ট লক্ষ্য করা যায়:

  • এই পর্যায়ে পাসওয়ার্ড এবং শংসাপত্র উভয়ই একই সাথে চেক করা হয়। এটি একটি নিরাপত্তা পরিমাপ: যে ব্যবহারকারীদের দুই-ফ্যাক্টর প্রমাণীকরণ সেট আপ আছে, আমরা পাসওয়ার্ডটি সঠিক ছিল কিনা তার উপর নির্ভর করে UI ফ্লো আলাদা দেখতে চাই না। তাই আমরা এই ধাপে পাসওয়ার্ড এবং শংসাপত্র উভয়ই একই সাথে পরীক্ষা করি।
  • যদি পাসওয়ার্ড এবং শংসাপত্র উভয়ই বৈধ হয়, তাহলে আমরা completeAuthentication(req, res); অনুশীলনে এর অর্থ হল যে আমরা সেশনগুলিকে , একটি অস্থায়ী auth সেশন থেকে যেখানে ব্যবহারকারী এখনও প্রমাণীকৃত নয়, মূল সেশনের main যেখানে ব্যবহারকারীকে প্রমাণীকরণ করা হয় সেখানে স্যুইচ করি৷

ব্যবহারকারীর প্রবাহে দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ পৃষ্ঠাটি অন্তর্ভুক্ত করুন

views ফোল্ডারে, নতুন পৃষ্ঠাটি লক্ষ্য করুন second-factor.html

এটিতে একটি বোতাম রয়েছে যা বলে নিরাপত্তা কী ব্যবহার করুন , কিন্তু আপাতত, এটি কিছুই করে না।

ক্লিক করলে এই বোতামটি কল authenticateTwoFactor() করুন।

  • যদি authenticateTwoFactor() সফল হয়, ব্যবহারকারীকে তাদের অ্যাকাউন্ট পৃষ্ঠায় পুনঃনির্দেশ করুন।
  • এটি সফল না হলে, ব্যবহারকারীকে সতর্ক করুন যে একটি ত্রুটি ঘটেছে। একটি বাস্তব অ্যাপ্লিকেশনে, আপনি আরও সহায়ক ত্রুটির বার্তা প্রয়োগ করবেন—এই ডেমোতে সরলতার জন্য, আমরা শুধুমাত্র একটি উইন্ডো সতর্কতা ব্যবহার করব।
    <main>
...
    </main>
    <script type="module">
      import { authenticateTwoFactor, authStatuses } from "/auth.client.js";

      const button = document.querySelector("#authenticateButton");
      button.addEventListener("click", async e => {
        try {
          // Ask the user to authenticate with the second factor; this will trigger a browser prompt
          const response = await authenticateTwoFactor();
          const { authStatus } = response;
          if (authStatus === authStatuses.COMPLETE) {
            // The user is properly authenticated => Navigate to the Account page
            location.href = "/account";
          } else {
            throw new Error("Two-factor authentication failed");
          }
        } catch (e) {
          // Alert the user that something went wrong
          alert(`Two-factor authentication failed. ${e}`);
        }
      });
    </script>
  </body>
</html>

দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ ব্যবহার করুন

আপনি এখন একটি দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ পদক্ষেপ যোগ করার জন্য প্রস্তুত।

আপনাকে এখন যা করতে হবে তা হল index.html থেকে এই ধাপটি যোগ করা, যারা দুই-ফ্যাক্টর প্রমাণীকরণ কনফিগার করেছেন তাদের জন্য।

322a5c49d865a0d8.png

index.html এ, নীচে location.href = "/account"; , কোড যোগ করুন যা শর্তসাপেক্ষে ব্যবহারকারীকে দ্বিতীয় ফ্যাক্টর প্রমাণীকরণ পৃষ্ঠায় নেভিগেট করে যদি তারা 2FA সেট আপ করে থাকে।

এই কোডল্যাবে, একটি শংসাপত্র তৈরি করা স্বয়ংক্রিয়ভাবে ব্যবহারকারীকে দ্বি-ফ্যাক্টর প্রমাণীকরণে বেছে নেয়।

মনে রাখবেন যে server.js সার্ভার-সাইড সেশন চেক প্রয়োগ করে, যা নিশ্চিত করে যে শুধুমাত্র প্রমাণীকৃত ব্যবহারকারীরা account.html অ্যাক্সেস করতে পারে।

const { authStatus } = response;
if (authStatus === authStatuses.COMPLETE) {
  // The user is properly authenticated => navigate to account
  location.href = '/account';
} else if (authStatus === authStatuses.NEED_SECOND_FACTOR) {
  // Navigate to the two-factor-auth page because two-factor-auth is set up for this user
  location.href = '/second-factor';
}

চেষ্টা কর! 👩🏻‍💻

  • একটি নতুন ব্যবহারকারী johndoe দিয়ে লগ ইন করুন।
  • প্রস্থান.
  • johndoe হিসাবে আপনার অ্যাকাউন্টে লগ ইন করুন; দেখুন যে শুধুমাত্র একটি পাসওয়ার্ড প্রয়োজন।
  • একটি শংসাপত্র তৈরি করুন. এটি কার্যকরভাবে বোঝাবে যে আপনি johndoe হিসাবে দ্বি-ফ্যাক্টর প্রমাণীকরণ সক্রিয় করেছেন।
  • প্রস্থান.
  • আপনার ব্যবহারকারীর নাম johndoe এবং পাসওয়ার্ড প্রবেশ করান.
  • দেখুন কিভাবে আপনি স্বয়ংক্রিয়ভাবে দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ পৃষ্ঠায় নেভিগেট করছেন।
  • ( /account account-এ অ্যাকাউন্ট পৃষ্ঠাটি অ্যাক্সেস করার চেষ্টা করুন; নোট করুন যে আপনি কীভাবে সূচী পৃষ্ঠায় পুনঃনির্দেশিত হচ্ছেন কারণ আপনি সম্পূর্ণরূপে প্রমাণীকৃত নন: আপনি একটি দ্বিতীয় ফ্যাক্টর মিস করছেন)
  • দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণ পৃষ্ঠায় ফিরে যান এবং দ্বিতীয়-ফ্যাক্টর প্রমাণীকরণের জন্য নিরাপত্তা কী ব্যবহার করুন ক্লিক করুন।
  • আপনি এখন লগ ইন করেছেন এবং আপনার অ্যাকাউন্ট পৃষ্ঠা দেখতে হবে!

8. শংসাপত্রগুলি ব্যবহার করা সহজ করুন

আপনি একটি নিরাপত্তা কী দিয়ে দ্বি-ফ্যাক্টর প্রমাণীকরণের প্রাথমিক কার্যকারিতা সম্পন্ন করেছেন 🚀

কিন্তু... আপনি কি লক্ষ্য করেছেন?

এই মুহুর্তে, আমাদের শংসাপত্রের তালিকা খুব সুবিধাজনক নয়: শংসাপত্র আইডি এবং সর্বজনীন কী হল দীর্ঘ স্ট্রিং যা শংসাপত্রগুলি পরিচালনা করার সময় সহায়ক নয়! মানুষ দীর্ঘ স্ট্রিং এবং সংখ্যা সঙ্গে খুব ভাল না 🤖

সুতরাং আসুন এটিকে উন্নত করি, এবং মানব-পঠনযোগ্য স্ট্রিংগুলির সাথে নাম এবং শংসাপত্রগুলি পুনঃনামকরণে কার্যকারিতা যুক্ত করি।

RenameCredential এ একবার দেখুন

এই ফাংশনটি বাস্তবায়নে আপনার সময় বাঁচানোর জন্য যা খুব একটা যুগান্তকারী কিছু করে না, auth.client.js এ স্টার্টার কোডে আপনার জন্য একটি শংসাপত্রের নাম পরিবর্তন করার জন্য একটি ফাংশন যোগ করা হয়েছে :

async function renameCredential(credId, newName) {
  const params = new URLSearchParams({
    credId,
    name: newName
  });
  return _fetch(
    `/auth/credential?${params}`,
    "PUT"
  );
}

এটি একটি নিয়মিত ডাটাবেস আপডেট কল: ক্লায়েন্ট ব্যাকএন্ডে একটি PUT অনুরোধ পাঠায়, একটি শংসাপত্র আইডি এবং সেই শংসাপত্রের জন্য নতুন নাম সহ।

কাস্টম শংসাপত্রের নাম প্রয়োগ করুন

account.html এ, খালি ফাংশন rename লক্ষ্য করুন।

এটিতে নিম্নলিখিত কোড যোগ করুন::

// Rename a credential
async function rename(credentialId) {
  // Let the user input a new name
  const newName = window.prompt(`Name this credential:`);
  // Rename only if the user didn't cancel AND didn't enter an empty name
  if (newName && newName.trim()) {
    try {
      // Make the backend call to rename the credential (the name is sanitized) server-side
      await renameCredential(credentialId, newName);
    } catch (e) {
      // Alert the user that something went wrong
      if (Array.isArray(e)) {
        alert(
          // `msg` not `message`, this is the key's name as per the express validator API
          `Renaming failed. ${e.map((err) => `${err.msg} (${err.param})`)}`
        );
      } else {
        alert(`Renaming failed. ${e}`);
      }
    }
    // Refresh the credential list to display the new name
    await updateCredentialList();
  }
}

শংসাপত্রটি সফলভাবে তৈরি হয়ে গেলেই কেবলমাত্র একটি শংসাপত্রের নাম দেওয়া আরও বোধগম্য হতে পারে। সুতরাং আসুন কোন নাম ছাড়াই একটি শংসাপত্র তৈরি করি এবং সফলভাবে তৈরি করার পরে, শংসাপত্রটির নাম পরিবর্তন করি। যদিও এর ফলে দুটি ব্যাকএন্ড কল হবে।

register() তে rename ফাংশন ব্যবহার করুন, যাতে ব্যবহারকারীরা রেজিস্ট্রেশনের সময় শংসাপত্রের নাম দিতে সক্ষম হন:

async function register() {
  let user = {};
  try {
    const user = await registerCredential();
    // Get the latest credential's ID (newly created credential)
    const allUserCredentials = user.credentials;
    const newCredential = allUserCredentials[allUserCredentials.length - 1];
    // Rename it
    await rename(newCredential.credId);
  } catch (e) {
    // ...
  }
  // Refresh the credential list to display the new credential
  await updateCredentialList();
}

নোট করুন যে ব্যাকএন্ডে ব্যবহারকারীর ইনপুট যাচাই করা হবে এবং স্যানিটাইজ করা হবে:

  check("name")
    .trim()
    .escape()

শংসাপত্রের নাম প্রদর্শন করুন

templates.jsgetCredentialHtml এ যান।

উল্লেখ্য যে ক্রেডেনশিয়াল কার্ডের শীর্ষে শংসাপত্রের নাম প্রদর্শন করার জন্য ইতিমধ্যেই কোড রয়েছে:

// Register credential
const getCredentialHtml = (credential, removeEl, renameEl) => {
 const { name, credId, publicKey } = credential;
 return html`
    <div class="credential-card">
      <div class="credential-name">
        ${name
          ? html`
              ${name}
            `
          : html`
              <span class="unnamed">(Unnamed)</span>
            `}
      </div>
     // ...
    </div>
  `;
};

চেষ্টা কর! 👩🏻‍💻

  • একটি শংসাপত্র তৈরি করুন.
  • আপনি এটি নাম অনুরোধ করা হবে.
  • একটি নতুন নাম লিখুন এবং ঠিক আছে ক্লিক করুন.
  • শংসাপত্রের এখন নামকরণ করা হয়েছে।
  • পুনরাবৃত্তি করুন এবং চেক করুন যে নাম ক্ষেত্রটি খালি রাখার সময় জিনিসগুলিও মসৃণভাবে কাজ করে।

শংসাপত্র পুনঃনামকরণ সক্ষম করুন৷

ব্যবহারকারীদের শংসাপত্রগুলি পুনঃনামকরণ করতে হতে পারে-উদাহরণস্বরূপ, তারা একটি দ্বিতীয় কী যোগ করছে এবং তাদের আরও ভালভাবে আলাদা করতে তাদের প্রথম কীটির নাম পরিবর্তন করতে চায়৷

account.html এ, এখন পর্যন্ত খালি ফাংশন renameEl করুন এবং এতে নিম্নলিখিত কোড যোগ করুন:

// Rename a credential via HTML element
async function renameEl(el) {
  // Define the ID of the credential to update
  const credentialId = el.srcElement.dataset.credentialId;
  // Rename the credential
  await rename(credentialId);
  // Refresh the credential list to display the new name
  await updateCredentialList();
}

এখন, templates.js এর getCredentialHtml এ, class="flex-end" div-এর মধ্যে, নিম্নলিখিত কোডটি যোগ করুন, এই কোডটি ক্রেডেনশিয়াল কার্ড টেমপ্লেটে একটি Rename বাটন যোগ করে; ক্লিক করা হলে, সেই বোতামটি আমরা এইমাত্র তৈরি করা renameEl ফাংশনটিকে কল করবে:

const getCredentialHtml = (credential, removeEl, renameEl) => {
// ...
 <div class="flex-end">
  <button
    data-credential-id="${credId}"
    @click="${renameEl}"
    class="secondary right"
  >
   Rename
  </button>
 </div>
 // ...
  `;
};

চেষ্টা কর! 👩🏻‍💻

  • পুনঃনামকরণ ক্লিক করুন।
  • অনুরোধ করা হলে একটি নতুন নাম লিখুন।
  • ঠিক আছে ক্লিক করুন.
  • শংসাপত্রের সফলভাবে নামকরণ করা উচিত এবং তালিকাটি স্বয়ংক্রিয়ভাবে আপডেট হওয়া উচিত।
  • পৃষ্ঠাটি পুনরায় লোড করার পরেও নতুন নাম দেখাতে হবে (এটি দেখায় যে নতুন নামটি সার্ভার-সাইডে স্থায়ী)।

শংসাপত্র তৈরির তারিখ প্রদর্শন করুন

navigator.credential.create() এর মাধ্যমে তৈরি শংসাপত্রগুলিতে তৈরির তারিখটি উপস্থিত নেই।

কিন্তু যেহেতু এই তথ্যটি ব্যবহারকারীর জন্য শংসাপত্রের মধ্যে পার্থক্য করতে উপযোগী হতে পারে, তাই আমরা আপনার জন্য স্টার্টার কোডে সার্ভার-সাইড লাইব্রেরিটি টুইক করেছি এবং নতুন শংসাপত্র সংরক্ষণ করার সময় creationDate Date.now() সমান একটি CreationDate ক্ষেত্র যোগ করেছি।

templates.jsclass="creation-date" div এর মধ্যে, ব্যবহারকারীর কাছে তৈরির তারিখের তথ্য প্রদর্শন করতে নিম্নলিখিত যোগ করুন:

<div class="creation-date">
  <label>Created:</label>
  <div class="info">
    ${new Date(creationDate).toLocaleDateString()}
    ${new Date(creationDate).toLocaleTimeString()}
  </div>
</div>

9. আপনার কোড ভবিষ্যৎ-বান্ধব করুন

এখন পর্যন্ত আমরা ব্যবহারকারীকে শুধুমাত্র একটি সাধারণ রোমিং প্রমাণীকরণকারী নিবন্ধন করতে বলেছি যা সাইন-ইন করার সময় দ্বিতীয় ফ্যাক্টর হিসেবে ব্যবহৃত হয়।

আরও একটি উন্নত পদ্ধতি হল আরও শক্তিশালী ধরণের প্রমাণীকরণকারীর উপর নির্ভর করা: একটি ব্যবহারকারী-যাচাই রোমিং প্রমাণীকরণকারী (UVRA)। একটি UVRA একক-পদক্ষেপ সাইন-ইন প্রবাহে দুটি প্রমাণীকরণ কারণ এবং ফিশিং প্রতিরোধ প্রদান করতে পারে।

আদর্শভাবে, আপনি উভয় পন্থা সমর্থন করবেন। এটি করার জন্য, আপনাকে ব্যবহারকারীর অভিজ্ঞতা কাস্টমাইজ করতে হবে:

  • যদি একজন ব্যবহারকারীর কাছে শুধুমাত্র একটি সাধারণ (অ-ব্যবহারকারী-যাচাইকারী) রোমিং অথেনটিকেটর থাকে, তাহলে তাদেরকে ফিশিং-প্রতিরোধী অ্যাকাউন্ট বুটস্ট্র্যাপ অর্জন করতে এটি ব্যবহার করতে দিন, তবে তাদের একটি ব্যবহারকারীর নাম এবং পাসওয়ার্ডও টাইপ করতে হবে। এটি আমাদের কোডল্যাব ইতিমধ্যেই করে।
  • যদি অন্য ব্যবহারকারীর কাছে আরও উন্নত ব্যবহারকারী-যাচাই রোমিং প্রমাণীকরণকারী থাকে, তাহলে তারা অ্যাকাউন্ট বুটস্ট্র্যাপের সময় পাসওয়ার্ড ধাপ-এবং সম্ভাব্য এমনকি ব্যবহারকারীর নাম ধাপ-টি এড়িয়ে যেতে সক্ষম হবে।

ঐচ্ছিক পাসওয়ার্ডহীন সাইন-ইন সহ ফিশিং-প্রতিরোধী অ্যাকাউন্ট বুটস্ট্র্যাপিং- এ এই সম্পর্কে আরও জানুন।

এই কোডল্যাবে, আমরা আসলে ব্যবহারকারীর অভিজ্ঞতা কাস্টমাইজ করব না, তবে আমরা আপনার কোডবেস সেট আপ করব যাতে ব্যবহারকারীর অভিজ্ঞতা কাস্টমাইজ করার জন্য আপনার প্রয়োজনীয় ডেটা থাকে।

আপনার দুটি জিনিস দরকার:

  • residentKey: preferred । এটি ইতিমধ্যে আপনার জন্য করা হয়েছে.
  • একটি আবিষ্কারযোগ্য শংসাপত্র (যাকে রেসিডেন্ট কীও বলা হয়) তৈরি করা হয়েছে কিনা তা খুঁজে বের করার একটি উপায় সেট আপ করুন৷

একটি আবিষ্কারযোগ্য শংসাপত্র তৈরি করা হয়েছে কিনা তা খুঁজে বের করতে:

  • ক্রেডেনশিয়াল তৈরির সময় credProps মান জিজ্ঞাসা করুন ( credProps: true )।
  • শংসাপত্র তৈরির পরে transports মান জিজ্ঞাসা করুন। এটি আপনাকে নির্ণয় করতে সাহায্য করবে যে অন্তর্নিহিত প্ল্যাটফর্মটি UVRA কার্যকারিতা সমর্থন করে কিনা, উদাহরণস্বরূপ এটি সত্যিই একটি মোবাইল ফোন কিনা।
  • ব্যাকএন্ডে credProps এবং transports মান সংরক্ষণ করুন। এটি ইতিমধ্যেই স্টার্টার কোডে আপনার জন্য করা হয়েছে। আপনি আগ্রহী হলে auth.js এ একবার দেখুন।

আসুন credProps এবং transports মান পান এবং সেগুলিকে ব্যাকএন্ডে পাঠাই। auth.client.js এ, নিম্নরূপ registerCredential সংশোধন করুন:

  • navigator.credentials.create কল করার সময় একটি extensions ক্ষেত্র যোগ করুন
  • স্টোরেজের জন্য ব্যাকএন্ডে শংসাপত্র পাঠানোর আগে encodedCredential.transports এবং encodedCredential.credProps সেট করুন।

registerCredential নিম্নরূপ দেখতে হবে:

async function registerCredential() {
  // Fetch the credential creation options from the backend
  const credentialCreationOptionsFromServer = await _fetch(
    '/auth/credential-options',
    'POST'
  );
  // Decode the credential creation options
  const credentialCreationOptions = decodeServerOptions(
    credentialCreationOptionsFromServer
  );
  // Create a credential via the browser API; this will prompt the user
  const credential = await navigator.credentials.create({
    publicKey: {
      ...credentialCreationOptions,
      extensions: {
        credProps: true,
      },
    },
  });
  // Encode the newly created credential to send it to the backend
  const encodedCredential = encodeCredential(credential);
  // Set transports and credProps for more advanced user flows
  encodedCredential.transports = credential.response.getTransports();
  encodedCredential.credProps =
    credential.getClientExtensionResults().credProps;
  // Send the encoded credential to the backend for storage
  return await _fetch('/auth/credential', 'POST', encodedCredential);
}

10. ক্রস-ব্রাউজার সমর্থন নিশ্চিত করুন

নন-ক্রোমিয়াম ব্রাউজার সমর্থন করে

public/auth.client.js এর registerCredential ফাংশনে, আমরা সার্ভারের ইঙ্গিত হিসাবে এই তথ্যটিকে শেষ পর্যন্ত ব্যাকএন্ডে সংরক্ষণ করতে নতুন তৈরি শংসাপত্রে credential.response.getTransports() কল করছি।

যাইহোক, getTransports() বর্তমানে সমস্ত ব্রাউজারে প্রয়োগ করা হয় না ( getClientExtensionResults এর বিপরীতে যা ব্রাউজার জুড়ে সমর্থিত): getTransports() কল Firefox এবং Safari-এ একটি ত্রুটি ছুড়ে দেবে, যা এই ব্রাউজারগুলিতে শংসাপত্র তৈরিতে বাধা দেবে।

আপনার কোড সমস্ত প্রধান ব্রাউজারে চলবে তা নিশ্চিত করতে, encodedCredential.transports কলটি একটি শর্তে মোড়ানো:

if (credential.response.getTransports) {
  encodedCredential.transports = credential.response.getTransports();
}

নোট করুন যে সার্ভারে, transports transports || [] ফায়ারফক্স এবং সাফারিতে transports তালিকা undefined হবে না তবে একটি খালি তালিকা [] , যা ত্রুটি প্রতিরোধ করে।

যেসব ব্যবহারকারীরা WebAuthn সমর্থন করে না এমন ব্রাউজার ব্যবহার করে তাদের সতর্ক করুন

1e9c1be837d66ce8.png

যদিও WebAuthn সমস্ত প্রধান ব্রাউজারে সমর্থিত, তবে WebAuthn সমর্থন করে না এমন ব্রাউজারগুলিতে একটি সতর্কতা প্রদর্শন করা একটি ভাল ধারণা৷

index.html এ, এই ডিভের উপস্থিতি পর্যবেক্ষণ করুন:

<div id="warningbanner" class="invisible">
⚠️ Your browser doesn't support WebAuthn. Open this demo in Chrome, Edge, Firefox or Safari.
</div>

index.html এর ইনলাইন স্ক্রিপ্টে, WebAuthn সমর্থন করে না এমন ব্রাউজারগুলিতে ব্যানার প্রদর্শন করতে নিম্নলিখিত কোড যোগ করুন:

// Display a banner in browsers that don't support WebAuthn
if (!window.PublicKeyCredential) {
  document.querySelector('#warningbanner').classList.remove('invisible');
}

একটি বাস্তব ওয়েব অ্যাপ্লিকেশনে, আপনি আরও বিস্তৃত কিছু করতে চান এবং এই ব্রাউজারগুলির জন্য একটি সঠিক ফলব্যাক প্রক্রিয়া থাকবে—কিন্তু এটি আপনাকে দেখায় কিভাবে WebAuthn সমর্থন পরীক্ষা করতে হয়।

11. ভাল হয়েছে!

✨আপনার কাজ শেষ!

আপনি একটি নিরাপত্তা কী দিয়ে দ্বি-ফ্যাক্টর প্রমাণীকরণ প্রয়োগ করেছেন।

এই কোডল্যাবে, আমরা মৌলিক বিষয়গুলো কভার করেছি। আপনি যদি 2FA এর জন্য WebAuthn আরও অন্বেষণ করতে চান, তাহলে আপনি পরবর্তীতে কী চেষ্টা করতে পারেন তার কিছু ধারণা এখানে রয়েছে:

  • ক্রেডেনশিয়াল কার্ডে "শেষ ব্যবহৃত" তথ্য যোগ করুন। একটি প্রদত্ত নিরাপত্তা কী সক্রিয়ভাবে ব্যবহার করা হয়েছে কিনা তা নির্ধারণ করতে ব্যবহারকারীদের জন্য এটি দরকারী তথ্য—বিশেষ করে যদি তারা একাধিক কী নিবন্ধন করে থাকে।
  • আরো শক্তিশালী ত্রুটি পরিচালনা এবং আরো সুনির্দিষ্ট ত্রুটি বার্তা প্রয়োগ করুন।
  • auth.js দেখুন, এবং অন্বেষণ করুন যখন আপনি কিছু authSettings পরিবর্তন করেন, বিশেষ করে যখন ব্যবহারকারীর যাচাইকরণ সমর্থন করে এমন একটি কী ব্যবহার করেন।