অথেন্টিকেশন ও অথরাইজেশন
এই পাঠে যা শিখবেন
- AuthN বনাম AuthZ-এর স্পষ্ট পার্থক্য
- সেশন-বেসড বনাম টোকেন-বেসড (JWT) অথেন্টিকেশনের ট্রেড-অফ
- OAuth 2.0 কীভাবে কাজ করে এবং RBAC কেন পারমিশন ম্যানেজমেন্ট সহজ করে
- Python-এ stdlib
hmac/hashlibদিয়ে বাস্তব HMAC-সিগনড টোকেন তৈরি, যাচাই ও একটি টেম্পার-করা টোকেন প্রত্যাখ্যান করা
১ · AuthN বনাম AuthZ
দুটো শব্দ শুনতে কাছাকাছি হলেও সম্পূর্ণ ভিন্ন প্রশ্নের উত্তর দেয় — Authentication (AuthN)Authenticationইউজার আসলে যে দাবি করছে সেই ব্যক্তি কিনা তা যাচাই করা — সাধারণত লগইন প্রক্রিয়া (পাসওয়ার্ড, OTP, বায়োমেট্রিক ইত্যাদি)। বলে "আপনি কে?" — লগইন করে প্রমাণ করা আপনি যে ব্যবহারকারী বলে দাবি করছেন, সেই ব্যবহারকারীই। Authorization (AuthZ)Authorizationএকজন যাচাইকৃত ইউজার কোন কোন রিসোর্স/অ্যাকশনে অ্যাক্সেস পাবে তা নির্ধারণ করা — পারমিশন ব্যবস্থাপনা। বলে "আপনি কী করতে পারবেন?" — যাচাইকৃত হওয়ার পরও, একজন সাধারণ ইউজার হয়তো অন্য ইউজারের ডেটা ডিলিট করার অনুমতি পাবে না, কিন্তু একজন অ্যাডমিন পাবে।
একটি সিস্টেমে AuthN সঠিক হলেও AuthZ ভুল হতে পারে — যেমন সঠিকভাবে লগইন করা একজন ইউজার ভুলবশত এমন একটি API এন্ডপয়েন্টে অ্যাক্সেস পেয়ে যায় যা শুধু অ্যাডমিনদের জন্য হওয়া উচিত ছিল। প্রতিটি সেনসিটিভ অপারেশনে দুটো চেক আলাদাভাবে করা দরকার — "এই টোকেন/সেশন বৈধ কি না" (AuthN) এবং "এই ইউজারের এই নির্দিষ্ট অ্যাকশনের অনুমতি আছে কি না" (AuthZ)।
২ · সেশন-বেসড বনাম টোকেন-বেসড (JWT) অথেন্টিকেশন
লগইনের পর সার্ভার কীভাবে "মনে রাখে" ইউজার লগইন করা আছে, তার দুটো প্রধান পদ্ধতি —
সার্ভার একটি সেশন তৈরি করে শেয়ার্ড স্টোরে (Redis, L12) রাখে, ক্লায়েন্টকে শুধু একটি সেশন-আইডি কুকি দেয়। প্রতিটি রিকোয়েস্টে সার্ভার সেই আইডি দিয়ে স্টোর লুকআপ করে। সহজে রিভোক করা যায়, কিন্তু প্রতি রিকোয়েস্টে একটি এক্সট্রা লুকআপ লাগে।
সার্ভার একটি JWTJSON Web Tokenইউজার আইডি, রোল ও মেয়াদ-উত্তীর্ণের সময় সহ একটি সাইনড টোকেন — সার্ভার শুধু সিগনেচার যাচাই করে, DB লুকআপ ছাড়াই। ইস্যু করে (ইউজার আইডি, রোল, expiry-সহ, স্বাক্ষরিত)। প্রতি রিকোয়েস্টে সার্ভার শুধু সিগনেচার যাচাই করে — কোনো DB/স্টোর লুকআপ লাগে না, স্টেটলেস বলে সহজে হরাইজন্টালি স্কেল করে (L12), কিন্তু ইস্যু হওয়ার পর মেয়াদ শেষের আগে রিভোক করা কঠিন।
৩ · OAuth 2.0 — ডেলিগেশন প্রোটোকল
OAuth 2.0OAuth 2.0একটি ডেলিগেশন প্রোটোকল যা ইউজারকে পাসওয়ার্ড শেয়ার না করেই একটি থার্ড-পার্টি অ্যাপকে সীমিত অ্যাক্সেস দেওয়ার সুযোগ দেয়। হলো "Sign in with Google/Facebook"-এর পেছনের প্রোটোকল — ইউজার তার Google পাসওয়ার্ড থার্ড-পার্টি অ্যাপকে না দিয়েই সেই অ্যাপকে সীমিত অ্যাক্সেস (যেমন শুধু ইমেইল ও নাম পড়ার) দিতে পারে। এর চারটি মূল ভূমিকা — Resource Owner (ইউজার নিজে), Client (থার্ড-পার্টি অ্যাপ), Authorization Server (যেমন Google-এর অথ সার্ভার, যেখানে ইউজার লগইন করে অনুমতি দেয়), এবং Resource Server (যে আসল ডেটা/API ধারণ করে, যেমন Google-এর প্রোফাইল API)।
৪ · RBAC — রোল-বেসড অ্যাক্সেস কন্ট্রোল
RBACRole-Based Access Controlপারমিশন সরাসরি ইউজারকে নয়, রোলকে অ্যাসাইন করা হয়; প্রতিটি ইউজারকে এক বা একাধিক রোল দেওয়া হয়।
স্কিমে পারমিশন সরাসরি প্রতিটি ইউজারকে না দিয়ে "রোল"-কে (যেমন admin, editor,
viewer) দেওয়া হয়, এবং প্রতিটি ইউজারকে এক বা একাধিক রোল অ্যাসাইন করা হয়। হাজার হাজার ইউজারের
জন্য আলাদা আলাদা পারমিশন ম্যানেজ করার চেয়ে কয়েকটি রোল ম্যানেজ করা অনেক সহজ ও কম ভুল-প্রবণ।
নিচের কোড সেলে বাস্তব ক্রিপ্টোগ্রাফি — stdlib hmac ও hashlib.sha256 ব্যবহার করে একটি
সিম্পল সাইনড টোকেন তৈরি ও যাচাই করা হলো (JWT-এর ঠিক ফরম্যাট নয়, কিন্তু একই সিগনিং নীতি)। একটি বৈধ টোকেন
সফলভাবে যাচাই হবে, এবং সাইন করার পর payload বদলে দিলে (টেম্পারিং) যাচাই ব্যর্থ হবে।
import hmac
import hashlib
def create_token(payload, secret):
signature = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return f"{payload}.{signature}"
def verify_token(token, secret):
payload, _, signature = token.rpartition(".")
expected = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
secret = "super-secret-key-2026"
payload = "user_id=42;role=admin;exp=1999999999"
token = create_token(payload, secret)
print("তৈরি হওয়া টোকেন:")
print(" ", token)
print("\nবৈধ টোকেন verify:", verify_token(token, secret))
# --- টেম্পারিং: সাইন করার পর payload বদলে ফেলা হলো ---
tampered_payload = "user_id=42;role=SUPERADMIN;exp=1999999999"
original_signature = token.rpartition(".")[2]
tampered_token = f"{tampered_payload}.{original_signature}"
print("টেম্পার করা টোকেন verify:", verify_token(tampered_token, secret))
secret
নেই বলে সে নতুন বৈধ সিগনেচার বানাতে পারবে না), কিন্তু payload বদলে ফেলায় সার্ভারের পুনঃগণনা করা
expected সিগনেচার পুরনো সিগনেচারের সাথে আর মেলে না — তাই verify_token
False রিটার্ন করে। এটাই প্রমাণ করে কেন role="SUPERADMIN" বসিয়ে দিলেও আক্রমণকারী উপকৃত হয় না।
AuthN ও AuthZ দুটো ভিন্ন স্তর — একটি "কে" নিশ্চিত করে, অন্যটি "কী করতে পারবে" নিয়ন্ত্রণ করে। টোকেন-বেসড অথেন্টিকেশনের নিরাপত্তা পুরোপুরি নির্ভর করে সিগনেচারের উপর — সিক্রেট কী গোপন থাকলে payload-এ যা-ই লেখা থাকুক, সেটি টেম্পারিং-প্রুফ। এই নীতিই বাস্তব JWT ও অন্যান্য সাইনড-টোকেন সিস্টেমের ভিত্তি।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ JWT-ভিত্তিক অথেন্টিকেশনে একজন ইউজারকে সাথে সাথে লগ-আউট করানো (টোকেন রিভোক করা) কেন কঠিন?
JWT-এর মূল সুবিধাই হলো সার্ভার প্রতিটি টোকেনের অস্তিত্ব সেন্ট্রালি ট্র্যাক করে না — এটি শুধু সিগনেচার
যাচাই করে, কোনো ডেটাবেস/স্টোর লুকআপ ছাড়াই। তাই একটি নির্দিষ্ট টোকেন "বাতিল" করার কোনো সরাসরি উপায় নেই যতক্ষণ
না সেটির নিজের exp মেয়াদ শেষ হয়। প্রকৃত সিস্টেমগুলো এটি সমাধান করে ছোট মেয়াদের টোকেন +
রিফ্রেশ-টোকেন দিয়ে, অথবা একটি ছোট "ব্ল্যাকলিস্ট" শেয়ার্ড স্টোর রেখে (যা আংশিকভাবে স্টেটলেসনেসের সুবিধা
কমিয়ে দেয়) — এটি JWT-এর একটি সুপরিচিত ট্রেড-অফ।
প্র ০২ সেশন-বেসড অথ কেন হরাইজন্টাল স্কেলিংয়ে (L12) টোকেন-বেসডের চেয়ে বাড়তি জটিলতা যোগ করে?
সেশন-বেসড অথে প্রতিটি রিকোয়েস্টে একটি শেয়ার্ড সেশন-স্টোরে (Redis-এর মতো) লুকআপ করতে হয় — অর্থাৎ প্রতিটি অ্যাপ সার্ভার instance-কে সেই শেয়ার্ড স্টোরের সাথে যুক্ত থাকতে হবে (L12-এর "stateless সার্ভার, শেয়ার্ড স্টোর স্টেট রাখে" প্যাটার্ন)। এটি একটি অতিরিক্ত নেটওয়ার্ক হপ ও একটি নতুন ক্রিটিক্যাল ডিপেন্ডেন্সি যোগ করে। টোকেন-বেসড অথে যাচাই সম্পূর্ণ লোকালি (শুধু CPU দিয়ে সিগনেচার চেক) হয় বলে কোনো শেয়ার্ড স্টোর ছাড়াই যেকোনো সংখ্যক স্টেটলেস সার্ভার instance যাচাই করতে পারে — স্কেল করা সহজ।
প্র ০৩ RBAC-এর বদলে যদি প্রতিটি ইউজারের জন্য আলাদা আলাদা পারমিশন সেট রাখা হতো, তাহলে ১০ লক্ষ ইউজারের একটি সিস্টেমে কী সমস্যা হতো?
প্রতিটি পারমিশন পরিবর্তন (যেমন "সব এডিটরকে একটি নতুন ফিচার অ্যাক্সেস দাও") তখন ১০ লক্ষ পৃথক ইউজার রেকর্ড আপডেট করা দাবি করত — ধীর, ভুল-প্রবণ, এবং অডিট করা কঠিন (কে কী অ্যাক্সেস পেল তা ট্র্যাক করা জটিল হয়ে যায়)। RBAC-এ একই পরিবর্তন একটি রোল সংজ্ঞায় একবার করলেই সেই রোলের সব ইউজার স্বয়ংক্রিয়ভাবে আপডেট পায় — পরিবর্তন, অডিট, ও রিজনিং সবই অনেক সহজ হয়ে যায়।
অনুশীলন
-
চিন্তা করুন: একটি ব্লগিং প্ল্যাটফর্মের জন্য কমপক্ষে ৩টি RBAC রোল ও প্রতিটির ২-৩টি পারমিশন ডিজাইন করুন।
উদাহরণ — Viewer: পোস্ট পড়তে পারবে। Author: পোস্ট পড়তে, নিজের পোস্ট তৈরি/এডিট করতে পারবে (কিন্তু অন্যের পোস্ট নয়)। Admin: যেকোনো পোস্ট পড়তে/এডিট/ডিলিট করতে পারবে, এবং ইউজারদের রোল বদলাতে পারবে। প্রতিটি ইউজারকে একটি রোল দেওয়া হবে, এবং পারমিশন-চেক (AuthZ) সরাসরি "এই রোলের এই পারমিশন আছে কি না" প্রশ্ন করবে, নির্দিষ্ট ইউজার আইডি দিয়ে নয়।
-
কোড পরিবর্তন করুন: উপরের কোড সেলে
verify_tokenকল করার সময় ভুলsecret(যেমন"wrong-secret") দিয়ে মূল (টেম্পার-না-করা)tokenযাচাই করুন — ফলাফল কী হবে এবং কেন?verify_token(token, "wrong-secret")Falseরিটার্ন করবে। কারণexpectedসিগনেচার এখন ভুল সিক্রেট দিয়ে গণনা করা হয়েছে — যা মূল সিগনেচার তৈরির সময় ব্যবহৃত আসল সিক্রেট দিয়ে গণনা করা সিগনেচারের থেকে ভিন্ন হবে, যদিও payload নিজে অপরিবর্তিত। এটি দেখায় সিক্রেট কী-ই হলো একমাত্র জিনিস যা কাউকে বৈধ টোকেন তৈরি বা যাচাই করার ক্ষমতা দেয় — সিক্রেট ফাঁস হওয়া মানেই পুরো অথেন্টিকেশন সিস্টেম আপস (compromised) হয়ে যাওয়া।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫১টি পাঠ পরবর্তী পাঠ — এনক্রিপশন ও ডেটা সুরক্ষা।
- L38 · আইডেম্পোটেন্সি ও এক্সাক্টলি-ওয়ান্স ডেলিভারি পূর্ববর্তী M9-এর শেষ পাঠে ফেরত যান।
- L12 · Stateless বনাম Stateful সার্ভিস ডিজাইন পূর্বশর্ত টোকেন-বেসড অথ কেন স্টেটলেস স্কেলিং-এর সাথে ভালো মেলে তা আরও গভীরে দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics ও System Design — সব এক জায়গায়।