এনক্রিপশন ও ডেটা সুরক্ষা
এই পাঠে যা শিখবেন
- এনক্রিপশন ইন-ট্রানজিট বনাম এট-রেস্টের পার্থক্য এবং প্রতিটির ব্যবহার
- কেন TLS হ্যান্ডশেকে অ্যাসিমেট্রিক ও সিমেট্রিক ক্রিপ্টো দুটোই একসাথে ব্যবহৃত হয়
- হ্যাশিং বনাম এনক্রিপশন, এবং পাসওয়ার্ডের জন্য কেন ধীর সল্টেড হ্যাশিং জরুরি
- Python-এ stdlib
hashlibদিয়ে সল্টেড পাসওয়ার্ড হ্যাশিং ও ভেরিফিকেশন বাস্তবে প্রয়োগ করা
১ · এনক্রিপশন ইন-ট্রানজিট — TLS/HTTPS
এনক্রিপশন ইন-ট্রানজিটEncryption in Transitডেটা নেটওয়ার্কের মধ্য দিয়ে যাওয়ার সময় (ক্লায়েন্ট থেকে সার্ভার) সুরক্ষিত রাখা — TLS/HTTPS এর মূল কাজ। নিশ্চিত করে ক্লায়েন্ট ও সার্ভারের মধ্যে চলাচল করা ডেটা কেউ মাঝপথে পড়তে বা বদলাতে না পারে (L06-এ HTTPS-এর সংক্ষিপ্ত পরিচিতি দেখুন)। এই সুরক্ষা দুই ধাপে কাজ করে —
RSA/ECC (discrete-math কোর্সের RSA পাঠের সরাসরি সম্প্রসারণ) ব্যবহার করে ক্লায়েন্ট ও সার্ভার নিরাপদে একটি শেয়ার্ড সিমেট্রিক কী তৈরি/বিনিময় করে — কম্পিউটেশনালি ব্যয়বহুল, তাই শুধু একবার এই ধাপে ব্যবহৃত হয়।
হ্যান্ডশেকে পাওয়া শেয়ার্ড কী দিয়ে AES-এর মতো সিমেট্রিক অ্যালগরিদম ব্যবহার করে আসল ডেটা এনক্রিপ্ট/ডিক্রিপ্ট হয় — অনেক দ্রুত, তাই বড় পরিমাণ ডেটার জন্য উপযুক্ত।
শুধু অ্যাসিমেট্রিক ক্রিপ্টো ব্যবহার করলে পুরো কানেকশন অনেক ধীর হয়ে যেত — অ্যাসিমেট্রিক অপারেশন সিমেট্রিকের চেয়ে অনেক বেশি CPU-ব্যয়বহুল। শুধু সিমেট্রিক ব্যবহার করলে প্রথমে দুই পক্ষ কীভাবে একটি শেয়ার্ড কী নিরাপদে বিনিময় করবে তার কোনো উপায় থাকত না (একজন আড়িপাতাকারী কী-টিও ধরে ফেলতে পারত)। তাই বাস্তবে অ্যাসিমেট্রিক ব্যবহৃত হয় শুধু প্রাথমিক "নিরাপদে হ্যান্ডশেক করা"-র জন্য, আর সিমেট্রিক ব্যবহৃত হয় প্রকৃত ভারী কাজে।
২ · এনক্রিপশন এট-রেস্ট
এনক্রিপশন এট-রেস্টEncryption at Restডিস্কে/ডেটাবেসে/ব্যাকআপে সংরক্ষিত ডেটা সুরক্ষিত রাখা — কেউ সরাসরি স্টোরেজ চুরি করলেও কী ছাড়া ডেটা পড়তে পারবে না। সাধারণত AES দিয়ে করা হয়, এবং কী সংরক্ষণ করা হয় একটি আলাদা Key Management Service (KMS)-এ — যাতে "কে এনক্রিপ্টেড বাইট পড়তে পারে" (স্টোরেজ অ্যাক্সেস) ও "কে কী ধারণ করে" (KMS অ্যাক্সেস) দুটো আলাদা নিয়ন্ত্রণ-স্তর থাকে। কেউ শুধু ডিস্ক/ব্যাকআপ চুরি করলেও, KMS অ্যাক্সেস ছাড়া ডেটা পড়া অসম্ভব।
৩ · হ্যাশিং বনাম এনক্রিপশন — পাসওয়ার্ডের জন্য কোনটা
এনক্রিপশন রিভার্সিবল — সঠিক কী থাকলে যেকোনো এনক্রিপ্টেড ডেটা আবার আসল রূপে ফিরিয়ে আনা যায়। হ্যাশিংHashingএকমুখী (one-way) রূপান্তর — ইনপুট থেকে আউটপুট বের করা সহজ, কিন্তু আউটপুট থেকে আসল ইনপুট ফিরিয়ে আনা কম্পিউটেশনালি অসম্ভবের কাছাকাছি। সম্পূর্ণ একমুখী — কোনো কী দিয়েও হ্যাশ থেকে আসল ইনপুট ফিরিয়ে আনা যায় না। পাসওয়ার্ড কখনোই এনক্রিপ্ট নয়, সবসময় হ্যাশ করা উচিত — কারণ সার্ভারের নিজেরই কখনো পাসওয়ার্ডের মূল টেক্সট জানার দরকার নেই, শুধু যাচাই করার ক্ষমতা দরকার।
MD5 বা সাদামাটা SHA256 ডিজাইন করা হয়েছে দ্রুততার জন্য — চেকসাম বা ইন্টিগ্রিটি যাচাইয়ের মতো কাজে এটি ভালো গুণ। কিন্তু পাসওয়ার্ডের জন্য এই দ্রুততাই সমস্যা — একজন আক্রমণকারী সেকেন্ডে বিলিয়ন সম্ভাব্য পাসওয়ার্ড ট্রাই করতে পারে যদি হ্যাশ অ্যালগরিদম দ্রুত হয়। bcrypt/scrypt/Argon2 ইচ্ছাকৃতভাবে ধীর ও মেমরি-নিবিড় ডিজাইন করা — একটি বৈধ লগইনে এই ধীরতা অনুভবই হয় না (কয়েক মিলিসেকেন্ড), কিন্তু ব্রুট-ফোর্স আক্রমণে এটি হাজার-লক্ষ গুণ ধীর করে দেয়।
৪ · সল্টিং — একই পাসওয়ার্ড, ভিন্ন হ্যাশ
সল্টSaltহ্যাশ করার আগে পাসওয়ার্ডের সাথে যোগ করা একটি ইউনিক, র্যান্ডম মান — প্রতিটি পাসওয়ার্ডের জন্য আলাদা, ডেটাবেসে হ্যাশের পাশে প্লেইন টেক্সটে সংরক্ষিত থাকে। ছাড়া, দুইজন ইউজারের একই পাসওয়ার্ড থাকলে তাদের হ্যাশও হুবহু একই হতো — যা একটি প্রি-কম্পিউটেড rainbow-table আক্রমণকে সহজ করে দিত (লক্ষ লক্ষ সাধারণ পাসওয়ার্ডের হ্যাশ আগে থেকেই গণনা করে রাখা)। প্রতিটি পাসওয়ার্ডে একটি ইউনিক সল্ট যোগ করলে একই পাসওয়ার্ডও ভিন্ন হ্যাশে পরিণত হয় — প্রতিটি ইউজারের জন্য আক্রমণকারীকে আলাদাভাবে ব্রুট-ফোর্স করতে হয়, প্রি-কম্পিউটেড টেবিল আর কাজ করে না।
নিচের কোড সেলে stdlib hashlib ব্যবহার করে একই পাসওয়ার্ড দুটি ভিন্ন সল্ট দিয়ে হ্যাশ করা হলো —
হ্যাশ দুটো ভিন্ন হবে। তারপর একটি ভেরিফিকেশন ফাংশন — সঠিক পাসওয়ার্ডে সফল, ভুল পাসওয়ার্ডে ব্যর্থ হবে।
import hashlib
def hash_password(password, salt):
return hashlib.sha256((salt + password).encode()).hexdigest()
password = "MyS3cretPass!"
# বাস্তবে salt সাধারণত os.urandom(16).hex() দিয়ে জেনারেট করা হয়;
# এই ডেমোতে রিপ্রোডিউসিবল আউটপুটের জন্য দুটি আলাদা fixed salt ব্যবহার করা হলো।
salt1 = "9f86d081884c7d65"
salt2 = "3d4f2bfa1e5c8f21"
hash1 = hash_password(password, salt1)
hash2 = hash_password(password, salt2)
print("Salt 1:", salt1)
print(" Hash:", hash1)
print("Salt 2:", salt2)
print(" Hash:", hash2)
print("\nএকই পাসওয়ার্ড, ভিন্ন salt → হ্যাশ একই কিনা:", hash1 == hash2)
def verify_password(input_password, stored_salt, stored_hash):
return hash_password(input_password, stored_salt) == stored_hash
print("\nসঠিক পাসওয়ার্ড দিয়ে verify:", verify_password("MyS3cretPass!", salt1, hash1))
print("ভুল পাসওয়ার্ড দিয়ে verify: ", verify_password("WrongPass!", salt1, hash1))
hash1 != hash2 যদিও উভয়ই একই password থেকে বানানো, শুধু সল্ট
ভিন্ন। ডেটাবেসে salt ও hash দুটোই একসাথে সংরক্ষণ করা হয় (সল্ট গোপন রাখার দরকার
নেই, শুধু ইউনিক হলেই চলে) — verify_password লগইনের সময় ইউজারের দেওয়া পাসওয়ার্ড + সংরক্ষিত সল্ট
দিয়ে পুনরায় হ্যাশ করে সংরক্ষিত হ্যাশের সাথে তুলনা করে। বাস্তব সিস্টেমে এখানে hashlib.sha256-এর
বদলে bcrypt/scrypt/Argon2-এর মতো ইচ্ছাকৃতভাবে ধীর অ্যালগরিদম ব্যবহৃত হয়, নীতিটা একই থাকে।
নেটওয়ার্কে ডেটা সুরক্ষার জন্য অ্যাসিমেট্রিক + সিমেট্রিক ক্রিপ্টোর সমন্বয় (TLS), সংরক্ষিত ডেটার জন্য AES + আলাদা KMS, আর পাসওয়ার্ডের জন্য ধীর সল্টেড হ্যাশিং — তিনটিই ভিন্ন সমস্যার ভিন্ন সমাধান, একটি দিয়ে অন্যটি প্রতিস্থাপন করা যায় না। "পাসওয়ার্ড এনক্রিপ্ট করা" একটি সাধারণ ভুল ধারণা — সঠিক শব্দ ও প্র্যাকটিস সবসময় "পাসওয়ার্ড হ্যাশ করা" (সল্টসহ, ধীর অ্যালগরিদমে)।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১ একটি ডেটাবেস "পাসওয়ার্ড এনক্রিপ্টেড রাখে" শুনলে কেন সেটি একটি রেড ফ্ল্যাগ হওয়া উচিত?
এনক্রিপশন রিভার্সিবল — অর্থাৎ কোথাও একটি ডিক্রিপশন কী আছে যা দিয়ে আসল পাসওয়ার্ড ফিরিয়ে আনা সম্ভব। এর মানে হয় (ক) সার্ভার অপারেটর/একজন আক্রমণকারী যে কী চুরি করে সে সব ইউজারের প্লেইন-টেক্সট পাসওয়ার্ড দেখতে পারবে, অথবা (খ) ডেভেলপাররা প্রয়োজনে পাসওয়ার্ড ডিক্রিপ্ট করে দেখতে পারেন — উভয়ই নিরাপত্তার দৃষ্টিকোণ থেকে অগ্রহণযোগ্য। সঠিক ডিজাইনে সার্ভারের নিজেরই কখনো প্লেইন-টেক্সট পাসওয়ার্ড ফিরে পাওয়ার সামর্থ্য থাকা উচিত নয় — শুধু হ্যাশ তুলনা করে যাচাই করার সামর্থ্য, যা একমুখী হ্যাশিং দিয়েই সম্ভব।
প্র ০২ সল্ট প্লেইন টেক্সটে ডেটাবেসে রাখা হয় বলা হলো — তাহলে এটি কি নিরাপত্তাহীনতা তৈরি করে না?
না, কারণ সল্টের কাজ গোপন রাখা নয়, বরং প্রতিটি পাসওয়ার্ডকে ইউনিক করা। rainbow-table আক্রমণ কাজ করে কারণ এটি "সাধারণ পাসওয়ার্ড → হ্যাশ" ম্যাপিং আগে থেকে গণনা করে রাখে — একটি ইউনিক সল্ট যোগ হলে সেই প্রি-কম্পিউটেড ম্যাপিং অকেজো হয়ে যায় (প্রতিটি সল্টের জন্য আলাদা টেবিল লাগবে, যা প্র্যাকটিক্যালি অসম্ভব)। আসল নিরাপত্তা আসে হ্যাশ অ্যালগরিদমের ধীরতা ও পাসওয়ার্ডের নিজের এনট্রপি (শক্তি) থেকে, সল্ট গোপন রাখা থেকে নয় — তাই সল্ট প্লেইন টেক্সটে রাখা সম্পূর্ণ স্বাভাবিক ও প্রত্যাশিত প্র্যাকটিস।
প্র ০৩ TLS হ্যান্ডশেকে যদি শুধু সিমেট্রিক ক্রিপ্টো ব্যবহার করা হতো (কোনো অ্যাসিমেট্রিক ধাপ ছাড়াই), তাহলে মূল সমস্যাটা কী হতো?
সমস্যাটা হলো "কী বিতরণ" (key distribution) — দুই পক্ষের প্রথমবার নিরাপদে একটি শেয়ার্ড সিমেট্রিক কী নিয়ে একমত হওয়ার কোনো উপায় থাকবে না একটি অসুরক্ষিত নেটওয়ার্কের উপর দিয়ে, কারণ কী নিজেই যদি প্লেইন টেক্সটে পাঠানো হয় তাহলে একজন আড়িপাতাকারী সেটি ধরে ফেলে সবকিছু ডিক্রিপ্ট করতে পারবে। অ্যাসিমেট্রিক ক্রিপ্টোর বিশেষ গুণ হলো এটি এমন একটি প্রক্রিয়া দেয় যেখানে দুই পক্ষ একটি শেয়ার্ড সিক্রেটে একমত হতে পারে এমনকি পুরো যোগাযোগ কেউ শুনে ফেললেও (এর গাণিতিক ভিত্তি discrete-math কোর্সের RSA পাঠে দেখুন) — এই একবারের নিরাপদ বিনিময়ের পরই দ্রুত সিমেট্রিক এনক্রিপশন নিরাপদে ব্যবহার করা যায়।
অনুশীলন
-
চিন্তা করুন: একটি ই-কমার্স সাইট কোন কোন ডেটার জন্য এনক্রিপশন ইন-ট্রানজিট প্রয়োজন এবং কোন কোন ডেটার জন্য এট-রেস্ট এনক্রিপশনও প্রয়োজন তা তালিকা করুন।
ইন-ট্রানজিট (সব ক্ষেত্রেই, HTTPS দিয়ে): লগইন ক্রেডেনশিয়াল, পেমেন্ট ফর্ম ডেটা, সেশন টোকেন — যেকোনো ক্লায়েন্ট-সার্ভার ট্রাফিক। এট-রেস্টও অতিরিক্তভাবে প্রয়োজন: সংরক্ষিত পেমেন্ট/কার্ড তথ্য, ব্যবহারকারীর ব্যক্তিগত ঠিকানা/পরিচয় তথ্য, ব্যাকআপ ডেটাবেস ফাইল — কারণ এই ডেটা ডিস্কে/ব্যাকআপে চুরি হলেও (নেটওয়ার্ক আক্রমণ ছাড়াই, যেমন একটি চুরি যাওয়া হার্ডডিস্ক) সুরক্ষিত থাকতে হবে।
-
কোড পরিবর্তন করুন: উপরের কোড সেলে একই
salt1ব্যবহার করেpassword-এর একটি সামান্য ভিন্ন ভার্সন (যেমন"MyS3cretPass", শেষে!ছাড়া) হ্যাশ করেhash1-এর সাথে তুলনা করুন — ফলাফল কী প্রমাণ করে?হ্যাশ সম্পূর্ণ আলাদা হয়ে যাবে (SHA256-এর avalanche effect — ইনপুটে সামান্যতম পরিবর্তনেও আউটপুট আমূল বদলে যায়)। এটি প্রমাণ করে হ্যাশ ফাংশন প্রেডিক্টেবল নয় — একজন আক্রমণকারী একটি হ্যাশ দেখে অনুমান করতে পারবে না মূল পাসওয়ার্ডটি কেমন ছিল, এমনকি প্রায়-সঠিক অনুমানও কোনো "কাছাকাছি" হ্যাশ তৈরি করবে না যা দিয়ে দিকনির্দেশনা পাওয়া যায়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫১টি পাঠ পরবর্তী পাঠ — লগিং, মনিটরিং ও ডিস্ট্রিবিউটেড ট্রেসিং।
- L39 · অথেন্টিকেশন ও অথরাইজেশন পূর্ববর্তী এই পাঠের HMAC-সিগনড টোকেন এই লেসনের হ্যাশিং নীতির উপরই তৈরি — ফিরে দেখুন।
- L06 · HTTP/HTTPS ও REST API ডিজাইন পূর্বশর্ত HTTPS-এর প্রাথমিক পরিচিতি এখানে দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, Discrete Mathematics ও System Design — সব এক জায়গায়।