Skip to main content

Command Palette

Search for a command to run...

Backend Security (Part-5)

Hashing With Salting

Published
5 min readView as Markdown

আমি যখন প্রথম পাসওয়ার্ড স্টোর করার কথা ভাবতাম, তখন খুব সহজভাবে চিন্তা করতাম—ডাটাবেজে প্লেইন টেক্সটে না রেখে যদি হ্যাশ করে রাখি, তাহলেই সব সমস্যা শেষ। বাস্তবে বিষয়টা মোটেও এত সরল না।

এখানে আমি ধরে নিচ্ছি যে আমি আগেই সব জানি না। যেসব টার্ম ব্যবহার করব—MD5, SHA‑256, bcrypt, Argon2ID—সবগুলোর মানে ধীরে ধীরে বোঝাব। টার্গেট একটাই: পাসওয়ার্ড সিকিউরিটির পুরো ছবিটা মাথায় পরিষ্কার করে রাখা। যদিও গত লেখায় আমি প্লেইন পাসওয়ার্ড এবং হ্যাশিং নিয়ে বলেছি , তবুও প্রথমে একটু আবার এই বিষয় গুলো নিয়ে হালকা একটা ধারণা দিয়ে যাবো ।


১. পাসওয়ার্ড সরাসরি স্টোর করা কেন ভয়ংকর

ধরি, আমার একটা অ্যাপ আছে। ইউজার সাইনআপ করার সময় ইমেইল আর পাসওয়ার্ড দেয়। আমি যদি সেই পাসওয়ার্ডটা ঠিক যেভাবে ইউজার দিয়েছে সেভাবেই ডাটাবেজে রেখে দিই, তাহলে একদিন যদি ডাটাবেজ লিক হয়, সেই মুহূর্তেই সব ইউজারের আসল পাসওয়ার্ড বের হয়ে যাবে।

সমস্যা এখানেই শেষ না। মানুষ সাধারণত একই পাসওয়ার্ড অনেক জায়গায় ব্যবহার করে। একটা লিক মানে—ইমেইল, ব্যাংক, সোশ্যাল সব ঝুঁকিতে।

এই জায়গা থেকেই হ্যাশিংয়ের ধারণাটা আসে।


২. হ্যাশিং আসলে কী এবং কী নয়

হ্যাশিং হলো এক ধরনের গাণিতিক ফাংশন, যেটা কোনো ইনপুট নিয়ে একটা নির্দিষ্ট দৈর্ঘ্যের আউটপুট তৈরি করে।

এর সবচেয়ে গুরুত্বপূর্ণ বৈশিষ্ট্য হলো—এটা একমুখী (one‑way)

উদাহরণ:

"12345"hash"a8c9e4f2..."

আমি ইনপুট থেকে আউটপুট পেতে পারি, কিন্তু আউটপুট দেখে ইনপুট বের করা বাস্তবে অসম্ভব।

লগইনের সময় আমি আসল পাসওয়ার্ডের সাথে তুলনা করি না। আমি আবার নতুন করে হ্যাশ বানাই, তারপর আগের হ্যাশের সাথে মিলাই।

আইডিয়াটা ভালো। কিন্তু এখানেই গল্প শেষ না।


৩. MD5 ও SHA‑256 কী (এবং কেন এগুলো পাসওয়ার্ডের জন্য খারাপ)

MD5 কী

  • অনেক পুরোনো হ্যাশ ফাংশন

  • এখন Cryptographically Broken ধরা হয়

  • আজকের দিনে পাসওয়ার্ডের জন্য একেবারেই ব্যবহারযোগ্য না

SHA‑256 কী

  • SHA‑2 পরিবারের অংশ

  • এখনো ফাইল ইন্টেগ্রিটি, ডিজিটাল সিগনেচার ইত্যাদিতে ব্যবহৃত হয়

  • কিন্তু সমস্যা হলো—এটা ভয়ংকর দ্রুত

Python‑এ SHA‑256 ব্যবহার করা খুব সহজ:

import hashlib

password = "12345"
hash_value = hashlib.sha256(password.encode()).hexdigest()
print(hash_value)

এই কোডটা চালাতে প্রায় কোনো সময়ই লাগে না। এখন যদি এটা GPU দিয়ে করা হয়? একটা আধুনিক GPU সেকেন্ডে বিলিয়ন বিলিয়ন SHA‑256 হ্যাশ হিসাব করতে পারে।


৪. Rainbow Table Attack কেন সম্ভব হয়

হ্যাশিংয়ের একটা বৈশিষ্ট্য হলো—একই ইনপুট দিলে সবসময় একই আউটপুট আসে।

এই বৈশিষ্ট্যটাই Rainbow Table আক্রমণের ভিত্তি।

আক্রমণকারীরা আগেই লক্ষ লক্ষ সাধারণ পাসওয়ার্ড নিয়ে সেগুলোর হ্যাশ বানিয়ে রাখে:

  • "12345" → এই হ্যাশ

  • "password" → ওই হ্যাশ

  • "qwerty" → আরেকটা হ্যাশ

এই বিশাল mapping‑টাই হলো Rainbow Table।

Rainbow Tables: The Password Conundrum Part 4 — Between The Hacks

যদি আমার ডাটাবেজ লিক হয় এবং আমি শুধু hash(password) রেখে থাকি, তাহলে আক্রমণকারী খুব সহজেই lookup করে কিছু ইউজারের আসল পাসওয়ার্ড বের করে ফেলতে পারে।


৫. Salting: একই পাসওয়ার্ড, কিন্তু আলাদা হ্যাশ

Rainbow Table আটকানোর প্রথম বাস্তব সমাধান হলো Salting

Salting মানে—পাসওয়ার্ডের সাথে একটা র‍্যান্ডম ডাটা যোগ করা, যেটা প্রতিটা ইউজারের জন্য আলাদা।

বাস্তবে আমি যেটা হ্যাশ করি:

hash(password + salt)

Salt:

  • র‍্যান্ডম

  • ইউনিক

  • ডাটাবেজে রাখা যায়

  • গোপন হওয়ার দরকার নেই

Python উদাহরণ:

import os
import hashlib

password = "12345"
salt = os.urandom(16)
hash_value = hashlib.sha256(password.encode() + salt).hexdigest()

এখন দুইজন ইউজারের পাসওয়ার্ড একই হলেও হ্যাশ আলাদা হবে। Rainbow Table এখানে একেবারেই অকেজো।


৬. Salting থাকলেও Brute Force কেন ভয়ংকর

এখানে এসে অনেকেই ভাবে— “Salt তো আছে, এখন আমি পুরো সেফ।”

ভুল।

যদি আক্রমণকারী পুরো ডাটাবেজ পায়:

  • সে প্রতিটা ইউজারের salt পায়

  • প্রতিটা ইউজারের জন্য আলাদা brute force চালাতে পারে

GPU দিয়ে:

  • প্রতি সেকেন্ডে বিলিয়ন ট্রাই

  • সাধারণ প্যাটার্ন কয়েক দিনে শেষ

Salt শুধু Rainbow Table আটকায়। Brute force আটকায় না।


৭. Slow Password Hashing Function কেন দরকার

এখানেই সাধারণ হ্যাশ আর password hashing‑এর পার্থক্য।

bcrypt, scrypt, Argon2—এগুলো ইচ্ছা করে ধীর বানানো। এই অ্যালগরিদমগুলোতে আমি ঠিক করে দিতে পারি— একটা হ্যাশ বানাতে কত সময় লাগবে। এটাই cost factor বা work factor।

ধরি, একটা হ্যাশ বানাতে cost factor 400ms দিয়ে দিলাম । মানে 400ms স্লো জেনারেট হবে , এই সময় টা একজন ইউজার এর লগইন পাসওয়ার্ড চেক করার জন্য খুব নগণ্য সময় ধরা যায়


৮. bcrypt কী এবং কেন এতদিন স্ট্যান্ডার্ড ছিল

bcrypt বহু বছর ধরে industry standard ছিল—এবং এখনো অনেক জায়গায় আছে। এটা মূলত CPU‑bound। ভিতরে Blowfish‑based repeated round ব্যবহার করে। bcrypt‑এ একটা cost factor থাকে। এই cost যত বাড়ে, হ্যাশ করতে সময় তত বাড়ে।

Python উদাহরণ:

import bcrypt

password = b"12345"

hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))

bcrypt.checkpw(password, hashed)

bcrypt:

  • নিজেই salt বানায়

  • salt হ্যাশের ভেতরেই রাখে

  • সহজ, battle‑tested

আজও bcrypt নিরাপদ। কিন্তু এর একটা সীমাবদ্ধতা আছে—মেমোরি ব্যবহার খুব কম


৯. Argon2ID কী এবং কেন এটা আলাদা

Argon2 হলো Password Hashing Competition (PHC) এর উইনার অ্যালগরিদম।

Argon2ID এমনভাবে ডিজাইন করা, যাতে:

  • CPU ধীর হয়

  • মেমোরি ব্যবহার বাধ্যতামূলক হয়

GPU খুব দ্রুত গণনা করতে পারে। কিন্তু GPU‑র বড় দুর্বলতা হলো—প্রচুর মেমোরি parallel ভাবে ব্যবহার করা।

Argon2ID এই দুর্বলতাকেই টার্গেট করে।

এখানে আমি কনফিগার করতে পারি:

  • কত মেমোরি লাগবে

  • কত iteration হবে

  • কত parallel thread

Python উদাহরণ:

# pip install argon2-cffi
from argon2 import PasswordHasher

# Create a PasswordHasher instance with custom parameters
ph = PasswordHasher(
    time_cost=3,          # Number of iterations
    memory_cost=64 * 1024, # Memory usage in KiB (64 MB)
    parallelism=2         # Number of parallel threads
)

# Hash a password
password = "12345"
hash_value = ph.hash(password)
print(f"Hash: {hash_value}")

লাইব্রেরি নিজেই:

  • salt বানায়

  • নিরাপদ default ব্যবহার করে

  • timing attack handle করে


১০. bcrypt বনাম Argon2ID

bcrypt:

  • CPU‑bound

  • বহু বছর ধরে battle‑tested

  • implement সহজ

  • GPU‑র বিরুদ্ধে তুলনামূলক দুর্বল

Argon2ID:

  • CPU + memory‑hard

  • GPU ও ASIC‑এর বিরুদ্ধে শক্ত

  • আধুনিক হার্ডওয়্যার মাথায় রেখে ডিজাইন

  • কনফিগারেশন বুঝে সেট করতে হয়

নতুন সিস্টেম হলে Argon2ID সেরা পছন্দ। পুরোনো সিস্টেমে ঠিকভাবে কনফিগার করা bcrypt এখনো গ্রহণযোগ্য।


১১. শেষ কথা

এই পুরো লেখাটা লিখে আমার কাছে একটা জিনিস খুব পরিষ্কার হয়েছে— পাসওয়ার্ড সিকিউরিটি কোনো এক লাইনের কোড না। এটা আসলে একটা চিন্তার ধারাবাহিকতা।

কিছু গুরুত্বপূর্ণ ভুল, যেগুলো আমি আর করব না

❌ MD5 ব্যবহার করব না
❌ SHA-256 দিয়ে পাসওয়ার্ড হ্যাশ করব না
❌ নিজের মতো করে hashing scheme বানানোর লোভে পড়ব না
❌ Plain text তো প্রশ্নই আসে না

✔ Argon2id ব্যবহার করব
✔ ভালো লাইব্রেরির default সেটিংসকে সম্মান করব
✔ Login-এ rate limit রাখব—কারণ বাস্তব দুনিয়ায় মানুষ ভুল পাসওয়ার্ড দেয়, আর বট ট্রাই করে

এই লিস্টটা নিয়ম নয়, এটা আমার নিজের সঙ্গে করা একটা চুক্তি। ভুল থেকে শেখা জিনিসগুলো যেন ভুলে না যাই—এই জন্যই।