আপলোড করা নোট দুটোতে Session-based এবং Token-based (JWT) অথেন্টিকেশনের বেসিক মেকানিজম ভালোভাবেই কভার করা হয়েছে। সংক্ষেপে — Session-based পদ্ধতি stateful (সার্ভার মনে রাখে), আর Token-based পদ্ধতি stateless (টোকেনই তথ্য বহন করে, সার্ভার শুধু signature ভেরিফাই করে)।
কিন্তু বাস্তব জগতে সমস্যাটা এত সহজ নয়। JWT "stateless" — এই একটা শব্দ অনেক ডেভেলপারকে ভুল পথে নিয়ে যায়: তারা ভাবে stateless মানেই "revocation/refresh/rotation লাগবে না, কারণ সার্ভারকে কিছু মনে রাখতে হয় না।" এই রিপোর্টের মূল প্রশ্নটাই এখানে — আপনি যে Method-01 বর্ণনা করেছেন (শুধুমাত্র একটা ২৪ ঘণ্টার JWT, কোনো refresh/revocation/rotation ছাড়া) সেটা আসলে stateless সিস্টেমের একটা "naive" (সরলীকৃত) ভার্সন, এবং এই সরলীকরণের একটা নির্দিষ্ট নিরাপত্তা-মূল্য (security cost) আছে।
আমরা প্রথমে Method-01-কে বিচ্ছিন্নভাবে (isolation-এ) বিশ্লেষণ করব — কোন অ্যাটাকগুলো সম্ভব, কোন সিস্টেমে এটা চলে। তারপর সেটাকে সরাসরি আপনার দেওয়া Pharmaciano ERP রিয়েল-ওয়ার্ল্ড রেসপন্সের ওপর প্রয়োগ করে ফরেনসিক বিশ্লেষণ করব — কারণ একটা সিঙ্গেল-টেনেন্ট ব্লগের জন্য যা "যথেষ্ট নিরাপদ", মাল্টি-organization, মাল্টি-branch, PBAC, Accounting ও AI-forecasting সহ একটা ERP-এর জন্য তা সম্পূর্ণ ভিন্ন রিস্ক ক্যাটাগরিতে পড়ে।
JWT-কে একটা সাইন করা চেকের সাথে তুলনা করা যায়। একবার চেক সাইন হয়ে গেলে সেটা নিজেই একটা "valid promise" বহন করে — প্রতিবার চেক ভাঙানোর সময় ব্যাংককে ফোন করে জিজ্ঞেস করতে হয় না "এই চেক কি এখনো valid?" — এটাই stateless-এর সুবিধা। কিন্তু সমস্যা হলো — চেকটা চুরি হয়ে গেলে, বা স্বাক্ষরকারীর সিল চুরি হয়ে গেলে, বা একজন কর্মচারীকে বরখাস্ত করা হলে, ব্যাংক কি সেই নির্দিষ্ট চেকটা আলাদাভাবে আটকাতে পারবে — চেক মেয়াদ শেষ হওয়ার আগেই? Stateless টোকেনে উত্তরটা হলো: পারবে না, যদি না আলাদা একটা ব্ল্যাকলিস্ট/স্টেট তৈরি করা হয় — আর সেটা করলেই আবার আংশিক statefulness ফিরে আসে। এই টেনশনটাই (stateless-এর performance benefit বনাম instant-revocation-এর security benefit) পুরো রিপোর্টের কেন্দ্রবিন্দু।
আপনার বর্ণিত Method-01-টা পুনরায় স্পষ্ট করি:
user_id, user_name,
user_email, user_role
এই ডিজাইনের পেছনে যুক্তি বোধগম্য: "JWT তো signed, কেউ এডিট করতে পারবে না; CORS দিয়ে অন্য origin আটকানো হয়েছে; তাহলে আর কী সমস্যা?" — সমস্যাটা হলো, JWT-র signature শুধু integrity (টোকেনটা edit হয়নি) প্রমাণ করে, confidentiality বা lifecycle-control প্রমাণ করে না। একবার একটা valid টোকেন কোনোভাবে (XSS, MITM, ডিভাইস চুরি, shoulder-surfing, malicious browser extension, log leakage) অন্য কারো হাতে চলে গেলে — সেই টোকেন বাকি ২৪ ঘণ্টা সম্পূর্ণ legitimate ইউজার হিসেবেই কাজ করবে, কারণ সার্ভারের কাছে "এই টোকেনটা এখন আর valid না" বলার কোনো ব্যবস্থা নেই।
এই ডিজাইনে যখন ইউজার Logout ক্লিক করে, ফ্রন্টএন্ড কোড সম্ভবত শুধু cookie/localStorage থেকে টোকেন
delete করে দেয়। কিন্তু টোকেনটা নিজে এখনো সম্পূর্ণ valid — অর্থাৎ যদি কেউ logout হওয়ার আগেই টোকেনটা
copy করে রাখে (browser dev tools, network tab, malicious extension, proxy log), সে ইউজার logout করার পরেও সেই কপি
করা টোকেন দিয়ে API hit করে যেতে পারবে যতক্ষণ না ২৪ ঘণ্টা শেষ হয়। এটা একটা মৌলিক functional ও security gap
— "Logout" শব্দটার সাধারণ ব্যবহারকারীর প্রত্যাশার সাথে সিস্টেমের আসল আচরণ মেলে না।
একটা সংখ্যা দিয়ে বোঝা যাক — কেন "একটাই দীর্ঘ-মেয়াদী টোকেন" risk-multiplier হিসেবে কাজ করে:
| স্ক্রিনারিও | Access Token TTL = 15 মিনিট (refresh সহ) | একক JWT TTL = 24 ঘণ্টা (Method-01) |
|---|---|---|
| টোকেন leak হলে গড় exposure window | ≤ 15 মিনিট (worst case) | ≤ 24 ঘণ্টা (worst case — ৯৬ গুণ বেশি) |
| Admin "এই ইউজারকে এখনই ব্লক করো" করলে কার্যকর হতে সময় | তাৎক্ষণিক (refresh token revoke করলেই next refresh-এ আটকে যায়, এবং access token নিজেই কয়েক মিনিটে এক্সপায়ার করে) | কার্যকর না হতে পারে — পুরোনো access token ২৪ ঘণ্টা valid থেকেই যাবে, যদি না আলাদা blacklist থাকে |
| কর্মচারী ছাঁটাই হলে অফবোর্ডিং রিস্ক | কম — refresh token সাথে সাথে revoke করা যায় | উচ্চ — ছাঁটাই হওয়া স্টাফ ২৪ ঘণ্টা পর্যন্ত সিস্টেমে অ্যাক্সেস রাখতে পারে |
"Stateless" ডিজাইন performance দেয়, কিন্তু control ছেড়ে দেয়। ২৪-ঘণ্টা একক টোকেনে আপনি কার্যত বলছেন — "যদি এই টোকেন কখনো leak হয়, আমরা পরের ২৪ ঘণ্টা সেটা নিয়ে কিছু করতে পারব না।" একটা সাধারণ ব্লগ অ্যাপের জন্য এটা মেনে নেওয়া যায়; financial/inventory ডেটা সহ ERP-র জন্য এটা সম্ভবত মেনে নেওয়া যায় না (Section 08-এ বিস্তারিত)।
নিচে Method-01-এর বিরুদ্ধে বাস্তব-জগতের অ্যাটাক ক্যাটাগরিগুলো সাজানো হয়েছে গুরুত্ব অনুযায়ী। প্রতিটার সাথে "কীভাবে কাজ করে" এবং "কখন এটা ফেইল করায়" ব্যাখ্যা করা হয়েছে।
যদি টোকেন localStorage বা sessionStorage-এ রাখা হয় (এবং HttpOnly cookie-তে না রাখা
হয়), তাহলে পেজের যেকোনো জায়গায় ইনজেক্ট হওয়া JavaScript সরাসরি localStorage.getItem('token') কল
করে টোকেন পড়ে ফেলতে পারে এবং নিজের সার্ভারে পাঠিয়ে দিতে পারে।
কখন ঘটে: কোনো ইউজার-জেনারেটেড কনটেন্ট ফিল্ড (যেমন প্রোডাক্ট রিভিউ, নোট
ফিল্ড, ইনভয়েস মেমো) যদি sanitize না করে সরাসরি DOM-এ render করা হয় (innerHTML), একটা malicious
<script> ট্যাগ বা event handler ইনজেক্ট করে আক্রমণকারী যেকোনো ভিজিটরের টোকেন চুরি করতে পারে।
ERP-তে এটা ভয়াবহ — কারণ super-admin যদি একটা malicious purchase-note খোলে, তার পূর্ণ-অ্যাক্সেস টোকেন চুরি হয়ে
যেতে পারে।
একবার একটা ভ্যালিড টোকেন নেটওয়ার্ক লগ, ব্রাউজার হিস্ট্রি, ব্রাউজার ডেভটুলস স্ক্রিনশট,
ভুলবশত পাবলিক গিটহাব রিপোতে কমিট, কিংবা CI/CD পাইপলাইন লগে (এটাই Pharmaciano কেসে ঘটেছে — Section 08 দেখুন)
এক্সপোজ হলে, যেকেউ সেটা যত খুশি বার Authorization: Bearer <token> হেডারে বসিয়ে রিপ্লে করতে
পারবে — যতক্ষণ exp পার না হয়। কোনো nonce, কোনো single-use মেকানিজম নেই বলে সার্ভার রিপ্লে আর
লেজিটিমেট রিকোয়েস্টের মধ্যে পার্থক্য করতে পারে না।
পাবলিক Wi-Fi, প্রক্সি, কম্প্রোমাইজড রাউটার, বা TLS downgrade (যদি HSTS ঠিকমতো এনফোর্স না হয়) — এসবের মাধ্যমে টোকেন ট্রানজিটে চুরি হতে পারে। যদি Pharmaciano-এর মতো সিস্টেম HSTS হেডার সঠিকভাবে সেট করে (যা আমরা Section 08-এ দেখব এটা করেছে), MITM-এর সুযোগ অনেক কমে যায় — কিন্তু পুরোপুরি বন্ধ হয় না (যেমন প্রথম ভিজিটে HSTS এখনো ব্রাউজারে cache না থাকলে)।
টোকেন যদি কুকিতে রাখা হয় এবং SameSite অ্যাট্রিবিউট ঠিকমতো সেট না থাকে
(অর্থাৎ default বা None), তাহলে একটা malicious ওয়েবসাইট ভিজিটরের ব্রাউজার ব্যবহার করে তার নামে
আনঅথরাইজড রিকোয়েস্ট পাঠাতে পারে (যেমন "একটা নতুন purchase order তৈরি করো")। ব্রাউজার স্বয়ংক্রিয়ভাবে কুকি
অ্যাটাচ করে পাঠিয়ে দেয়, ইউজার কিছু বোঝার আগেই।
অনেকে ভাবে "JWT base64-encoded, তাই কেউ user_role: "admin" বসিয়ে দিতে
পারবে।" এটা ভুল ধারণা — যদি সার্ভার ঠিকভাবে signature verify করে (HS256/RS256), payload পরিবর্তন করলে signature
mismatch হবে এবং রিকোয়েস্ট রিজেক্ট হবে। আসল ঝুঁকি tampering-এ না, বরং "alg: none" attack বা weak-secret
brute-force-এ। যদি কোনো লাইব্রেরি ভুলভাবে কনফিগার করা থাকে এবং alg হেডার ক্লায়েন্ট থেকে
নির্ধারিত হতে দেয় (legacy bug), আক্রমণকারী alg: none পাঠিয়ে signature ভেরিফিকেশন সম্পূর্ণ বাইপাস
করতে পারে। আধুনিক JWT লাইব্রেরিতে এটা সাধারণত প্যাচ করা থাকে, কিন্তু পুরোনো/কাস্টম ইমপ্লিমেন্টেশনে এখনো দেখা যায়।
HS256 (symmetric) ব্যবহার করলে সেই একই সিক্রেট কী টোকেন সাইন আর ভেরিফাই দুটোই করে। যদি
এই সিক্রেট দুর্বল হয় (ছোট, predictable, .env ফাইল git-এ পুশ হয়ে যায়, বা environment variable leak হয় কোনো
error-log/stack-trace এর মাধ্যমে), আক্রমণকারী নিজেই ইচ্ছামতো claims (যেমন user_role: "super_admin")
দিয়ে সম্পূর্ণ নতুন, সম্পূর্ণ-ভ্যালিড টোকেন বানিয়ে ফেলতে পারে — কোনো লগইন ছাড়াই। এটা পুরো সিস্টেম টেকওভারের
সমান।
একজন কর্মচারী (বা branch manager) চাকরি ছাড়ার/বরখাস্ত হওয়ার পরেও, তার আগের ইস্যু করা টোকেন এক্সপায়ার না হওয়া পর্যন্ত (২৪ ঘণ্টা) পূর্ণ-অ্যাক্সেস বজায় রাখে। ERP-তে এটার অর্থ — ছাঁটাই হওয়া একাউন্টিং স্টাফ এখনো invoice তৈরি করতে, ইনভেন্টরি অ্যাডজাস্ট করতে, বা ডেটা এক্সপোর্ট করতে পারবে যতক্ষণ না টোকেন আপনাআপনি এক্সপায়ার করে।
ফার্মেসি/রিটেইল POS টার্মিনাল প্রায়ই শেয়ার্ড ডিভাইস হয় — একই ব্রাউজার সেশনে একাধিক স্টাফ পালা করে লগইন করে। যদি একজন স্টাফ ব্রাউজার ট্যাব বন্ধ না করেই চলে যায় এবং "Logout" না করে (অথবা Logout করলেও, যেমন ৩.১-এ ব্যাখ্যা করা হয়েছে, পুরোনো টোকেন এখনো valid), পরের শিফটের স্টাফ আগের ইউজারের একসেস ব্যবহার করে কাজ চালিয়ে যেতে পারে — audit log-এ ভুল ইউজার রেকর্ড হবে, যা accounting/compliance-এর জন্য সমস্যাজনক।
Method-01 নিজে "খারাপ" কোড নয় — এটা একটা ট্রেড-অফ সিদ্ধান্ত, এবং সব ট্রেড-অফের মতোই এটা প্রসঙ্গ-নির্ভর (context-dependent)। নিচে কোন ধরনের সিস্টেমে এটা যুক্তিসঙ্গত এবং কোথায় বিপজ্জনক, তার একটা বাস্তব ম্যাপ দেওয়া হলো।
| সিস্টেম টাইপ | কেন এটা চলে |
|---|---|
| পাবলিক কনটেন্ট/ব্লগ প্ল্যাটফর্ম (read-heavy, কম sensitive write) | Token leak হলে worst-case ক্ষতি সীমিত — কেউ একটা কমেন্ট পোস্ট করতে পারবে, কিন্তু financial loss নেই |
| ইন্টারনাল টুল/ড্যাশবোর্ড (VPN-এর পেছনে, সীমিত ইউজার) | Network-level আরেকটা নিরাপত্তা স্তর (VPN/IP allowlist) থাকে বলে token leak-এর সুযোগ কম |
| MVP / Hackathon / Proof-of-Concept | Speed-to-market অগ্রাধিকার; প্রোডাকশনে যাওয়ার আগে এটা আপগ্রেড করার প্ল্যান থাকে |
| Demo/Sandbox এনভায়রনমেন্ট (real data নেই) | কোনো sensitive ডেটা এক্সপোজড না হওয়ায় ঝুঁকি নগণ্য |
| Server-to-server, short-lived machine token (কয়েক মিনিটের জন্য ইস্যু করা, human session না) | এক্ষেত্রে TTL এমনিতেই অনেক কম রাখা হয়, তাই "একটাই টোকেন"-এর রিস্ক কম |
| সিস্টেম টাইপ | কেন এটা বিপজ্জনক |
|---|---|
| ব্যাংকিং / পেমেন্ট গেটওয়ে / ফিনটেক | রেগুলেটরি কম্প্লায়েন্স (PCI-DSS, PSD2) সাধারণত নির্দিষ্ট সেশন টাইমআউট এবং তাৎক্ষণিক রিভোকেশন বাধ্যতামূলক করে |
| ERP / Accounting / Inventory System (এই কেসের মতো) | একটা leaked টোকেন দিয়ে ইনভেন্টরি অ্যাডজাস্ট, ভুয়া purchase order, বা debit-credit এন্ট্রি ম্যানিপুলেট করা সম্ভব — যার আর্থিক প্রভাব সরাসরি |
| হেলথকেয়ার / Patient Data System | HIPAA-সদৃশ রেগুলেশনে দ্রুত access revocation একটা মৌলিক প্রয়োজনীয়তা |
| Multi-tenant SaaS (একাধিক organization একই ইনফ্রায়) | একটা tenant-এর টোকেন leak হলে অন্য tenant-এর ডেটা পর্যন্ত প্রভাবিত হতে পারে যদি claim/scope যাচাই দুর্বল হয় |
| Admin Panel / Super-Admin Console | সর্বোচ্চ-প্রিভিলেজ অ্যাকাউন্ট compromise হলে পুরো সিস্টেম টেকওভার সম্ভব — এই অ্যাকাউন্টের জন্যই সবচেয়ে কড়া revocation দরকার |
সিনারিও A — পাবলিক ব্লগ: একজন আক্রমণকারী XSS দিয়ে একজন রিডারের টোকেন চুরি করল। ফলাফল: আক্রমণকারী সেই ইউজারের নামে একটা কমেন্ট পোস্ট করতে পারল। ক্ষতি: বিরক্তিকর, কিন্তু লো-স্টেক।
সিনারিও B — Pharmaciano-এর মতো ERP: একজন আক্রমণকারী একই কৌশলে একজন Branch Manager-এর টোকেন চুরি করল। ফলাফল: আক্রমণকারী ২৪ ঘণ্টা ধরে ইনভেন্টরি অ্যাডজাস্টমেন্ট করতে পারে, ভুয়া sales entry দিতে পারে, supplier payment তথ্য দেখতে পারে, এমনকি (role অনুযায়ী) ডেটা এক্সপোর্ট করতে পারে — এবং অ্যাডমিন এটা টের পেলেও তাৎক্ষণিকভাবে অ্যাক্সেস বন্ধ করতে পারবে না, কারণ কোনো revocation মেকানিজম নেই।
আপনার প্রশ্ন ছিল: user_id, user_name, user_email, user_role —
এই চারটা claim JWT payload-এ রাখা কি নিরাপদ? উত্তরটা একমাত্রিক নয় — এটা নির্ভর করে "নিরাপদ" বলতে কী বোঝানো
হচ্ছে তার ওপর। তিনটা আলাদা কোণ থেকে দেখা যাক।
JWT-র payload base64url-এনকোডেড, এনক্রিপ্টেড না। যেকেউ টোকেনটা দেখলেই
(ব্রাউজার ডেভটুলস, নেটওয়ার্ক প্রক্সি, jwt.io-এর মতো ওয়েবসাইটে পেস্ট করে) পুরো payload প্লেইন-টেক্সট-এ পড়ে ফেলতে
পারে — কোনো secret key দরকার নেই decode করতে, শুধু verify করতে দরকার। অর্থাৎ user_email এবং
user_name টোকেনের ভেতরে থাকলে তা de facto পাবলিক — যেকোনো ব্রাউজার এক্সটেনশন, প্রক্সি লগ, বা এমনকি
ব্রাউজার হিস্ট্রি এক্সেস পাওয়া কেউ এটা পড়তে পারবে।
| Claim | Confidentiality Risk | মন্তব্য |
|---|---|---|
user_id |
কম | একটা opaque আইডি (যেমন MongoDB ObjectId); একা এটা দিয়ে সরাসরি কোনো PII এক্সপোজ হয় না, যদি আইডিটা sequential/predictable না হয় |
user_name |
মধ্যম | PII (ব্যক্তিগত তথ্য) — কিন্তু সাধারণত UI-তেই দেখানো হয়, তাই এক্সপোজার তেমন নতুন কিছু যোগ করে না |
user_email |
উচ্চ | সরাসরি PII; phishing/spam target হওয়ার সুযোগ তৈরি করে এবং অনেক রেগুলেশনে (GDPR-সদৃশ) email-কে protected personal data ধরা হয় |
user_role |
মধ্যম-উচ্চ | সরাসরি sensitive না, কিন্তু আক্রমণকারীকে "টার্গেট রিকনেসান্স" সুবিধা দেয় — কে super_admin, কে শুধু cashier, সেটা জেনে আক্রমণকারী সবচেয়ে মূল্যবান টোকেনটা খুঁজে নিতে পারে |
চারটা claim-ই — যদি সার্ভার প্রতিটা রিকোয়েস্টে signature ভেরিফাই করে — ট্যাম্পার-প্রুফ। আক্রমণকারী payload এডিট
করে user_role: "admin" বসিয়ে দিলে signature mismatch হবে এবং রিকোয়েস্ট রিজেক্ট হবে (Section 3.5-এ
বিস্তারিত)। সুতরাং, "কেউ role পরিবর্তন করে দিতে পারবে কিনা" — এই অর্থে এই চারটা claim নিরাপদ, যতক্ষণ সাইনিং
key সুরক্ষিত থাকে।
ধরুন একজন cashier-কে মাঝপথে branch manager-এ promote করা হলো, বা একজন branch manager-এর role downgrade/suspend
করা হলো ডেটাবেসে। কিন্তু তার আগে ইস্যু করা JWT-তে এখনো পুরোনো user_role: "cashier" (বা পুরোনো higher
role) এনকোড করা আছে — এবং টোকেন valid থাকবে যতক্ষণ exp পার না হয়।
ফলাফল দুই দিকেই ঝুঁকিপূর্ণ: ডিমোশন/সাসপেনশনের ক্ষেত্রে ইউজার পুরোনো higher-privilege role নিয়ে কাজ চালিয়ে যেতে পারবে (security risk); প্রমোশনের ক্ষেত্রে নতুন প্রিভিলেজ অ্যাক্সেস করতে গেলে আটকে যাবে যতক্ষণ না সে আবার লগইন করে (UX bug)। JWT-তে role এনকোড করার এটাই মূল মূল্য — role পরিবর্তনের প্রতিফলন instant হয় না।
সাধারণ নিয়ম: JWT payload-এ এমন কিছুই রাখবেন না যা (ক) সরাসরি PII, (খ) দ্রুত পরিবর্তনশীল, অথবা (গ) ক্লায়েন্ট-সাইডে এমনিতেই UI থেকে পাওয়া যাবে। যেটা সত্যিকারের প্রয়োজন তা হলো একটা stable identifier (user_id) যা দিয়ে প্রতিটা প্রোটেক্টেড রিকোয়েস্টে সার্ভার চাইলে fresh ডেটা lookup করতে পারে।
সংক্ষিপ্ত উত্তর: হ্যাঁ, এটা ইন্ডাস্ট্রি-স্ট্যান্ডার্ড সর্বোত্তম প্র্যাকটিসের সবচেয়ে কাছাকাছি — কিন্তু এর একটা পারফরম্যান্স মূল্য আছে, যা বুঝে নেওয়া জরুরি।
এখানেই আসল প্রশ্ন — যদি প্রতিটা প্রোটেক্টেড রিকোয়েস্টে user_id দিয়ে role/permission lookup করতে হয়,
তাহলে আমরা কি Session-based পদ্ধতির মতোই একটা lookup করছি না? উত্তর: হ্যাঁ, আংশিকভাবে — কিন্তু এই lookup আর
session-lookup সম্পূর্ণ একই খরচের না, যদি সঠিকভাবে ডিজাইন করা হয়।
| প্যাটার্ন | প্রতি-রিকোয়েস্ট খরচ | মন্তব্য |
|---|---|---|
| Pure Session lookup (DB hit) | উচ্চ — প্রতিবার DB query | Method-01 এড়াতে চাইছিল, এটাই |
| JWT-এ role এনকোডেড (Method-01 বর্ণিত) | শূন্য — শুধু signature verify | স্পিড সর্বোচ্চ, কিন্তু stale-role সমস্যা থেকে যায় |
| JWT-এ user_id + role lookup Redis cache থেকে | খুব কম — in-memory cache hit (সাধারণত <1ms) | প্রায়-stateless পারফরম্যান্স, কিন্তু fresh role + instant-revocation সুবিধা একসাথে পাওয়া যায় |
আপনার Pharmaciano-এর মতো সিস্টেমে যেহেতু Redis ক্যাশিং ইতিমধ্যে আছে
(আপনার N.B. অনুযায়ী), সবচেয়ে ভালো প্যাটার্ন হলো: JWT-তে শুধু user_id + একটা short-lived
role-snapshot রাখা, এবং প্রতিটা রিকোয়েস্টে middleware Redis থেকে current role/permission চেক করবে (DB hit না,
in-memory hit)। এতে stale-role সমস্যা সমাধান হয়, পারফরম্যান্স প্রায় stateless-এর কাছাকাছি থাকে, এবং role
পরিবর্তন/revocation সাথে সাথে কার্যকর হয় কারণ Redis entry আপডেট/ডিলিট করা mongo DB lookup-এর চেয়ে অনেক সস্তা।
user_id-only +
Redis-cached permission lookup ই সবচেয়ে ব্যালান্সড সমাধান।আপনার প্রশ্নটা সরাসরি এবং গুরুত্বপূর্ণ: "যদি একটা JWT-ই ইউজারকে ঠিকমতো অথেন্টিকেট করতে পারে, তাহলে refresh token, revocation, rotation এই জটিলতাগুলো কেন আনা হয়?" — চলুন প্রতিটাকে আলাদা করে যুক্তি দিয়ে justify করি, কারণ এই তিনটা আসলে তিনটা ভিন্ন সমস্যার সমাধান করে, একটার সমাধান অন্যটা দিয়ে হয় না।
মূল যুক্তি: এটা "best of both worlds" — UX-এ কোনো compromise (ইউজার বারবার লগইন করে না) করা ছাড়াই security exposure window কে drastically কমিয়ে আনে। দুটো টোকেনের ভূমিকা আলাদা: access token হলো "এই মুহূর্তে কাজ করার জন্য" (frequently exposed, short-lived), refresh token হলো "নতুন access token পাওয়ার অনুমতি" (rarely transmitted, long-lived, well-protected)।
একটা স্টেটলেস JWT সিস্টেমের সবচেয়ে বড় দুর্বলতা হলো এটা — "আমি এখন এই ইউজারকে ব্লক করতে চাই" — এই ইচ্ছাটা JWT নিজে থেকে সম্মান করতে পারে না, কারণ টোকেন একবার ইস্যু হলে সার্ভার আর তার ওপর কোনো নিয়ন্ত্রণ রাখে না exp ছাড়া। Refresh token-কে সার্ভারে track করে রাখলে (একটা ডেটাবেস টেবিল বা Redis সেটে) revocation সহজ হয়ে যায়:
Refresh Token Rotation মানে — প্রতিবার refresh token ব্যবহার করে নতুন access token নেওয়ার সময়, সার্ভার একটা নতুন refresh token-ও ইস্যু করে এবং পুরোনোটা invalid করে দেয়। এর পেছনের যুক্তি হলো replay-ডিটেকশন:
| মেকানিজম | কোন সমস্যার সমাধান করে | না থাকলে কী হয় |
|---|---|---|
| Short-lived Access + Refresh | Exposure window কমানো | একটা leak হলে দীর্ঘ সময় (Method-01-এ ২৪ ঘণ্টা) এক্সপোজড থাকে |
| Revocation/Blacklist | "এখনই বন্ধ করো" ক্ষমতা | Admin চাইলেও তাৎক্ষণিক অ্যাক্সেস বন্ধ করতে পারে না |
| Token Rotation | চুরি হওয়া টোকেনের silent, persistent ব্যবহার ডিটেক্ট করা | চুরি যাওয়া refresh token অনির্দিষ্টকাল ব্যবহার করে যেতে পারে, কোনো অ্যালার্ম ছাড়াই |
একটা একক JWT "অথেন্টিকেট করতে পারে" — এটা সত্য, কিন্তু authentication-এর কাজ শুধু "কে এটা প্রমাণ করা" নয়; এর সাথে আসে lifecycle management-এর দায়িত্ব — সিস্টেমকে compromise, abuse, বা policy পরিবর্তনের সাথে real-time-এ adapt করার ক্ষমতা দেওয়া। Method-01 প্রথম কাজটা (প্রমাণ করা) ভালোভাবে করে, কিন্তু দ্বিতীয় কাজটা (নিয়ন্ত্রণ করা) সম্পূর্ণ উপেক্ষা করে। এটাই ঠিক যেখানে refresh + revocation + rotation একসাথে এসে সেই ফাঁকটা পূরণ করে।
আপনি যে real curl রিকোয়েস্ট ও রেসপন্স দিয়েছেন, তা decode করে কয়েকটা গুরুত্বপূর্ণ, বাস্তব
নিরাপত্তা-সংকেত পাওয়া গেছে। এগুলো শুধু theoretical না — এটা একটা লাইভ প্রোডাকশন সিস্টেমের আসল আচরণ।
// curl কমান্ডের Authorization হেডারের টোকেন (পুরোনো/স্টেল টোকেন) decode করে:
{
"userId": "6991e81185553e712a4a0a1a",
"lastLogin": "2026-05-29T20:11:15.000Z",
"iat": 1780063875,
"exp": 1780668675
}
// রেসপন্সে পাওয়া নতুন টোকেন decode করে:
{
"userId": "6991e81185553e712a4a0a1a",
"lastLogin": "2026-06-25T14:56:59.000Z",
"iat": 1782377819,
"exp": 1782982619
}
প্রশ্নে যা বর্ণনা করা হয়েছিল (claims-এ user_name, user_email, user_role থাকা) — বাস্তব
টোকেনে তা নেই। আসল payload-এ শুধু userId, lastLogin, iat,
exp আছে। এটা Section 5-6 এ যা সুপারিশ করা হয়েছে তার সাথে সামঞ্জস্যপূর্ণ — Pharmaciano ইতিমধ্যে
claims minimal রাখার ভালো প্র্যাকটিস অনুসরণ করছে বলে মনে হচ্ছে। TTL হিসাব করলে — exp - iat = ৬০৪৮০০
সেকেন্ড = ৭ দিন। এটা প্রশ্নে বর্ণিত ২৪-ঘণ্টা ধারণার চেয়েও দীর্ঘ — যা ঝুঁকি আরও বাড়িয়ে দেয়
(নিচে বিস্তারিত)।
লক্ষ্য করুন — দেওয়া curl কমান্ডে লগইন রিকোয়েস্টের সাথেই একটা পুরোনো, এখনো-হয়তো-ভ্যালিড
JWT Authorization: Bearer ... হেডারে পাঠানো হয়েছে। এটা একটা লগইন এন্ডপয়েন্ট — এখানে কোনো
Bearer token-ই দরকার নেই, কারণ ইউজার তখনও অথেন্টিকেটেড না। এর মানে এই টোকেনটা সম্ভবত কোনো API testing টুল
(Postman/Swagger/Insomnia) থেকে স্বয়ংক্রিয়ভাবে কপি হয়ে গেছে — এবং এটাই হলো ঠিক Section 3.2-তে বর্ণিত
"Token Replay via Accidental Exposure" অ্যাটাকের একটা জীবন্ত উদাহরণ।
লক্ষণীয়: যদি এই টোকেনটা — যা একটা ডকুমেন্টেশন/example-এ বসে আছে — এখনো
এক্সপায়ার না হয়ে থাকে (৭ দিনের TTL মনে রাখুন), এবং এই ডকুমেন্ট/example কোথাও publicly শেয়ার্ড থাকে (Slack
চ্যানেল, পাবলিক GitHub repo, support ticket), তাহলে এটা userId: 6991e81185553e712a4a0a1a — সম্ভবত
super administrator — অ্যাকাউন্টের জন্য একটা সরাসরি, ব্যবহারযোগ্য takeover vector। এটাই একদম Section 3.2 আর 3.6-এ
আলোচিত theoretical ঝুঁকির বাস্তব রূপ।
| হেডার | মান | মূল্যায়ন |
|---|---|---|
strict-transport-security |
max-age=31536000; includeSubDomains | ভালো — HSTS ১ বছরের জন্য এনফোর্সড, সব সাবডোমেইনে |
content-security-policy |
default-src 'self'; script-src 'self'... | ভালো — restrictive CSP, ইনলাইন script ব্লকড, যা XSS-এর কার্যকারিতা সীমিত করে |
x-content-type-options |
nosniff | ভালো — MIME-sniffing অ্যাটাক প্রতিরোধ করে |
x-frame-options |
SAMEORIGIN | ভালো — clickjacking-এর বিরুদ্ধে সুরক্ষা |
access-control-allow-origin |
https://pharmaciano.onrender.com | ভালো — wildcard (*) না, নির্দিষ্ট origin |
access-control-allow-credentials |
true | নজরে রাখা দরকার — এটা ঠিক আছে যদি ALLOW-ORIGIN wildcard না হয় (যা এখানে ঠিকই আছে), কিন্তু এর মানে কুকি-ভিত্তিক অথ ব্যবহৃত হচ্ছে — তাই কুকির SameSite/HttpOnly সেটিংস অত্যন্ত গুরুত্বপূর্ণ হয়ে পড়ে |
set-cookie |
(হেডারে দেখানো হয়নি) | অনিশ্চিত — যদি টোকেন response body-তে JSON-এ ফেরত আসে (যা এই রেসপন্সে হয়েছে) এবং ক্লায়েন্ট তা localStorage-এ রাখে, তাহলে HttpOnly cookie protection সম্পূর্ণ বাইপাস হয়ে যাচ্ছে — Section 3.1-এর XSS ঝুঁকি সরাসরি প্রযোজ্য |
server / x-render-origin-server |
cloudflare / Render | তথ্য-উন্মোচন — hosting stack প্রকাশ পাচ্ছে, যা reconnaissance-এ সামান্য সাহায্য করতে পারে আক্রমণকারীকে, কিন্তু এটা সাধারণত minor risk |
রেসপন্স বডিতে সরাসরি "token": "eyJ..." JSON ফিল্ডে টোকেন ফেরত আসছে। এর মানে
ফ্রন্টএন্ড কোডকে এই টোকেন জাভাস্ক্রিপ্ট দিয়ে read করে কোথাও store করতে হবে — এবং সবচেয়ে
সম্ভাব্য জায়গা localStorage। যদি তা-ই হয়, তাহলে CSP থাকা সত্ত্বেও (CSP script injection ঠেকায়,
কিন্তু সব XSS ভেক্টর ঠেকায় না — যেমন DOM-based XSS, dependency-injected malicious script যদি 'self' থেকেই serve
হয়) একটা সফল XSS attack token-টা সরাসরি পড়ে ফেলতে পারবে।
আপনার বর্ণনা অনুযায়ী — একটা সার্ভার, একটা শেয়ার্ড MongoDB, এবং Redis caching ইতিমধ্যে আছে। এই তথ্যটা গুরুত্বপূর্ণ কারণ এটা সরাসরি প্রভাবিত করে কোন সমাধান practically সহজ:
revoked_tokens:{jti} বা
user_sessions:{userId}) ব্যবহার করতে হবে
refresh_tokens) যোগ করা ন্যূনতম অতিরিক্ত খরচ/auth/login-এ POST করে। সার্ভার বিক্রুপ্ট দিয়ে পাসওয়ার্ড verify করে।user_id, jti — token identifier) এবং একটা long-lived
Refresh Token (random opaque string, ৭-১৪ দিন) জেনারেট করে।refresh_tokens কালেকশনে save হয় — সাথে userId, deviceInfo,
issuedAt, expiresAt, familyId (rotation chain ট্র্যাক করার জন্য)।
HttpOnly,
Secure, SameSite=Strict কুকিতে সেট করে পাঠানো হয় — response body-তে raw টোকেন ফেরত আসে
না (যা Pharmaciano-এর বর্তমান প্যাটার্ন থেকে একটা গুরুত্বপূর্ণ পরিবর্তন)।jti
ব্ল্যাকলিস্টে আছে কিনা চেক করে (O(1) lookup), তারপর Redis থেকে current role/permission নিয়ে আসে (cache miss হলেই
DB hit)।/auth/refresh কল করে — refresh token কুকি
থেকে স্বয়ংক্রিয়ভাবে পাঠানো হয়।familyId) instantly revoke করে দেয় এবং ইউজারকে re-authenticate করতে বাধ্য করে — এটা breach
signal।| অপারেশন | কী ঘটে |
|---|---|
| স্বাভাবিক Logout | Refresh token DB থেকে delete; access token-এর jti Redis ব্ল্যাকলিস্টে অ্যাড (TTL = বাকি access
token lifetime) |
| "সব ডিভাইস থেকে Logout" | সেই userId-এর সব refresh token DB থেকে delete + একটা tokenInvalidAfter: now()
timestamp ইউজার রেকর্ডে সেট, middleware প্রতিটা JWT-র iat এই timestamp-এর সাথে তুলনা করে |
| Admin কর্তৃক User Suspend | ইউজার ডকুমেন্টে status: suspended সেট + সেই ইউজারের সব refresh token revoke + active access
token-গুলো পরের permission-lookup-এ Redis cache miss করিয়ে ব্লক (cache-invalidate করে দিলে) |
| Password পরিবর্তন | স্বয়ংক্রিয়ভাবে সব refresh token revoke (security best practice — নতুন পাসওয়ার্ড সেট করার পর পুরোনো সব সেশন অবৈধ হওয়া উচিত) |
আশঙ্কা হতে পারে — "প্রতিটা রিকোয়েস্টে Redis lookup মানে তো অতিরিক্ত latency।" বাস্তবে Redis in-memory lookup সাধারণত সাব-মিলিসেকেন্ড (০.১-১ms), যা MongoDB-তে ডিস্ক-ভিত্তিক query-র (কয়েক ms থেকে শুরু করে, ইনডেক্স miss হলে অনেক বেশি) তুলনায় নগণ্য। যেহেতু Redis ইতিমধ্যে Pharmaciano-এর স্ট্যাকে আছে, এই hybrid প্যাটার্ন কোনো নতুন অপারেশনাল জটিলতা যোগ করে না — শুধু বিদ্যমান ইনফ্রাস্ট্রাকচার আরও কার্যকরভাবে ব্যবহার করে।
Backend-এর আর্কিটেকচার যত ভালোই হোক, ফ্রন্টএন্ডে ভুল হ্যান্ডলিংয়ে পুরো সিকিউরিটি মডেল ভেঙে যেতে পারে। নিচে priority অনুযায়ী সাজানো ফ্রন্টএন্ড-সংক্রান্ত মাস্ট-কনসার্ন তালিকা।
localStorage.setItem('token', ...) বা sessionStorage-এ
access/refresh token রাখা — এই দুটোই জাভাস্ক্রিপ্ট দিয়ে readable, তাই যেকোনো XSS vulnerability (এমনকি একটা npm
dependency-র মধ্যে hidden malicious code থেকেও) টোকেন সরাসরি চুরি করে নিতে পারে।
টোকেন HttpOnly কুকিতে রাখুন (যা JavaScript দিয়ে পড়া যায় না), এবং
সার্ভার-সাইডে সেট করুন। ফ্রন্টএন্ড কোডের তখন টোকেন নিয়ে সরাসরি কিছু করার দরকার নেই — ব্রাউজার স্বয়ংক্রিয়ভাবে
প্রতিটা রিকোয়েস্টে কুকি অ্যাটাচ করবে।
dangerouslySetInnerHTML (React) বা innerHTML (vanilla JS) ব্যবহার করে
ইউজার-জেনারেটেড কনটেন্ট সরাসরি render করবেন না — DOMPurify-এর মতো লাইব্রেরি দিয়ে sanitize করুনnpm audit) — supply-chain attack একটা বাস্তব ঝুঁকিযেহেতু আমরা কুকি-ভিত্তিক টোকেন স্টোরেজ সুপারিশ করছি, CSRF protection অপরিহার্য — কুকি স্বয়ংক্রিয়ভাবে ব্রাউজার
পাঠিয়ে দেয়, তাই SameSite=Strict (বা ন্যূনতম Lax) + একটা CSRF টোকেন (double-submit cookie
প্যাটার্ন বা synchronizer token) state-changing রিকোয়েস্টে (POST/PUT/DELETE) ব্যবহার করুন।
console.log দিয়ে টোকেন/সেনসিটিভ ডেটা প্রিন্ট করা থেকে বিরত থাকুন (সহজে ভুলে
যাওয়া কিন্তু gravely risky)Axios/fetch interceptor ব্যবহার করে ৪০১ রেসপন্সে স্বয়ংক্রিয়ভাবে refresh চেষ্টা করুন, ব্যর্থ হলে gracefully login পেজে রিডাইরেক্ট করুন — ইউজারকে কোনো cryptic error দেখানো উচিত না (যেমন raw JSON error বা stack trace, যা প্রোডাকশন সিস্টেমে ইনফরমেশন-লিকেজ ঝুঁকি তৈরি করে)।
যেহেতু এই ERP-তে POS টার্মিনাল শেয়ার্ড ডিভাইস হতে পারে (Section 3.8), ফ্রন্টএন্ডে একটা স্পষ্ট, প্রমিনেন্ট "Switch User" / "Lock Screen" ফিচার রাখা উচিত — যাতে শিফট পরিবর্তনের সময় স্টাফরা পুরো ব্রাউজার বন্ধ না করেও নিরাপদে session পরিবর্তন করতে পারে। সাথে, ইনঅ্যাক্টিভিটি-ভিত্তিক auto-logout (যেমন ৫-১০ মিনিট নিষ্ক্রিয়তার পর) POS টার্মিনালের জন্য একটা ভালো অতিরিক্ত সুরক্ষা স্তর।
| আইটেম | স্ট্যাটাস হওয়া উচিত |
|---|---|
| Token storage | HttpOnly Cookie — localStorage না |
| User input rendering | Sanitized (DOMPurify) |
| State-changing requests | CSRF token + SameSite |
| Console logging | প্রোডাকশনে disabled |
| ৪০১ হ্যান্ডলিং | Auto-refresh interceptor |
| Shared device protection | Auto-lock + Quick switch user |
| Dependency audit | নিয়মিত npm audit / Snyk |
নিচে Method-01 (Before — Pharmaciano-এর বর্তমান বাস্তবায়ন) এবং Section 9-এ প্রস্তাবিত আর্কিটেকচার (After) এর পাশাপাশি তুলনা — সিকিউরিটি, পারফরম্যান্স, এবং অ্যাটাক-সারফেস তিনটা মাত্রায়।
| অ্যাটাক ভেক্টর | Before — ঝুঁকি স্তর | After — ঝুঁকি স্তর |
|---|---|---|
| XSS দিয়ে Token Theft | উচ্চ (যদি localStorage-এ থাকে) | কম (HttpOnly cookie পড়া যায় না) |
| Token Replay (leaked/logged token) | উচ্চ (৭ দিন exposure window) | কম (১৫ মিনিট window + revoke সম্ভব) |
| Insider/ছাঁটাই-পরবর্তী অ্যাক্সেস | উচ্চ (revoke অসম্ভব) | নগণ্য (instant revoke) |
| CSRF | নির্ভরশীল (cookie ব্যবহৃত হলে SameSite ক্রিটিক্যাল) | কম (SameSite=Strict + CSRF token) |
| চুরি হওয়া refresh token-এর persistent ব্যবহার | প্রযোজ্য নয় (refresh token নেই) | ডিটেক্টেবল (rotation reuse-detection) |
| মেট্রিক | Before | After |
|---|---|---|
| প্রতি-রিকোয়েস্ট ভেরিফিকেশন খরচ | শূন্য lookup (pure signature check) | +Redis lookup (~০.১-১ms) — নগণ্য বৃদ্ধি |
| লগইন ফ্রিকোয়েন্সি (ইউজার-অভিজ্ঞতা) | ৭ দিনে একবার | সিলেন্ট refresh — ইউজার কার্যত একবারই লগইন করে (UX অপরিবর্তিত) |
| Token সাইজ (নেটওয়ার্ক ওভারহেড) | ছোট (minimal claims) | একই রকম ছোট, পরিবর্তন নগণ্য |
"After" আর্কিটেকচার পারফরম্যান্সে ব্যবহারিকভাবে অপরিবর্তিত থাকে (Redis lookup-এর খরচ এত কম যে ইউজার-অভিজ্ঞতায় কোনো পার্থক্য অনুভূত হবে না), কিন্তু সিকিউরিটি ঝুঁকি প্রতিটা মাত্রায় significantly কমে যায় — বিশেষ করে instant-revocation ক্ষমতা, যা একটা মাল্টি-organization, মাল্টি-branch ERP-তে অপারেশনাল প্রয়োজনীয়তা (যেমন দ্রুত staff offboarding) হিসেবেই গণ্য হওয়া উচিত, নিরাপত্তা-বিলাসিতা না।
Session আর JWT-র বাইরেও আধুনিক সিস্টেমে আরও কিছু গুরুত্বপূর্ণ অথেন্টিকেশন/অথোরাইজেশন পদ্ধতি ব্যবহৃত হয়। প্রতিটার উপযুক্ত প্রসঙ্গ, কারণ এবং একটা সিনারিও দেওয়া হলো।
কী: ইউজার আপনার অ্যাপের পাসওয়ার্ড তৈরি না করে, Google/Facebook-এর মাধ্যমে অথেন্টিকেট হয়। আপনার সার্ভার Google-কে বিশ্বাস করে identity verification-এর জন্য। কেন/কখন: ইউজার অনবোর্ডিং ফ্রিকশন কমাতে, পাসওয়ার্ড ম্যানেজমেন্টের দায়িত্ব এড়াতে (Google-ই 2FA, breach-detection handle করে)। ERP প্রসঙ্গে: যদি Pharmaciano-এর ক্লায়েন্ট organization-গুলো Google Workspace ব্যবহার করে, SSO (Single Sign-On) দিয়ে staff onboarding/offboarding-কে organization-এর নিজের identity provider-এর সাথে সিঙ্ক করা যায় — কেউ চাকরি ছাড়লে Google Workspace থেকে রিমুভ করলেই ERP অ্যাক্সেসও বন্ধ হয়ে যায়।
কী: একটা দীর্ঘ-মেয়াদী, র্যান্ডম স্ট্রিং যা রিকোয়েস্ট হেডারে পাঠানো হয়, সাধারণত human session না, বরং machine-to-machine যোগাযোগের জন্য। কখন: Pharmaciano-এর AI-forecasting মডিউল যদি একটা এক্সটার্নাল ডেটা-প্রোভাইডার (যেমন supplier price feed API) থেকে ডেটা টানে, বা যদি Pharmaciano নিজেই একটা পাবলিক API অফার করে accounting software ইন্টিগ্রেশনের জন্য (Tally, QuickBooks-সদৃশ)। সিকিউরিটি নোট: API key-কে rate-limit এবং scope-restrict করা জরুরি — একটা leaked key দিয়ে সর্বোচ্চ কতটা ক্ষতি হতে পারে তা সীমিত রাখতে হয়।
কী: পাসওয়ার্ডের পাশাপাশি একটা দ্বিতীয় ফ্যাক্টর (SMS OTP, TOTP অ্যাপ যেমন Google Authenticator, বা hardware key) যাচাই করা। কেন: পাসওয়ার্ড একা compromise হলেও (phishing, credential-stuffing) আক্রমণকারী দ্বিতীয় ফ্যাক্টর ছাড়া লগইন করতে পারবে না। ERP প্রসঙ্গে অপরিহার্য কোথায়: Super-admin এবং financial-approval-ক্ষমতাসম্পন্ন role-গুলোর জন্য MFA বাধ্যতামূলক করা উচিত — কারণ এই অ্যাকাউন্টগুলোর compromise সবচেয়ে বেশি আর্থিক ক্ষতির কারণ হতে পারে।
কী: ইউজারকে একটা ফিক্সড role দেওয়া হয়, এবং প্রতিটা role-এর সাথে নির্দিষ্ট permission-সেট বাঁধা থাকে। সীমাবদ্ধতা: RBAC দ্রুত জটিল হয়ে পড়ে যখন একই role-এর মধ্যেও সূক্ষ্ম পার্থক্য দরকার হয় (যেমন "এই branch manager শুধু তার নিজের branch-এর ডেটা দেখতে পারবে, অন্য branch-এর না")।
কী: পারমিশন নির্ধারিত হয় শুধু role দিয়ে না, বরং একসেট attribute দিয়ে
— ইউজারের organization, branch, department, এমনকি সময় (যেমন "শুধু business hours-এ access")। কেন
Pharmaciano-এর জন্য এটাই দরকার: আপনার বর্ণনা অনুযায়ী মাল্টি-organization, মাল্টি-branch সিস্টেম — একই
"Branch Manager" role থাকা দুইজন ভিন্ন organization-এর ইউজারের একে অপরের ডেটা দেখার অধিকার থাকা উচিত না। এটা শুধু
role দিয়ে এক্সপ্রেস করা কঠিন, কিন্তু পলিসি হিসেবে সহজ:
permission = (role == 'branch_manager') AND (resource.branchId == user.branchId) AND (resource.orgId == user.orgId)।
এই পলিসি evaluation middleware-এ implement করতে হবে, এবং JWT-তে orgId ও branchId claim
রাখা (user_id-এর পাশাপাশি, সতর্কতার সাথে non-PII হওয়ায়) practically সহায়ক হতে পারে।
কী: পাসওয়ার্ড সম্পূর্ণ বাদ দিয়ে, একটা ইমেইল লিংক (magic link) বা ডিভাইস-বাউন্ড ক্রিপ্টোগ্রাফিক কী (WebAuthn/Passkey, যা biometric দিয়ে আনলক হয়) দিয়ে অথেন্টিকেট করা। কেন গুরুত্বপূর্ণ হয়ে উঠছে: পাসওয়ার্ড reuse এবং phishing — দুটোই সম্পূর্ণ অপ্রাসঙ্গিক হয়ে যায়, কারণ চুরি করার মতো কোনো "secret" ইউজারের মাথায় থাকে না। ২০২৬ সালে Apple, Google, Microsoft সবাই Passkey-কে primary authentication method হিসেবে push করছে।
| পদ্ধতি | মূল ব্যবহার | Pharmaciano-এর জন্য প্রাসঙ্গিকতা |
|---|---|---|
| OAuth2/SSO | থার্ড-পার্টি/এন্টারপ্রাইজ আইডেন্টিটি | ভবিষ্যতে Organization-level SSO ইন্টিগ্রেশনের জন্য বিবেচনাযোগ্য |
| API Key | Machine-to-machine | AI-forecasting external feed, একাউন্টিং সফটওয়্যার ইন্টিগ্রেশন |
| MFA | উচ্চ-প্রিভিলেজ অ্যাকাউন্ট সুরক্ষা | অবিলম্বে প্রয়োজন — super-admin ও financial-approver role |
| RBAC | সাধারণ role-ভিত্তিক অনুমতি | বেস লেয়ার হিসেবে থাকতে পারে |
| PBAC/ABAC | সূক্ষ্ম, প্রসঙ্গ-নির্ভর অনুমতি | মূল প্রয়োজন — multi-org, multi-branch isolation-এর জন্য অপরিহার্য |
| Passwordless/WebAuthn | Phishing-প্রতিরোধী লগইন | মধ্য-মেয়াদী রোডম্যাপ আইটেম হিসেবে বিবেচনাযোগ্য |
AI-এর যুগে আক্রমণও দ্রুততর এবং স্বয়ংক্রিয় হয়ে উঠেছে (automated credential-stuffing bots, AI-generated phishing, LLM-assisted vulnerability scanning)। নিচে ২০২৬ সালের প্রেক্ষাপটে একটা আধুনিক সিস্টেমে যা থাকা প্রায়-বাধ্যতামূলক বলে গণ্য করা উচিত।
| স্ট্যান্ডার্ড | কেন প্রয়োজনীয় |
|---|---|
| Short-lived Access Token + Rotated Refresh Token | আগে বিস্তারিত আলোচিত — exposure window সীমিত করা |
| MFA (অন্তত উচ্চ-প্রিভিলেজ রোলে বাধ্যতামূলক) | Credential-stuffing/phishing আক্রমণের বিরুদ্ধে দ্বিতীয় স্তর |
| Rate Limiting + Account Lockout (login endpoint) | Brute-force/credential-stuffing বট প্রতিরোধ — এখন AI দিয়ে এই আক্রমণ আরও স্কেলেবল |
| Bot Detection (CAPTCHA বা behavioral analysis) | স্বয়ংক্রিয় স্ক্রিপ্টেড আক্রমণ ফিল্টার করা |
| Passwordless/Passkey সাপোর্ট (অন্তত optional) | Phishing-resistant; ইন্ডাস্ট্রি ধীরে ধীরে এই দিকে সরে যাচ্ছে |
| Anomaly/Impossible-travel ডিটেকশন | একই অ্যাকাউন্ট থেকে অসম্ভব ভৌগোলিক দূরত্বে একসাথে লগইন ধরা |
| স্ট্যান্ডার্ড | কেন প্রয়োজনীয় |
|---|---|
| Least Privilege by Default | নতুন ইউজার/role ডিফল্টভাবে সর্বনিম্ন অ্যাক্সেস পাবে, প্রয়োজনে এক্সপ্লিসিটলি বাড়ানো হবে |
| Server-side Permission Re-verification | ক্লায়েন্ট UI hide করলেও সার্ভার সবসময় আলাদাভাবে permission চেক করবে — "frontend hides button" কখনো security control না |
| Audit Logging (immutable) | কে কখন কী করেছে তার পরিবর্তনহীন রেকর্ড — কম্প্লায়েন্স এবং forensic investigation-এর জন্য অপরিহার্য, বিশেষত accounting ERP-তে |
| Field-level Encryption (sensitive data at rest) | Database breach হলেও সবচেয়ে sensitive ফিল্ড (যেমন bank account info) এখনো এনক্রিপ্টেড থাকবে |
নিচে অথেন্টিকেশন কুকি ও সিকিউরিটি হেডারের জন্য একটা সম্পূর্ণ রেফারেন্স — কী সেট করতে হবে, কেন, এবং কী মান সাধারণত ব্যবহার করা হয়।
| অ্যাট্রিবিউট | প্রস্তাবিত মান | বিবরণ |
|---|---|---|
HttpOnly |
true | JavaScript দিয়ে কুকি পড়া/লেখা সম্পূর্ণ ব্লক করে — XSS-এর মাধ্যমে টোকেন চুরি প্রতিরোধের সবচেয়ে গুরুত্বপূর্ণ একক সেটিং |
Secure |
true | কুকি শুধুমাত্র HTTPS কানেকশনে পাঠানো হবে, plain HTTP-তে কখনো না — MITM-এর ঝুঁকি কমায় |
SameSite |
Strict (বা ন্যূনতম Lax) | ক্রস-সাইট রিকোয়েস্টে কুকি পাঠানো বন্ধ/সীমিত করে — CSRF-এর প্রধান প্রতিরোধক। Strict সবচেয়ে কড়া (third-party লিংক থেকে এলেও কুকি যাবে না); Lax কিছুটা flexible (টপ-লেভেল নেভিগেশনে কুকি যায়) |
Domain |
নির্দিষ্ট, যেমন .pharmaciano.com |
কোন ডোমেইন/সাবডোমেইনে কুকি ভ্যালিড তা সীমিত করে — অতিরিক্ত wide scope (যেমন উদ্দেশ্যহীনভাবে পুরো TLD) এড়িয়ে চলা উচিত |
Path |
/ বা নির্দিষ্ট রুট |
কুকি কোন URL path-এ প্রযোজ্য তা নির্ধারণ করে; refresh token-এর জন্য path সীমিত রাখা (যেমন শুধু
/auth/refresh) অতিরিক্ত সতর্কতা হতে পারে
|
Max-Age / Expires |
Access: ~১৫ মিনিট Refresh: ৭-১৪ দিন |
কুকির লাইফটাইম — JWT-র নিজের exp claim-এর সাথে সামঞ্জস্যপূর্ণ হওয়া উচিত |
__Host- prefix (cookie name prefix) |
প্রস্তাবিত, যেমন __Host-refreshToken |
ব্রাউজারকে বাধ্য করে যে এই কুকি Secure, Path=/, এবং কোনো Domain
অ্যাট্রিবিউট ছাড়া হতে হবে — cookie-injection আক্রমণের বিরুদ্ধে অতিরিক্ত সুরক্ষা স্তর |
| হেডার | প্রস্তাবিত মান | বিবরণ |
|---|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
ব্রাউজারকে বাধ্য করে যেন ভবিষ্যতে শুধু HTTPS-এ কানেক্ট করে, এমনকি ইউজার ভুলে http:// টাইপ
করলেও — Pharmaciano ইতিমধ্যে এটা সঠিকভাবে সেট করেছে |
Content-Security-Policy |
default-src 'self'; script-src 'self' |
কোন সোর্স থেকে স্ক্রিপ্ট/স্টাইল/ইমেজ লোড হতে পারবে তা নিয়ন্ত্রণ করে — XSS-এর কার্যকারিতা সীমিত করার একটা মূল স্তর |
X-Content-Type-Options |
nosniff |
ব্রাউজারকে ফাইলের MIME-টাইপ "অনুমান" করতে নিষেধ করে — malicious ফাইলকে script হিসেবে চালানো প্রতিরোধ করে |
X-Frame-Options |
SAMEORIGIN বা DENY |
আপনার সাইট অন্য ডোমেইনের <iframe>-এ embed হওয়া থেকে আটকায় — clickjacking প্রতিরোধ
|
Referrer-Policy |
no-referrer বা strict-origin-when-cross-origin |
URL-এ থাকা sensitive তথ্য (যেমন query param-এ token) অন্য সাইটে referrer হিসেবে leak হওয়া আটকায় |
Access-Control-Allow-Origin |
নির্দিষ্ট origin (কখনো * না, যদি credentials লাগে) |
CORS — কোন ডোমেইন থেকে ক্রস-অরিজিন রিকোয়েস্ট গ্রহণযোগ্য তা নির্দিষ্ট করে |
Access-Control-Allow-Credentials |
true (যদি কুকি-ভিত্তিক অথ ব্যবহৃত হয়) |
ক্রস-অরিজিন রিকোয়েস্টে কুকি পাঠানোর অনুমতি দেয় — সবসময় নির্দিষ্ট origin-এর সাথে পেয়ার করতে হবে, wildcard-এর সাথে না |
Permissions-Policy |
প্রয়োজন অনুযায়ী সীমিত, যেমন geolocation=(), camera=() |
ব্রাউজার ফিচার (ক্যামেরা, লোকেশন, মাইক্রোফোন) এক্সেস নিয়ন্ত্রণ করে — ব্যবহার না হলে disable রাখা ভালো |
Cross-Origin-Opener-Policy |
same-origin |
আপনার পেজ এবং অন্য origin-এর উইন্ডোর মধ্যে JS-level যোগাযোগ আটকায় — cross-origin attack-এর একটা স্তর কমায় |
Section 8.3-এ দেখানো হয়েছে — Pharmaciano-এর response header-এ HSTS, CSP, X-Content-Type-Options, X-Frame-Options, এবং সঠিক CORS configuration ইতিমধ্যে আছে। এটা header-level সিকিউরিটিতে একটা ভালো ভিত্তি দেখায়। মূল উন্নতির জায়গা হলো cookie-ভিত্তিক HttpOnly token storage-এ যাওয়া এবং token lifecycle management (Sections 7, 9) যোগ করা।
যেকোনো সিস্টেম ডিজাইনের আগে নিচের প্রশ্নগুলো ধারাবাহিকভাবে নিজেকে করা উচিত — উত্তরগুলোই নির্ধারণ করবে কোন পদ্ধতি (Session/JWT/Hybrid), কোন TTL, কতটা revocation-complexity প্রয়োজন।