পাঠ ২৯ · ৬০-এর মধ্যে · মডিউল ৫
Home / Courses / Cybersecurity & Ethical Hacking / A09/A10: লগিং ও SSRF

A09/A10: সিকিউরিটি লগিং ফেইলিওর ও SSRF

A09/A10: Logging failures & SSRF
৮ মিনিট পড়া মধ্যবর্তী · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কেন অপর্যাপ্ত লগিং একটি নিরাপত্তা দুর্বলতা নিজেই, শুধু একটি অপারেশনাল অসুবিধা নয়
  • কী কী ইভেন্ট অবশ্যই লগ করা উচিত এবং কোন প্যাটার্ন লগ থেকে পুনর্গঠনযোগ্য হওয়া উচিত
  • SSRF কীভাবে কাজ করে — সার্ভারকে "প্রক্সি" হিসেবে ব্যবহার করে ইন্টারনাল রিসোর্স অ্যাক্সেস
  • URL allowlist validation দিয়ে SSRF প্রতিরোধ করার প্র্যাকটিক্যাল পদ্ধতি

১ · A09 — সিকিউরিটি লগিং ও মনিটরিং ফেইলিওর

Security Logging and Monitoring FailuresA09 (OWASP Top 10, 2021)ব্যর্থ লগইন, অ্যাক্সেস-কন্ট্রোল লঙ্ঘন, উচ্চ-মূল্যের ট্রানজ্যাকশনের মতো সিকিউরিটি-প্রাসঙ্গিক ইভেন্ট পর্যাপ্তভাবে লগ ও মনিটর না করার ব্যর্থতা। -এর প্রভাব প্রায়ই বাস্তব বিশ্বে বিশাল — অনেক প্রকৃত ব্রিচের গড় শনাক্তকরণ সময় মাসের পর মাস পরিমাপ করা হয়, শুধু এই কারণে যে কেউ সেই সময় পর্যন্ত লক্ষ করেইনি কিছু ভুল হচ্ছে। একটি সিস্টেম প্রযুক্তিগতভাবে "নিরাপদ" হলেও, যদি কোনো আক্রমণ ঘটার পর তা শনাক্ত করার কোনো উপায়ই না থাকে, তাহলে প্রতিরক্ষা কার্যকরভাবে অসম্পূর্ণ।

যা অবশ্যই লগ করা উচিত: ব্যর্থ লগইন প্রচেষ্টা (ties to L25, L30-এর ব্রুট-ফোর্স প্যাটার্ন), অ্যাক্সেস-কন্ট্রোল লঙ্ঘনের প্রচেষ্টা (ties to L18), উচ্চ-মূল্যের ট্রানজ্যাকশন, এবং কনফিগারেশন পরিবর্তন। সমাধান শুধু "লগ রাখা" নয় — লগ + অ্যালার্টিং + একটি নিয়মিত রিভিউ প্রক্রিয়া একসাথে প্রয়োজন (M10-এ আমরা SIEM ও লগ-অ্যানালাইসিস বিস্তারিত কভার করব)।

২ · A10 — Server-Side Request Forgery (SSRF)

SSRFServer-Side Request Forgeryএকটি সার্ভার-সাইড ফিচার যখন ব্যবহারকারীর সরবরাহ করা একটি URL যাচাই ছাড়াই ফেচ করে, আক্রমণকারী সেই সার্ভারকে দিয়ে এমন ইন্টারনাল-অনলি রিসোর্সে অনুরোধ পাঠাতে পারে যা বাইরে থেকে সরাসরি অ্যাক্সেসযোগ্য নয়। -এর একটি ক্লাসিক উদাহরণ: একটি অ্যাপ যদি ব্যবহারকারীর দেওয়া একটি "ইমেজ URL" থেকে থাম্বনেইল তৈরি করার ফিচার দেয়, এবং সেই URL ফেচ করার আগে যাচাই না করে, একজন আক্রমণকারী সেই URL হিসেবে সার্ভারের ইন্টারনাল ক্লাউড মেটাডেটা এন্ডপয়েন্টের মতো ঠিকানা দিয়ে দিতে পারে — সার্ভার নিজেই (আক্রমণকারীর ব্রাউজার নয়) সেই ইন্টারনাল রিসোর্সে অনুরোধ পাঠিয়ে ফেলে এবং প্রতিক্রিয়া আক্রমণকারীকে ফিরিয়ে দেয়।

SSRF-এর প্রতিরক্ষা: অনুমোদিত গন্তব্যের একটি allowlist ব্যবহার করা (শুধু নির্দিষ্ট, পূর্ব-অনুমোদিত ডোমেইন/IP-তে ফেচ করার অনুমতি দেওয়া), অপ্রয়োজনীয় URL-ফেচিং ফিচার সম্পূর্ণ নিষ্ক্রিয় রাখা, এবং নেটওয়ার্ক সেগমেন্টেশন (যাতে অ্যাপ্লিকেশন সার্ভার থেকেও সবচেয়ে স্পর্শকাতর ইন্টারনাল রিসোর্স সরাসরি পৌঁছানো না যায়)।

৩ · কোড ডেমো ১ — লগিং থাকা বনাম না থাকার পার্থক্য

নিচের কোড সেলটি একটি সিমুলেটেড আক্রমণ-সিকোয়েন্স দুইভাবে চালাচ্ছে — একবার লগিং-সহ, একবার লগিং ছাড়া — এবং দেখাচ্ছে লগিং ছাড়া ঘটনাগুলো কার্যত অদৃশ্য থেকে যায়।

Python
events = []

def log_event(event_type, details):
    events.append({"event_type": event_type, "details": details})

def silent_action(event_type, details):
    pass  # লগিং নেই — কিছুই সংরক্ষিত হয় না

# একটি সিমুলেটেড আক্রমণ-সিকোয়েন্স
attack_sequence = [
    ("failed_login", {"user": "admin", "ip": "203.0.113.9"}),
    ("failed_login", {"user": "admin", "ip": "203.0.113.9"}),
    ("access_denied", {"user": "guest42", "resource": "/admin/settings"}),
    ("login_success", {"user": "admin", "ip": "203.0.113.9"}),
    ("high_value_txn", {"user": "admin", "amount": 900000}),
]

for event_type, details in attack_sequence:
    log_event(event_type, details)      # প্রপার লগিং ভার্সনে সংরক্ষিত হচ্ছে
    silent_action(event_type, details)  # সাইলেন্ট ভার্সনে কিছুই সংরক্ষিত হচ্ছে না

print(f"লগ করা ইভেন্ট সংখ্যা: {len(events)} — পুরো আক্রমণ-সিকোয়েন্স পুনর্গঠনযোগ্য")
for e in events:
    print(" -", e["event_type"], e["details"])
print()
print("সাইলেন্ট (আনলগড) ভার্সনে সংরক্ষিত ইভেন্ট সংখ্যা: 0 — একই আক্রমণ সম্পূর্ণ অদৃশ্য থেকে গেল")

    
দুটি সংস্করণেই ঠিক একই আক্রমণ-সিকোয়েন্স ঘটেছে — পার্থক্য শুধু এটাই যে একটিতে ঘটনাগুলো লগ হয়েছে, অন্যটিতে হয়নি। প্রপার লগিং সহ ভার্সনে পুরো ঘটনাক্রম পরে পুনর্গঠন করা যায় (কে, কখন, কী করেছে); সাইলেন্ট ভার্সনে ঘটনাটি ঘটেই যায়নি এমনটাই মনে হয় — যতক্ষণ না ক্ষতির প্রভাব অন্য কোনোভাবে ধরা পড়ে।

৪ · কোড ডেমো ২ — SSRF allowlist ভ্যালিডেশন

নিচের কোড সেলটি একটি "URL fetch" ফিচারের allowlist-ভিত্তিক প্রতিরক্ষা সিমুলেট করছে — কোনো বাস্তব নেটওয়ার্ক কল ছাড়াই, শুধু স্ট্রিং প্যাটার্ন মিলিয়ে।

Python
def is_allowed_url(url, allowlist_prefixes):
    return any(url.startswith(prefix) for prefix in allowlist_prefixes)

allowlist_prefixes = [
    "https://images.trusted-cdn.com/",
    "https://api.partner-service.com/",
]

candidate_urls = [
    "https://images.trusted-cdn.com/photo123.jpg",     # বৈধ, অনুমোদিত CDN
    "http://169.254.169.254/latest/meta-data/",         # ইন্টারনাল ক্লাউড মেটাডেটা এন্ডপয়েন্ট — বিপজ্জনক
    "http://localhost:6379/",                           # ইন্টারনাল সার্ভিস (যেমন Redis) — বিপজ্জনক
    "https://api.partner-service.com/v1/status",        # বৈধ, অনুমোদিত পার্টনার API
]

for url in candidate_urls:
    decision = "অনুমোদিত (fetch করা হবে)" if is_allowed_url(url, allowlist_prefixes) else "প্রত্যাখ্যাত — allowlist-এ নেই"
    print(f"{decision:35s} <- {url}")

    
লক্ষ করুন — allowlist পদ্ধতিতে শুধুমাত্র স্পষ্টভাবে অনুমোদিত ডোমেইনগুলো পাশ করে; ইন্টারনাল মেটাডেটা এন্ডপয়েন্ট বা লোকালহোস্ট সার্ভিসের মতো ঠিকানা — যা "ব্লকলিস্ট" পদ্ধতিতে অনেক সময় মিস হয়ে যায় (নতুন ইন্টারনাল ঠিকানা মনে রাখা কঠিন) — allowlist-এ স্বয়ংক্রিয়ভাবেই বাদ পড়ে যায়, কারণ এটি "ডিফল্ট-ডিনাই" নীতিতে কাজ করে।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ "সিস্টেম প্রযুক্তিগতভাবে নিরাপদ কিন্তু লগিং নেই" — এটি কেন তবুও একটি সিকিউরিটি দুর্বলতা হিসেবে গণ্য হয়?

কোনো সিস্টেমই ১০০% আক্রমণ-প্রতিরোধী নয় — সিকিউরিটির লক্ষ্য শুধু আক্রমণ ঠেকানো নয়, বরং আক্রমণ ঘটলে তা দ্রুত শনাক্ত করে সাড়া দেওয়ার ক্ষমতাও। লগিং ছাড়া, একটি সফল আক্রমণ মাসের পর মাস অশনাক্ত থেকে যেতে পারে, এই সময়ে আক্রমণকারী আরও ক্ষতি করার সুযোগ পায়। তাই যথাযথ মনিটরিং/লগিং না থাকা নিজেই একটি স্বাধীন দুর্বলতা — এটি অন্য সব প্রতিরক্ষার কার্যকারিতা যাচাই করার সুযোগ কেড়ে নেয়।

প্র ০২ SSRF-এ আক্রমণকারী নিজে সরাসরি ইন্টারনাল রিসোর্সে অনুরোধ পাঠায় না কেন — সার্ভারকে দিয়ে পাঠানোর সুবিধা কী?

ইন্টারনাল রিসোর্স (যেমন ক্লাউড মেটাডেটা এন্ডপয়েন্ট বা ইন্টারনাল সার্ভিস) সাধারণত শুধুমাত্র সেই নেটওয়ার্ক সেগমেন্ট থেকেই অ্যাক্সেসযোগ্য যেখানে অ্যাপ্লিকেশন সার্ভার নিজে অবস্থিত — বাইরের ইন্টারনেট থেকে সরাসরি পৌঁছানো যায় না। সার্ভারকে দিয়ে অনুরোধ পাঠালে আক্রমণকারী সেই সার্ভারের নেটওয়ার্ক-অবস্থানের "সুবিধা" ধার করে নেয় — সার্ভার যা যা পৌঁছাতে পারে, আক্রমণকারীও পরোক্ষভাবে সেই সবকিছু পৌঁছাতে পারে।

প্র ০৩ SSRF ঠেকাতে allowlist পদ্ধতি ব্লকলিস্ট পদ্ধতির চেয়ে কেন বেশি নির্ভরযোগ্য ধরা হয়?

ব্লকলিস্ট পদ্ধতিতে ডিফেন্ডারকে সব সম্ভাব্য বিপজ্জনক ঠিকানা আগে থেকে জেনে তালিকাভুক্ত করতে হয় — এবং নতুন ইন্টারনাল সার্ভিস বা ঠিকানা যোগ হলে সহজেই ভুলে যাওয়ার/মিস হওয়ার ঝুঁকি থাকে। Allowlist পদ্ধতি এর উল্টো — এটি "ডিফল্ট-ডিনাই" নীতিতে কাজ করে, শুধু স্পষ্টভাবে অনুমোদিত ঠিকানাই পাশ করে। ফলে ডিফেন্ডারকে সব বিপদ চেনার দরকার নেই — শুধু কী অনুমোদিত তা সীমিত ও স্পষ্টভাবে জানলেই যথেষ্ট, যা অনেক কম ভুলপ্রবণ।

অনুশীলন

  1. পরীক্ষা করুন: প্রথম কোড সেলে attack_sequence-এ আরও একটি ইভেন্ট (যেমন ("password_reset", {"user": "admin"})) যোগ করে চালান — লগ কীভাবে বদলায়?

    নতুন ইভেন্টটিও events লিস্টে যোগ হবে এবং শেষে প্রিন্ট হওয়া রিপোর্টে দেখাবে — এটিই দেখায় লগিং সিস্টেম কোনো নির্দিষ্ট ইভেন্ট-টাইপে সীমাবদ্ধ নয়, বরং যেকোনো সিকিউরিটি-প্রাসঙ্গিক ইভেন্ট একই প্যাটার্নে ক্যাপচার করা যায় — বাস্তব সিস্টেমেও একটি সাধারণ, পুনর্ব্যবহারযোগ্য লগিং ফাংশন এভাবেই ব্যবহার করা হয়।

  2. পরীক্ষা করুন: দ্বিতীয় কোড সেলে allowlist_prefixes-এ "http://169.254.169.254/" যোগ করে (ভুলবশত) চালান — ফলাফল কী দেখায়, এবং এটি বাস্তব জীবনে কেন বিপজ্জনক হবে?

    এখন সেই মেটাডেটা এন্ডপয়েন্ট "অনুমোদিত" হিসেবে দেখাবে — যা দেখায় allowlist নিজেই যদি ভুলভাবে কনফিগার করা হয় (একটি বিপজ্জনক ঠিকানা ভুলবশত যোগ হয়ে যায়), তাহলে পুরো প্রতিরক্ষা ব্যর্থ হয়ে যায়। এই কারণে allowlist তৈরি ও পরিবর্তনের প্রক্রিয়া নিজেই সতর্কতার সাথে রিভিউ করা প্রয়োজন — allowlist থাকাই যথেষ্ট নয়, এর বিষয়বস্তু সঠিক হওয়াও সমান গুরুত্বপূর্ণ।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
A08: সফটওয়্যার ও ডেটা ইন্টিগ্রিটি ফেইলিওর