সরাসরি পর্বে যান
পর্ব ৪৮ · ৬৪-এর মধ্যে · মডিউল ৭

OS নিরাপত্তা — authentication, privilege ring আর memory-সুরক্ষা

Operating System Security — Threats, Password Hashing, MFA and Passkeys, Privilege Rings, Memory-Safety Bugs and Layered Mitigations (NX, Canaries, ASLR, RELRO, CFI, KASLR, SMEP/SMAP, KPTI)

Taught in Bangla, this lesson covers operating system security: the CIA triad, threats and malware, authentication with salted password hashing, MFA, TOTP, passkeys and PAM, privilege rings and the kernel/user split, memory-safety bugs such as buffer overflow, use-after-free and integer overflow, and layered mitigations including NX, stack canaries, ASLR, RELRO, CFI, KASLR, SMEP/SMAP, KPTI and Spectre, plus patching and logging.

এই পর্বে যা শিখবেন

  • CIA triad, threat, vulnerability, attack আর threat model — আর malware-এর প্রধান ধরনগুলোর সংজ্ঞা
  • OS কীভাবে পাসওয়ার্ড রাখে ও যাচাই করে — salt, ধীর hash, /etc/shadow, PAM; আর MFA, TOTP ও passkey কীভাবে কাজ করে
  • Privilege ring আর kernel/user বিভাজন কেন OS নিরাপত্তার ভিত্তি
  • Buffer overflow, use-after-free আর integer overflow — ধারণা হিসেবে; আর NX, canary, ASLR, RELRO, CFI, KASLR, SMEP/SMAP, KPTI কোনটি কী থামায়
  • নিজের সিস্টেম আর binary-র সুরক্ষা নিজে যাচাই করা — /proc, readelf আর mprotect দিয়ে

১ · নিরাপত্তার মূল প্রশ্ন — CIA triad, threat, vulnerability আর attack

পর্ব ৪৬-এ দেখেছেন protection — OS-এর ভেতরের নিয়ম, কোন প্রসেস কোন resource-এ কী করতে পারবে। Security বা নিরাপত্তা আরও বড় প্রশ্ন: কেউ যদি ইচ্ছে করে নিয়ম ভাঙতে চায় — বাইরের আক্রমণকারী, ক্ষতিকর প্রোগ্রাম, এমনকি ভেতরের কোনো মানুষ — তখন সিস্টেম কতটা টেকে? Protection হলো তালা-চাবির ব্যবস্থা; security হলো সেই প্রশ্ন, চোর এলে তালাটি আসলে কাজ করবে কি না।

CIA triad — কী রক্ষা করছি

Confidentiality (গোপনীয়তা)

যার দেখার অধিকার নেই, সে যেন দেখতে না পায়। আপনার মোবাইল ব্যাংকিং-এর ব্যালান্স, রোগীর রিপোর্ট, অন্য ব্যবহারকারীর ফাইল।

OS-এ: file permission, encryption

Integrity (অখণ্ডতা)

অনুমতি ছাড়া কিছু বদলানো যাবে না — বদলালে ধরা পড়বে। বোর্ড পরীক্ষার ফল, kernel-এর ফাইল, ব্যাংকের লেনদেনের রেকর্ড।

OS-এ: write permission, signature, Secure Boot

Availability (প্রাপ্যতা)

দরকারের সময় সেবা পাওয়া যাবে। ঈদের আগে ব্যাংকের সার্ভার বসে গেলে, বা ransomware সব ফাইল আটকে দিলে এটিই ভাঙে।

OS-এ: resource limit, backup, patch

অনেকে যোগ করেন accountability — কে কী করল, পরে প্রমাণ করা যায় কি না (log আর audit-এর কাজ)।

Threat, vulnerability, attack — তিনটি আলাদা শব্দ

বাড়ির দারোয়ানের কথা ভাবুন। এলাকায় চোর আছে — এটি threat (হুমকি), দারোয়ান তা বদলাতে পারেন না। পেছনের জানালার ছিটকিনি ভাঙা — এটি vulnerability (দুর্বলতা), বাড়ির নিজের ত্রুটি। কোনো রাতে চোর ঠিক সেই জানালা দিয়ে ঢোকার চেষ্টা করল — এটি attack (আক্রমণ)। দারোয়ানের কাজ দুর্বলতা সারানো, পাহারা বাড়ানো, আর কিছু ঘটলে খাতায় লিখে রাখা।

  • Vulnerability: সফটওয়্যার, কনফিগারেশন বা মানুষের অভ্যাসের এমন ত্রুটি, যা অপব্যবহার করা যায় — একটি memory বাগ, ডিফল্ট পাসওয়ার্ড, সবার জন্য খোলা ফাইল। প্রকাশিত দুর্বলতাগুলো একটি সাধারণ নম্বর পায়, যাকে বলে CVE.
  • Exploit: নির্দিষ্ট একটি দুর্বলতা কাজে লাগানোর পদ্ধতি বা কোড। এই পর্বে আমরা exploit লিখব না — শিখব কোন ব্যবস্থা তা কঠিন বা অসম্ভব করে।
  • Attack surface: বাইরের জগৎ সিস্টেমের যত জায়গা ছুঁতে পারে — খোলা network port, ইনপুট নেওয়া প্রোগ্রাম, system call, USB পোর্ট। যত ছোট, তত কম ঝুঁকি।
  • Threat model: নকশার শুরুতে চারটি প্রশ্নের উত্তর — কী রক্ষা করছি, কার কাছ থেকে, সে কী কী পারে, আর ব্যর্থ হলে ক্ষতি কত। একটি ব্যক্তিগত ল্যাপটপ আর একটি ব্যাংকের সার্ভারের threat model আলাদা, তাই প্রতিরক্ষাও আলাদা।
মূল নীতি

নিরাপত্তা একটি দেয়াল নয়, কয়েক স্তরের বেড়া — defense in depth. প্রতিটি স্তর কিছু আক্রমণ থামায়, কিছু ফসকায়; একসাথে তারা আক্রমণকে কঠিন, ধীর আর ধরা-পড়ার-মতো করে। এই পর্বের প্রতিটি অংশ সেই বেড়ার একেকটি স্তর।

২ · হুমকির ধরন — malware, ভেতরের মানুষ আর প্রতারণা

ক্ষতিকর সফটওয়্যারকে একসাথে বলে malware. কীভাবে ছড়ায় আর কী করে, তা দিয়ে কয়েকটি প্রধান ধরন — এখানে শুধু সংজ্ঞা, যাতে খবর বা নিরাপত্তা-রিপোর্ট পড়ে বুঝতে পারেন:

ধরনসংজ্ঞাOS-স্তরের প্রধান প্রতিরক্ষা
Virusঅন্য প্রোগ্রাম বা ফাইলের সাথে নিজেকে জুড়ে নেয়; সেই ফাইল চালালে ছড়ায় — মানুষের কোনো কাজ লাগেঅচেনা ফাইল না চালানো, code signing, antivirus
Wormনিজে নিজেই network দিয়ে এক মেশিন থেকে আরেক মেশিনে ছড়ায়, কোনো মানুষের সাহায্য ছাড়াদ্রুত patch, firewall, অপ্রয়োজনীয় সেবা বন্ধ
Trojanদরকারি বা মজার প্রোগ্রামের ছদ্মবেশে আসে, ভেতরে লুকানো ক্ষতিকর কাজশুধু অফিসিয়াল উৎস থেকে অ্যাপ, অনুমতি দেখে install
Ransomwareফাইল এনক্রিপ্ট করে আটকে দেয়, ফেরত দিতে মুক্তিপণ চায়; প্রায়ই ডেটা চুরিও করেঅফলাইন বা immutable backup (পর্ব ৪৫), least privilege, patch
Rootkitঅধিকার পাওয়ার পর নিজেকে লুকিয়ে রাখে — অনেক সময় kernel বা বুটের স্তরে, তাই সাধারণ টুলে দেখা যায় নাSecure Boot ও signed kernel module (পর্ব ০৭), বাইরে থেকে পরীক্ষা

এর বাইরে আছে spyware (গোপনে তথ্য পাঠায়) আর botnet (হাজারো আক্রান্ত মেশিনকে দূর থেকে একসাথে চালানো)। বুটের স্তরে বসা rootkit-কে bootkit বলে — পর্ব ০৭-এ Secure Boot সেই হুমকির বিরুদ্ধেই দেখেছেন।

ভেতরের মানুষ আর প্রতারণা

  • Insider threat: প্রতিষ্ঠানের ভেতরের কেউ — কর্মী, ঠিকাদার — যাঁর বৈধ প্রবেশাধিকার আছে, তিনি ইচ্ছায় বা অসাবধানে ক্ষতি করেন। প্রতিরক্ষা প্রযুক্তি আর নিয়ম দুটোই: প্রয়োজনের চেয়ে বেশি অধিকার না দেওয়া, গুরুত্বপূর্ণ কাজে দুজনের অনুমোদন, আর প্রতিটি admin কাজের log.
  • Social engineering: প্রযুক্তি নয়, মানুষের বিশ্বাস আর তাড়াহুড়োকে কাজে লাগানো — “আমি ব্যাংক থেকে বলছি, আপনার অ্যাকাউন্ট বন্ধ হয়ে যাবে, এখনই কোডটি বলুন।”
  • Phishing: আসলের মতো দেখতে নকল ইমেইল, SMS বা ওয়েবসাইট দিয়ে পাসওয়ার্ড বা OTP আদায়। সবচেয়ে মজবুত OS-ও রক্ষা করতে পারে না, যদি মানুষ নিজেই চাবি তুলে দেন — তাই অংশ ৪-এর passkey এত গুরুত্বপূর্ণ।

বেশিরভাগ বাস্তব ঘটনা শুরু হয় সাধারণ পথে: চুরি হওয়া বা দুর্বল পাসওয়ার্ড, phishing, আর patch না করা পুরোনো সফটওয়্যার। জটিল আক্রমণ খবরে আসে বেশি, কিন্তু প্রতিরক্ষার প্রথম কাজ এই সাধারণ দরজাগুলো বন্ধ করা।

৩ · Authentication — “আপনি যে আপনিই”, তার প্রমাণ

OS কাউকে কিছু করতে দেওয়ার আগে দুটি প্রশ্ন করে। প্রথমটি authentication — আপনি কে, প্রমাণ দিন। দ্বিতীয়টি authorization — প্রমাণিত এই ব্যবহারকারী এই কাজটি করতে পারেন কি না (অংশ ৫, আর বিস্তারিত পর্ব ৪৬ ও ৪৭-এ)। প্রমাণ দেওয়ার তিন রকম উপায়, যাকে বলে factor:

  • যা আপনি জানেন: পাসওয়ার্ড, PIN, passphrase.
  • যা আপনার কাছে আছে: মোবাইল ফোন, security key, স্মার্ট কার্ড।
  • যা আপনি নিজে: আঙুলের ছাপ, মুখ — biometrics. আধুনিক ফোনে biometrics সাধারণত শুধু ডিভাইসের ভেতরের চাবিটি খোলে; আঙুলের ছাপ সার্ভারে যায় না।

পাসওয়ার্ড কীভাবে রাখা হয় — hash, salt আর ইচ্ছাকৃত ধীরতা

সার্ভার বা OS যদি পাসওয়ার্ড সরাসরি লিখে রাখে, তাহলে ফাইলটি একবার চুরি হলেই সবার পাসওয়ার্ড ফাঁস। তাই রাখা হয় একটি cryptographic hash — একমুখী হিসাব, যা থেকে আসল পাসওয়ার্ড উল্টো করে বের করা যায় না। লগইনের সময় আপনার টাইপ করা পাসওয়ার্ডের hash আবার হিসাব করে মেলানো হয়। কিন্তু শুধু hash যথেষ্ট নয়, দুটি কারণে:

  1. একই পাসওয়ার্ড, একই hash: হাজার জন যদি 123456 ব্যবহার করেন, চুরি হওয়া ফাইলে হাজারটি একই সারি। আর জনপ্রিয় পাসওয়ার্ডের hash আগে থেকে হিসাব করা টেবিলে (rainbow table) মিলিয়ে নেওয়া যায়। সমাধান salt: প্রতিটি ব্যবহারকারীর জন্য একটি এলোমেলো মান, পাসওয়ার্ডের সাথে মিশিয়ে hash. salt গোপন নয়, hash-এর পাশেই থাকে — কিন্তু এখন একই পাসওয়ার্ডেও hash আলাদা, আর আগে-বানানো টেবিল অকেজো।
  2. দ্রুত hash পাসওয়ার্ডের শত্রু: MD5, SHA-1 বা SHA-256 বানানো হয়েছে বড় ফাইল দ্রুত যাচাই করতে। ফাইল চুরি হলে একজন আক্রমণকারী নিজের মেশিনে (অফলাইনে) অনুমান করে করে মেলাতে পারে — দ্রুত hash-এ সেকেন্ডে বিপুলসংখ্যক অনুমান। সমাধান ইচ্ছাকৃত ধীর, অনেক মেমরি খায় এমন hash — key stretching: ১৯৯৯-এর bcrypt, ২০০৯-এর scrypt, আর ২০১৫ সালে Password Hashing Competition জেতা Argon2. বৈধ ব্যবহারকারীর কাছে একটি লগইনে কয়েকশো মিলিসেকেন্ড কিছুই নয়; কিন্তু কোটি কোটি অনুমানের কাছে প্রতিটির এই দাম বিশাল।

নিচের stepper-এ আসল scrypt (N = 16384, r = 8, p = 1) দিয়ে হিসাব করা মান দেখানো হয়েছে, পড়ার সুবিধায় hash-এর শুধু প্রথম ১৬টি hex অক্ষর:

1 register rahima: salt = random()2 store scrypt(pw, salt, params)3 register karim: same pw, new salt4 login rahima: recompute + compare5 login rahima: wrong password6 after the check
সার্ভারের হিসাব
salt
সংরক্ষিত hash
এখন হিসাব করা
ফল
  1. রেজিস্ট্রেশন: রহিমা একটি passphrase বেছে নিলেন। সার্ভার নিরাপদ এলোমেলো উৎস থেকে একটি salt বানাল — 9f2c4a71d03e5b86. এখনো কিছু সংরক্ষিত হয়নি।
  2. সংরক্ষণ: salt আর পাসওয়ার্ড মিলিয়ে scrypt হিসাব করা হলো — ফল 003b0d48…. রেকর্ডে থাকে অ্যালগরিদমের নাম, cost-এর মান, salt আর hash; পাসওয়ার্ড নিজে কোথাও নেই।
  3. একই পাসওয়ার্ড, অন্য মানুষ: করিম ঠিক একই passphrase বাছলেন, কিন্তু তাঁর salt 41e07bd2c9a5163f, তাই hash 2decef64… — রহিমার সাথে কোনো মিল নেই। চুরি হওয়া ফাইল দেখে বোঝার উপায় নেই যে দুজনের পাসওয়ার্ড এক।
  4. লগইন: রহিমা পাসওয়ার্ড দিলেন। সার্ভার তাঁর রেকর্ড থেকে salt আর cost পড়ে একই হিসাব আবার করল — 003b0d48…, সংরক্ষিত মানের সাথে মিলল। তুলনা করা হয় constant-time পদ্ধতিতে, যাতে উত্তরের সময় দেখে কিছু বোঝা না যায়। এরপর দ্বিতীয় factor (অংশ ৪)।
  5. ভুল পাসওয়ার্ড: শেষে একটি বাড়তি a — hash হলো e04794e2…, সম্পূর্ণ আলাদা। একটি অক্ষরের পার্থক্যেও কাছাকাছি কিছু আসে না। বার্তা সাধারণ রাখা হয়: “username বা password ভুল” — কোনটি ভুল তা বলা হয় না।
  6. যাচাইয়ের পর: ব্যর্থ চেষ্টাটি log-এ গেল; পরের চেষ্টার আগে অপেক্ষা (rate limit), বারবার ব্যর্থ হলে অ্যাকাউন্ট সাময়িক বন্ধ বা সতর্কবার্তা। সংরক্ষিত hash বদলায়নি।

১৯৭৯ সালে Bell Labs-এর Robert Morris (সিনিয়র) আর Ken Thompson “Password Security: A Case History” নামে একটি লেখায় দেখান, আগের Unix-এ পাসওয়ার্ড কত সহজে অনুমান করা যেত। তাঁদের সমাধানের দুটি অংশ আজও মূল ধারণা: ১২-বিটের একটি salt, আর ইচ্ছে করে ধীর করা একটি hash (DES-ভিত্তিক crypt, ২৫ বার পুনরাবৃত্তি)। পরে hash-গুলো সবার পড়ার যোগ্য /etc/passwd থেকে সরিয়ে শুধু root-এর পড়ার যোগ্য /etc/shadow-এ রাখা শুরু হয়।

বিভিন্ন OS কোথায় রাখে

Linux-এ /etc/passwd-এ ব্যবহারকারীর নাম আর UID থাকে, পাসওয়ার্ডের ঘরে শুধু x; আসল hash /etc/shadow-এ, যা সাধারণ ব্যবহারকারী পড়তে পারেন না। hash-এর শুরুর চিহ্ন বলে দেয় অ্যালগরিদম: $6$ মানে SHA-512 crypt (হাজারো পুনরাবৃত্তির ধীর রূপ), $y$ মানে yescrypt — সাম্প্রতিক বেশ কিছু distro (যেমন Debian 11, Ubuntu 22.04, Fedora 35 থেকে) এটিকে ডিফল্ট করেছে বলে জানা যায়।

$ grep rahima /etc/passwd
rahima:x:1001:1001:Rahima Akter:/home/rahima:/bin/bash
$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1342 Oct 20 10:12 /etc/shadow
$ sudo grep rahima /etc/shadow
rahima:$y$j9T$Kq3...salt...$Xw7...hash...:20381:0:99999:7:::
#       ^alg ^cost  ^salt       ^hash          ^last change (days since 1970)

Windows-এ স্থানীয় অ্যাকাউন্টের তথ্য থাকে SAM database-এ, আর লগইনের কাজ সামলায় LSASS প্রসেস; Windows Hello আর macOS-এর Touch ID-তে আঙুল বা মুখ শুধু ডিভাইসের ভেতরের নিরাপদ চিপে রাখা চাবি খোলে। নিয়ম সবখানে এক: পাসওয়ার্ড বা biometrics-এর আসল রূপ যেন কোথাও খোলা না থাকে।

৪ · ভালো পাসওয়ার্ড, MFA, TOTP, passkey আর PAM

দৈর্ঘ্য জটিলতার চেয়ে বেশি দামি

যুক্তরাষ্ট্রের মান-সংস্থা NIST-এর নির্দেশিকা SP 800-63B ২০১৭ সালের সংস্করণ থেকে পুরোনো অনেক নিয়ম উল্টে দিয়েছে; পরের সংশোধনে দিকটি আরও কড়া। মূল ভাবনা (খুঁটিনাটি সংস্করণভেদে বদলায়):

  • দৈর্ঘ্যই মূল: ন্যূনতম দৈর্ঘ্য বাড়ানো, আর লম্বা passphrase (অন্তত ৬৪ অক্ষর পর্যন্ত) ও স্পেস-সহ সব অক্ষর গ্রহণ করা।
  • জোর করে “একটি বড় হাতের অক্ষর, একটি চিহ্ন” নয়: এমন নিয়মে মানুষ Password1!-এর মতো অনুমানযোগ্য রূপ বানান।
  • নিয়মিত জোর করে বদলানো নয় — শুধু ফাঁসের প্রমাণ পেলে বদলানো।
  • ফাঁস হওয়া ও খুব প্রচলিত পাসওয়ার্ডের তালিকার সাথে মিলিয়ে বাতিল, আর অনলাইনে বারবার ভুল চেষ্টায় rate limit.

কেন দৈর্ঘ্য? সম্ভাব্য পাসওয়ার্ডের সংখ্যা = (অক্ষরের সংখ্যা)দৈর্ঘ্য. দৈর্ঘ্য ঘাতে বসে, তাই প্রতিটি বাড়তি অক্ষর গোটা সংখ্যাকে গুণ করে। নিচের calculator শুধু পাটিগণিত: একটি এলোমেলোভাবে বাছা পাসওয়ার্ড অফলাইনে গড়ে খুঁজে পেতে কত সময় লাগবে, দুটি ধরে-নেওয়া গতিতে — দ্রুত salt-ছাড়া hash-এ সেকেন্ডে ১০১০ অনুমান, আর ঠিকমতো সাজানো ধীর hash-এ সেকেন্ডে ১০৪. আসল গতি হার্ডওয়্যার আর cost-এর মানে অনেক বদলায়; সংখ্যাগুলো তুলনার জন্য।

// Offline guessing cost: keyspace / guess rate. Pure arithmetic, illustrative rates.
const FAST = 1e10;   // assumed guesses per second against a fast, unsalted hash (GPU rig)
const SLOW = 1e4;    // assumed guesses per second against a slow hash (bcrypt/Argon2 tuned)
const cases = [      // [description, symbols to choose from, length]
  ["8 digits",                      10,   8],
  ["8 lowercase letters",           26,   8],
  ["8 chars, all 94 printable",     94,   8],
  ["12 chars, all 94 printable",    94,  12],
  ["4 random words (7776 list)",  7776,   4],
  ["6 random words (7776 list)",  7776,   6],
];
const YEAR = 365.25 * 24 * 3600;
function human(sec) {
  if (sec < 1) return "< 1 second";
  if (sec < 60) return sec.toFixed(1) + " seconds";
  if (sec < 3600) return (sec / 60).toFixed(1) + " minutes";
  if (sec < 86400) return (sec / 3600).toFixed(1) + " hours";
  if (sec < YEAR) return (sec / 86400).toFixed(1) + " days";
  const y = sec / YEAR;
  return (y < 1e6 ? y.toFixed(0) : y.toExponential(1)) + " years";
}
console.log("password".padEnd(28) + "bits".padStart(6) + "   fast hash".padEnd(18) + "  slow hash");
for (const [name, symbols, len] of cases) {
  const space = symbols ** len;           // every possible password of this shape
  const bits = Math.log2(space);
  const avg = space / 2;                  // on average half the space is searched
  console.log(name.padEnd(28) + bits.toFixed(1).padStart(6) + "   " +
              human(avg / FAST).padEnd(16) + "  " + human(avg / SLOW));
}
console.log("\nslow hash is " + (FAST / SLOW).toExponential(0) + " times more work per guess");
console.log("Defence: long random passphrase + unique per site + MFA;");
console.log("servers: salted slow hash (Argon2id/bcrypt/scrypt) + rate limits.");

আউটপুট (নির্ধারিত, প্রতিবার একই):

password                      bits   fast hash        slow hash
8 digits                      26.6   < 1 second        1.4 hours
8 lowercase letters           37.6   10.4 seconds      120.8 days
8 chars, all 94 printable     52.4   3.5 days          9658 years
12 chars, all 94 printable    78.7   754050 years      7.5e+11 years
4 random words (7776 list)    51.7   2.1 days          5793 years
6 random words (7776 list)    77.5   350270 years      3.5e+11 years

slow hash is 1e+6 times more work per guess
Defence: long random passphrase + unique per site + MFA;
servers: salted slow hash (Argon2id/bcrypt/scrypt) + rate limits.

তিনটি শিক্ষা। এক, একই পাসওয়ার্ডে ধীর hash ১০ লাখ গুণ সময় নেয় — ৮ অক্ষরের জটিল পাসওয়ার্ড দ্রুত hash-এ ৩.৫ দিনে, ধীর hash-এ প্রায় ৯,৬৫৮ বছরে। দুই, ১২ অক্ষরে (৭৮.৭ বিট) দ্রুত hash-এও সাড়ে সাত লাখ বছর — দৈর্ঘ্য জটিলতাকে হারায়। তিন, ৭,৭৭৬ শব্দের তালিকা থেকে এলোমেলো ৬টি শব্দ (প্রতিটি প্রায় ১২.৯ বিট, মোট ৭৭.৫) মনে রাখা সহজ, শক্তিতে ১২টি এলোমেলো অক্ষরের কাছাকাছি। সাবধান: এই হিসাব শুধু সত্যিই এলোমেলো পাসওয়ার্ডের জন্য। মানুষের বানানো Dhaka@2026 ধরনের পাসওয়ার্ড অনুমানকারীর তালিকার শুরুতেই থাকে, তাই আসল সময় অনেক কম। আর এক সাইটের পাসওয়ার্ড অন্য সাইটে ব্যবহার করলে এক জায়গার ফাঁসে সব জায়গা ঝুঁকিতে পড়ে (credential stuffing) — তাই প্রতি সাইটে আলাদা পাসওয়ার্ড, একটি password manager, আর MFA.

MFA আর TOTP — ফোনের ছয় অঙ্কের কোড কোথা থেকে আসে

Multi-factor authentication মানে দুই বা ততোধিক ভিন্ন ধরনের factor. পাসওয়ার্ড চুরি হলেও দ্বিতীয় factor ছাড়া ঢোকা যায় না। Authenticator অ্যাপের ছয় অঙ্কের কোড আসে TOTP (time-based one-time password, RFC 6238, ২০১১) থেকে: সার্ভার আর ফোন একটি গোপন চাবি K ভাগ করে নেয়, তারপর দুজনেই আলাদাভাবে বর্তমান সময় থেকে একই কোড হিসাব করে। হিসাবের কেন্দ্রে HMAC — চাবি-নির্ভর একটি hash. নিচের মানগুলো RFC 6238-এর নিজস্ব পরীক্ষার চাবি দিয়ে হিসাব করা (বাস্তবে চাবি এলোমেলো):

  1. Enrollsecret KQR কোডে
  2. সময় → counter⌊T / 30⌋দুই পাশেই
  3. HMAC-SHA1HMAC(K, C)২০ বাইট
  4. Truncate31 bits৪ বাইট বাছাই
  5. যাচাইmod 10^6সার্ভার মেলায়
  6. ৩০ সেকেন্ড পরC + 1নতুন কোড
এই মুহূর্তে
সময় T (Unix সেকেন্ড)
Counter C
হিসাবের মান
স্ক্রিনে কোড
  1. চাবি ভাগ: MFA চালুর সময় সার্ভার একটি এলোমেলো গোপন চাবি K বানিয়ে QR কোডে দেখায়; অ্যাপ সেটি ফোনে রাখে, সার্ভারও (এনক্রিপ্ট করে) রাখে। এখানে RFC-র পরীক্ষার চাবি — ASCII 12345678901234567890, ২০ বাইট। এরপর K আর কখনো network-এ যায় না।
  2. সময় থেকে counter: T = 1234567890 (২০০৯ সালের ১৩ ফেব্রুয়ারি, 23:31:30 UTC). ৩০ সেকেন্ডের ধাপে ভাগ করলে C = 41152263, ভাগশেষ ০. ফোন আর সার্ভার দুজনেরই ঘড়ি মোটামুটি মিলতে হয়।
  3. HMAC: HMAC-SHA1(K, C) দেয় ২০ বাইট — 907cd1a9…3fe703. K না জানলে এই মান অনুমান করা যায় না।
  4. Truncate: শেষ বাইটের নিচের ৪ বিট (03 → ৩) বলে কোথা থেকে ৪ বাইট নিতে হবে: বাইট ৩–৬ = a9116564; সবচেয়ে উঁচু বিট মুছে 0x29116564 = 689005924.
  5. কোড আর যাচাই: 689005924-কে ১০৬ দিয়ে ভাগ করলে ভাগশেষ 005924 — স্ক্রিনের কোড। সার্ভার একই হিসাব করে মেলায়; ঘড়ির সামান্য পার্থক্যের জন্য সাধারণত আগের-পরের এক ধাপও গ্রহণ করে, আর একবার ব্যবহৃত কোড আবার নেয় না।
  6. পরের ধাপ: T = 1234567920-এ C = 41152264, HMAC সম্পূর্ণ বদলে নতুন কোড 590587; পুরোনোটি অকেজো। তবু মনে রাখুন: একটি নকল ওয়েবসাইট আপনার কাছ থেকে কোডটি নিয়ে সেই ৩০ সেকেন্ডের মধ্যেই আসল সাইটে বসিয়ে দিতে পারে — TOTP phishing পুরো ঠেকায় না।

Passkey — phishing-প্রতিরোধী লগইন

SMS-এ আসা OTP সুবিধাজনক, কিন্তু SIM বদলের প্রতারণা বা মানুষকে বুঝিয়ে কোড আদায়ের ঝুঁকি আছে; NIST-এর নির্দেশিকাও SMS-কে দুর্বলতর বিকল্প হিসেবে দেখে। সবচেয়ে মজবুত পথ FIDO2/WebAuthn (২০১৯ সালে W3C মান হয়), যার ভোক্তা-নাম passkey (২০২২ সাল থেকে Apple, Google আর Microsoft একসাথে প্রচার করছে):

  • প্রতিটি সাইটের জন্য ডিভাইস একটি আলাদা public/private key জোড়া বানায়; সার্ভার পায় শুধু public key — চুরি হলেও লগইন করা যায় না।
  • লগইনে সার্ভার একটি এলোমেলো challenge পাঠায়, ডিভাইস private key দিয়ে সই করে। Private key ডিভাইসের নিরাপদ চিপ (TPM, Secure Enclave) বা পাসওয়ার্ড-ম্যানেজারের ভেতরেই থাকে।
  • মূল শক্তি: সইটি সাইটের আসল ঠিকানার (origin) সাথে বাঁধা — ব্রাউজার নিজে ঠিকানা মিলিয়ে দেয়। নকল ওয়েবসাইটের জন্য আসল সাইটের সই তৈরিই হয় না, তাই ব্যবহারকারী ভুল করলেও phishing কাজ করে না।

PAM — Linux-এ লগইনের নিয়মগুলো এক জায়গায়

login, sshd, sudo — প্রতিটি প্রোগ্রাম কি নিজে নিজে পাসওয়ার্ড যাচাই করে? না। Linux (আর অনেক Unix) ব্যবহার করে PAM — Pluggable Authentication Modules, যা ১৯৯০-এর দশকে Sun Microsystems-এ শুরু হয়। প্রতিটি সেবার নিয়ম /etc/pam.d/-এর একটি ফাইলে, ছোট ছোট module-এর তালিকা হিসেবে। নতুন নিয়ম (যেমন TOTP বা বারবার ভুলে অ্যাকাউন্ট আটকানো) যোগ করতে প্রোগ্রাম বদলাতে হয় না, শুধু তালিকা:

auth      required   pam_faillock.so preauth     # too many failures? stop early
auth      sufficient     pam_unix.so             # hash in /etc/shadow matches? done
auth      [default=die]  pam_faillock.so authfail  # reached only on failure: count it
password  requisite  pam_pwquality.so minlen=12  # reject short or common new passwords
password  required   pam_unix.so yescrypt        # store the new hash with yescrypt
session   required   pam_limits.so               # apply ulimits for the session

Windows-এ এই কাজ করে LSA আর তার authentication package (যেমন domain-এ Kerberos). PAM ফাইল ভুল সম্পাদনা করলে কেউই লগইন করতে না পারার ঝুঁকি থাকে — তাই একটি root shell খোলা রেখে পরীক্ষা করা হয়।

৫ · OS নিরাপত্তার শিকড় — privilege ring, kernel/user বিভাজন আর least privilege

পাসওয়ার্ড দরজা পাহারা দেয়। কিন্তু ভেতরে ঢোকার পর একটি প্রোগ্রাম কেন অন্য প্রোগ্রামের মেমরি পড়তে বা ডিস্কের যেকোনো সেক্টরে লিখতে পারে না? উত্তর হার্ডওয়্যারে। পর্ব ০৪ আর ০৫-এ দেখেছেন: CPU-র অন্তত দুটি অবস্থা — user mode আর kernel mode. x86-এ চারটি ring (০–৩), যার মধ্যে Linux, Windows আর macOS ব্যবহার করে শুধু ring 0 (kernel) আর ring 3 (অ্যাপ); ARM-এ একই ধারণা EL0 (অ্যাপ), EL1 (kernel), EL2 (hypervisor), EL3 (firmware-এর secure monitor).

হার্ডওয়্যারের নিয়মকী রক্ষা করেভাঙার চেষ্টা করলে
Privileged instruction শুধু ring 0-তেinterrupt বন্ধ, page table বদল, I/O port, timer — পুরো মেশিনের নিয়ন্ত্রণCPU exception, kernel প্রসেসটিকে থামায়
প্রতিটি প্রসেসের নিজের page tableএক প্রসেস অন্যের মেমরি দেখতেই পায় না (পর্ব ৩২)ঠিকানাই অনুবাদ হয় না — page fault
PTE-র U/S বিটkernel-এর মেমরি user mode থেকে অস্পৃশ্যpage fault → সাধারণত SIGSEGV
PTE-র R/W/X বিটকোড বদলানো যায় না, ডেটা চালানো যায় না (অংশ ৭)page fault → SIGSEGV
Ring 3 থেকে ring 0-তে যাওয়ার একমাত্র দরজাsystem call, interrupt আর exception — kernel-এর নির্ধারিত প্রবেশপথযেখানে খুশি লাফ দেওয়া যায় না

তাই প্রতিটি system call একটি চেকপোস্ট: kernel সেখানে যাচাই করে প্রসেসটির পরিচয় (UID, group, capability) আর অনুমতি — এটিই authorization. পর্ব ৪৬-এ এর তত্ত্ব (domain, access matrix, ACL, capability), পর্ব ৪৭-এ Linux-এর বাস্তব রূপ (rwx, setuid, sudo). আর পর্ব ৪৯-এ দেখবেন কীভাবে seccomp আর SELinux এই চেকপোস্ট আরও কড়া করে।

একটি ব্যাংকের শাখা ভাবুন। গ্রাহকেরা (অ্যাপ) হলে বসে ফর্ম পূরণ করেন; ভল্টে (হার্ডওয়্যার) ঢোকার অধিকার শুধু কর্মকর্তাদের (kernel). গ্রাহক টাকা তুলতে চাইলে কাউন্টারে (system call) ফর্ম দেন, কর্মকর্তা সই আর ব্যালান্স মিলিয়ে (authorization) নিজে ভল্ট থেকে আনেন। দেয়াল আর তালা (ring, page table) নিশ্চিত করে কেউ কাউন্টার এড়িয়ে ভল্টে যেতে পারেন না। কিন্তু কর্মকর্তা নিজেই যদি প্রতারিত হন — kernel-এ বাগ — তাহলে পুরো ব্যাংক ঝুঁকিতে।

Kernel-এর একটি বাগ = সব সুরক্ষার শেষ। সব নিয়ম জোর করে মানায় kernel; তার ভেতরে কোনো memory বাগ থাকলে ring 3-এর একটি প্রোগ্রাম সেটি দিয়ে ring 0-এর অধিকার পেতে পারে (privilege escalation). এই কারণে kernel ছোট রাখা (পর্ব ০৬-এর microkernel যুক্তি), kernel-এর নিজের সুরক্ষা (অংশ ৮), আর দ্রুত kernel patch এত গুরুত্বপূর্ণ।

Least privilege — যতটুকু দরকার, ঠিক ততটুকু

১৯৭৫ সালে Jerome Saltzer আর Michael Schroeder-এর বিখ্যাত নকশা-নীতির তালিকায় একটি নীতি: প্রতিটি প্রোগ্রাম আর মানুষ শুধু সেই অধিকার পাবে, যা তার কাজের জন্য অপরিহার্য — least privilege. বাস্তবে: দৈনন্দিন কাজ সাধারণ অ্যাকাউন্টে, admin অধিকার শুধু দরকারের মুহূর্তে (sudo, Windows-এর UAC); web server চালু হয়ে port 80 খোলার পর root ছেড়ে সাধারণ ব্যবহারকারী হয়ে যায়; ব্রাউজারের প্রতিটি tab আলাদা সীমিত প্রসেসে চলে। লক্ষ্য একটাই — কোনো অংশ ভাঙলে ক্ষতি যেন সেই অংশেই আটকে থাকে।

৬ · Memory-safety বাগ — buffer overflow, use-after-free আর integer overflow

C আর C++-এ লেখা কোড (প্রায় সব kernel, ব্রাউজারের ইঞ্জিন, অনেক system টুল) মেমরি সরাসরি নিয়ন্ত্রণ করে — দ্রুত, কিন্তু ভাষা নিজে সীমা পাহারা দেয় না। এমন ভুলকে বলে memory-safety বাগ, আর C মানদণ্ডে এগুলো undefined behavior. তিনটি প্রধান ধরন, শুধু ধারণা হিসেবে:

Buffer overflow

১৬ বাইটের একটি জায়গায় ৪০ বাইট লেখা — বাড়তি বাইটগুলো পাশের মেমরিতে গিয়ে পড়ে। Stack-এ পাশেই থাকে ফাংশনের ফেরার ঠিকানা (পর্ব ০৮), তাই এটি নিয়ন্ত্রণ-প্রবাহ বদলানোর ঝুঁকি তৈরি করে।

লাইব্রেরির তাক উপচে পাশের তাকে বই

Use-after-free

free() করা মেমরি পরে আবার ব্যবহার। ততক্ষণে allocator হয়তো জায়গাটি অন্য বস্তুকে দিয়েছে — পুরোনো pointer দিয়ে লেখা মানে অন্যের ডেটা বদলানো।

হোটেলের চাবি ফেরতের পরও রুমে ঢোকা

Integer overflow

আকারের হিসাব (যেমন সংখ্যা × আকার) নির্দিষ্ট বিটে না আঁটলে ঘুরে ছোট একটি সংখ্যা হয়; ফলে ছোট জায়গা বরাদ্দ হয়, আর পরের কপি সেটি উপচে ফেলে — buffer overflow-এর একটি উৎস।

মিটার ৯৯৯৯৯ থেকে ০০০০০-এ

নিরাপদ কোডের অভ্যাস প্রথম প্রতিরক্ষা — সীমা নিজে মাপা, আর সীমাহীন ফাংশনের বদলে সীমা-নেওয়া ফাংশন। নিচে একটি ভুল নমুনা আর তার সংশোধন (চালানোর জন্য নয়):

/* BUG: no length check; input longer than 15 chars overflows name[] */
void greet_bad(const char *input) {
    char name[16];
    strcpy(name, input);
    printf("hello %s\n", name);
}

/* FIX: the copy is bounded by the buffer size; long input is cut, not overflowed */
void greet_ok(const char *input) {
    char name[16];
    snprintf(name, sizeof name, "%s", input);
    printf("hello %s\n", name);
}

/* FIX for size arithmetic: check before multiplying (or use calloc, which checks) */
void *alloc_items(size_t count, size_t size) {
    if (size != 0 && count > SIZE_MAX / size) return NULL;   /* would wrap around */
    return malloc(count * size);
}

বাগ খুঁজতে development-এর সময় AddressSanitizer (-fsanitize=address), Valgrind আর fuzzing (এলোমেলো ইনপুট দিয়ে বারবার চালানো) ব্যবহার হয়; C-র নিরাপদ কোডিং নিয়ে বিস্তারিত আছে C কোর্সের undefined behavior ও secure coding পর্বে। কিন্তু কোটি লাইনের কোডে কিছু বাগ থেকেই যায় — তাই OS আর compiler মিলে আরেক স্তর পাহারা বসায়: বাগ থাকলেও তাকে কাজে লাগানো যেন কঠিন হয়, আর খারাপ কিছু ঘটার আগেই প্রোগ্রাম থেমে যায়।

৭ · স্তরে স্তরে প্রতিরক্ষা — NX, canary, ASLR, RELRO আর CFI

NX / DEP আর W^X — ডেটা কখনো কোড নয়

পর্ব ৩২-এর page table-এ প্রতিটি page-এর অনুমতি-বিট থাকে। আধুনিক x86-64-এ একটি বিশেষ বিট হলো NX (no-execute; Intel বলে XD) — AMD ২০০৩ সালে AMD64-এর সাথে আনে। এটি চালু থাকলে CPU সেই page থেকে নির্দেশ পড়তে অস্বীকার করে। OS নিয়ম করে stack, heap আর ডেটার page-এ NX বসায় — Windows-এ এর নাম DEP (data execution prevention, Windows XP SP2, ২০০৪)। মূল নীতির নাম W^X (write XOR execute, OpenBSD ২০০৩ সালে জনপ্রিয় করে): একটি page হয় লেখা যায়, নয় চালানো যায় — দুটি একসাথে নয়। ফলে কেউ ইনপুট দিয়ে মেমরিতে বাইট ঢোকাতে পারলেও সেগুলো নির্দেশ হিসেবে চলে না।

নিচের প্রোগ্রাম mmap দিয়ে একটি নতুন page নেয় — PROT_EXEC ছাড়া, শুধু পড়া-লেখা। /proc/self/maps থেকে অনুমতি দেখে, তারপর JIT compiler-এর মতো “লেখা শেষ, এবার শুধু পড়া আর চালানো” অবস্থায় mprotect দিয়ে বদলায়। কোনো কোড চালানো হয় না — শুধু অনুমতির স্ট্রিং ছাপা হয়:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
/* copy the perms of the /proc/self/maps line containing addr; count W+X lines */
static int perms_of(unsigned long addr, char out[8]) {
    char line[512], perms[8];  unsigned long lo, hi;  int wx = 0;
    FILE *f = fopen("/proc/self/maps", "r");
    strcpy(out, "?");
    if (!f) return -1;
    while (fgets(line, sizeof line, f)) {
        if (sscanf(line, "%lx-%lx %7s", &lo, &hi, perms) != 3) continue;
        if (strchr(perms, 'w') && strchr(perms, 'x')) wx++;
        if (addr >= lo && addr < hi) strcpy(out, perms);
    }
    fclose(f);
    return wx;
}
int main(void) {
    long pg = sysconf(_SC_PAGESIZE);
    char perm[8], *p = mmap(NULL, pg, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    int local = 0, wx;
    if (p == MAP_FAILED) { perror("mmap"); return 1; }
    strcpy(p, "config data");                        /* RW page: writing is allowed */
    perms_of((unsigned long)p, perm);      printf("new page (RW)      : %s\n", perm);
    if (mprotect(p, pg, PROT_READ | PROT_EXEC) != 0) { perror("mprotect"); return 1; }
    perms_of((unsigned long)p, perm);      printf("after mprotect R+X : %s\n", perm);
    perms_of((unsigned long)&local, perm); printf("stack              : %s\n", perm);
    wx = perms_of((unsigned long)&main, perm); printf("code of main()     : %s\n", perm);
    printf("W+X mappings in this process: %d\n", wx);
    printf("page size %ld, data still readable: \"%s\"\n", pg, p);
    munmap(p, pg);  return 0;
}

আউটপুট:

new page (RW)      : rw-p
after mprotect R+X : r-xp
stack              : rw-p
code of main()     : r-xp
W+X mappings in this process: 0
page size 4096, data still readable: "config data"

নতুন page-এর অনুমতি rw-p: পড়া (r) আর লেখা (w) চলে, x-এর ঘরে - মানে চালানো নিষেধ, শেষের p মানে private. mprotect-এর পর r-xp — লেখা বন্ধ, চালানো অনুমোদিত; কোনো মুহূর্তেই w আর x একসাথে নয়, এটিই W^X. Stack rw-p (NX চালু), আর প্রোগ্রামের নিজের কোড r-xp — চালানো যায়, বদলানো যায় না। পুরো প্রসেসে W+X mapping ০টি. মনে রাখুন, সাধারণ Linux kernel কেউ চাইলে একসাথে RWX অনুমতিও দেয়; SELinux-এর নিয়ম বা কিছু কড়া সিস্টেম তা অস্বীকার করে — W^X কতটা জোর করে মানানো হবে, তা OS-এর নীতির ব্যাপার (পর্ব ৪৯)। Windows-এ একই কাজের API VirtualProtect.

Stack canary — ফেরার আগে পাহারাদার পাখি

কয়লাখনিতে একসময় খাঁচায় ক্যানারি পাখি রাখা হতো; বিষাক্ত গ্যাসে পাখিটি আগে অসুস্থ হলে শ্রমিকেরা সতর্ক হতেন। Stack canary একই ধারণা: compiler প্রতিটি ঝুঁকিপূর্ণ ফাংশনের শুরুতে local buffer আর ফেরার ঠিকানার মাঝখানে একটি গোপন এলোমেলো মান বসায়, আর ফেরার ঠিক আগে মিলিয়ে দেখে। Buffer উপচে ফেরার ঠিকানার দিকে গেলে পথে canary-ও বদলায় — মিল না পেলে প্রোগ্রাম সঙ্গে সঙ্গে থেমে যায় (glibc-তে বার্তা *** stack smashing detected ***: terminated). ধারণাটি ১৯৯৮ সালের StackGuard গবেষণা থেকে; gcc-তে -fstack-protector (GCC 4.1 থেকে), আর বেশি ফাংশন ঢাকা -fstack-protector-strong (GCC 4.9 থেকে)। x86-64 Linux-এ glibc প্রতিটি প্রসেসের শুরুতে canary এলোমেলো করে thread-local জায়গায় রাখে। Windows-এর MSVC-তে সমতুল্য /GS.

ASLR আর PIE — ঠিকানা লুকিয়ে রাখা

ডেটা চালানো না গেলে আক্রমণকারী চাইতে পারে প্রোগ্রাম বা library-র আগে থেকে থাকা কোডের টুকরো জুড়ে কাজে লাগাতে — একে বলে code-reuse attack. তার জন্য জানতে হয় সেই কোড ঠিক কোন ঠিকানায়। পর্ব ০৮-এ দেখা ASLR প্রতিবার stack, heap, mmap এলাকা আর library-র ঠিকানা এলোমেলো করে; প্রোগ্রাম নিজে PIE হলে তার কোডের ঠিকানাও। ভুল ঠিকানায় লাফ দিলে প্রোগ্রাম crash করে — নিয়ন্ত্রণ নেওয়ার বদলে শুধু থেমে যাওয়া, আর বারবার crash log-এ ধরা পড়ে। Linux mainline-এ ASLR আসে ২০০৫ সালে (২.৬.১২), Windows-এ Vista (২০০৭) থেকে। সীমা: কোনো বাগ দিয়ে একটি ঠিকানাও ফাঁস হলে বাকিগুলোর অবস্থান অনুমান সহজ হয় — তাই ASLR একা নয়, অন্য স্তরের সাথে।

RELRO — লাফের টেবিল শুধু-পড়ার

Dynamic library-র ফাংশন ডাকা হয় GOT-এর ঠিকানা দেখে (C কোর্সের linker পর্বের বিষয়)। এই টেবিল লেখা যায় এমন থাকলে একটি memory বাগ দিয়ে তা বদলানো যেত। Partial RELRO কিছু অংশ শুধু-পড়ার করে; full RELRO (-Wl,-z,relro,-z,now) প্রোগ্রাম চালু হওয়ার সময়েই সব ঠিকানা মিলিয়ে (BIND_NOW) পুরো টেবিল শুধু-পড়ার করে দেয় — দাম শুধু একটু ধীর শুরু।

এবার নিজের চোখে দেখুন: একই ছোট প্রোগ্রাম দুইভাবে compile করে readelf দিয়ে ELF header পড়া — কোনো কিছু আক্রমণ করা হয় না, শুধু ফাইলের লেবেল পড়া:

cat > hello.c <<'EOF'
#include <stdio.h>
int main(int argc, char **argv) {
    char name[32];
    snprintf(name, sizeof name, "%s", argc > 1 ? argv[1] : "Dhaka");
    printf("hello, %s\n", name);
    return 0;
}
EOF
HARD="-O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIE -pie -Wl,-z,relro,-z,now"
WEAK="-O2 -fno-stack-protector -U_FORTIFY_SOURCE -no-pie -Wl,-z,norelro,-z,lazy"
gcc $HARD -o hard hello.c && gcc $WEAK -o weak hello.c || exit 1
check() {   # only reads ELF headers; nothing is attacked
  echo "== $1"
  readelf -h "$1" | grep 'Type:'
  readelf -lW "$1" | awk '$1=="GNU_STACK" || $1=="GNU_RELRO" {print "  " $1 " flags=" $(NF-1)}'
  readelf -d "$1" | grep -q BIND_NOW && echo "  BIND_NOW: yes" || echo "  BIND_NOW: no"
  readelf --dyn-syms -W "$1" | grep -q __stack_chk_fail && echo "  canary: yes" || echo "  canary: no"
  readelf --dyn-syms -W "$1" | grep -q __printf_chk && echo "  fortify: yes" || echo "  fortify: no"
}
check hard
check weak
./hard
./weak Sylhet

আউটপুট:

== hard
  Type:                              DYN (Position-Independent Executable file)
  GNU_STACK flags=RW
  GNU_RELRO flags=R
  BIND_NOW: yes
  canary: yes
  fortify: yes
== weak
  Type:                              EXEC (Executable file)
  GNU_STACK flags=RW
  BIND_NOW: no
  canary: no
  fortify: no
hello, Dhaka
hello, Sylhet

hard: Type DYN — PIE, তাই ASLR প্রোগ্রামের কোডও সরায়; GNU_STACK RW — stack চালানো যায় না (NX); GNU_RELRO আর BIND_NOW একসাথে মানে full RELRO; __stack_chk_fail আমদানি মানে canary বসানো হয়েছে; __printf_chk মানে FORTIFY_SOURCE printf-কে যাচাইসহ রূপে বদলেছে। weak: Type EXEC — কোডের ঠিকানা প্রতিবার একই; RELRO, BIND_NOW, canary কিছুই নেই। লক্ষ করুন, weak-এও GNU_STACK RW — আধুনিক toolchain-এ NX ডিফল্ট, বন্ধ করতে আলাদা করে চাইতে হয় (অনুশীলন ৩)। Distro-র gcc এর অনেকগুলো ডিফল্টভাবেই চালু রাখে, তবু নিজের build যাচাই করাই নিয়ম। Windows-এ সমতুল্য লেবেল PE header-এর DYNAMIC_BASE (ASLR), NX_COMPAT (DEP) আর GUARD_CF (CFG), যা dumpbin /headers দিয়ে দেখা যায়।

CFI আর shadow stack — লাফ দেওয়ার অনুমোদিত পথ

শেষ স্তরের প্রশ্ন: কোনো বাগ যদি তবুও ফেরার ঠিকানা বা একটি ফাংশন-pointer বদলায়? Control-flow integrity নিয়ম করে, প্রোগ্রাম শুধু তার বৈধ পথেই লাফ দিতে পারবে। দুই দিক: ফেরা (return) — হার্ডওয়্যারের shadow stack প্রতিটি call-এ ফেরার ঠিকানার একটি আলাদা, সাধারণ লেখার অযোগ্য কপি রাখে, আর ret-এর সময় দুটি না মিললে CPU exception তোলে। আর পরোক্ষ লাফ (function pointer) — শুধু চিহ্নিত বৈধ ফাংশন-শুরুতেই যাওয়া যায়। Intel CET (Control-flow Enforcement Technology) দুটিই দেয়, নতুন প্রজন্মের Intel ও AMD প্রসেসরে আছে বলে জানা যায়; Linux-এ user-space shadow stack-এর সমর্থন kernel ৬.৬ (২০২৩) নাগাদ যুক্ত হয়েছে, আর Windows-এ “hardware-enforced stack protection” নামে আছে — CPU, OS আর প্রোগ্রাম তিনটিকেই সমর্থন করতে হয়। সফটওয়্যার-রূপ: Windows-এর Control Flow Guard, clang-এর CFI; ARM-এ pointer authentication আর BTI একই লক্ষ্যে।

  1. বাগstrcpyসীমা নেই
  2. NX / DEPrw-pডেটা চলে না
  3. ASLR + PIErandom baseঠিকানা অজানা
  4. Canarycheck on returnউপচে পড়া ধরা
  5. CFI / shadow stackret == copy?বৈধ পথ
  6. মূল সমাধানfix + patchবাগই না থাকা
Stack frame (ওপরে উঁচু ঠিকানা) আর ফল
return address
saved frame pointer
canary
name[16]
এই স্তরের ফল
  1. বাগ: একটি ফাংশন সীমা না মেপে ইনপুট ১৬ বাইটের name-এ কপি করে। ১৬ বাইটের বেশি ইনপুট এলে বাড়তি বাইট ওপরের দিকে — canary, saved frame pointer আর ফেরার ঠিকানার দিকে — গিয়ে পড়তে পারে। এখনো কোনো প্রতিরক্ষা সক্রিয় হয়নি।
  2. প্রথম স্তর NX/DEP: stack-এর page rw-p — লেখা যায়, চালানো যায় না। তাই কেউ ইনপুটের ভেতরে নির্দেশের বাইট রাখলেও CPU সেগুলো চালাতে অস্বীকার করে; চেষ্টা মানেই page fault আর প্রসেস বন্ধ।
  3. দ্বিতীয় স্তর ASLR + PIE: আগে থেকে থাকা কোড ব্যবহার করতে চাইলে তার ঠিকানা লাগে — কিন্তু প্রতিবার চালালে ঠিকানা আলাদা। ভুল ঠিকানায় লাফ মানে crash, নিয়ন্ত্রণ নয়।
  4. তৃতীয় স্তর canary: ফেরার ঠিকানার দিকে উপচে পড়া বাইট পথে canary বদলে দেয়। ফেরার ঠিক আগে compiler-এর বসানো যাচাই মিল পায় না — প্রোগ্রাম সঙ্গে সঙ্গে থামে, বদলানো ঠিকানায় কখনো ফেরে না।
  5. চতুর্থ স্তর CFI/shadow stack: যদি কোনোভাবে canary অক্ষত রেখে ফেরার ঠিকানা বদলায়, ret-এর সময় হার্ডওয়্যারের আলাদা কপির সাথে মিলবে না — CPU control-protection exception তোলে। পরোক্ষ লাফও শুধু বৈধ লক্ষ্যে।
  6. মূল সমাধান: প্রতিটি স্তর “নিয়ন্ত্রণ দখল”-কে “crash”-এ নামিয়ে আনে — কিন্তু crash নিজেও সেবা বন্ধ (availability-র ক্ষতি)। আসল সমাধান বাগটি সারানো (snprintf দিয়ে সীমা), দ্রুত patch, আর নতুন কোডে memory-safe ভাষা (অংশ ৮)।
সুরক্ষাকে দেয়কী কঠিন করেLinux-এ যাচাই
NX / DEP (W^X)CPU + OS + linkerইনপুটের বাইট নির্দেশ হিসেবে চালানোreadelf -lW: GNU_STACK RW; /proc/PID/maps-এ rwx নেই
Stack canarycompiler + libcএকটানা উপচে ফেরার ঠিকানা বদলানো__stack_chk_fail symbol
ASLR + PIEkernel + compilerকোড আর ডেটার ঠিকানা আগে জানাrandomize_va_space = 2; Type DYN
Full RELROlinker + dynamic linkerGOT বদলানোGNU_RELRO + BIND_NOW
FORTIFY_SOURCEcompiler + glibcজানা আকারের buffer-এ কিছু ভুল কপি__*_chk symbol
CFI / shadow stackCPU + compiler + OSফেরার ঠিকানা আর ফাংশন-pointer বদলে লাফCPU flag (shstk, ibt) আর binary-র CET চিহ্ন

৮ · Kernel-এর নিজের পাহারা — KASLR, SMEP/SMAP, KPTI, Spectre আর memory-safe ভাষা

অ্যাপের জন্য যেমন, kernel-এর জন্যও একই ধরনের স্তর — কারণ kernel-এর একটি বাগই সবচেয়ে দামি।

  • KASLR: বুটের সময় kernel-এর কোড আর ডেটার ঠিকানা এলোমেলো করা। Linux-এ ৩.১৪ (২০১৪)-এ যোগ হয়, পরে x86-এ ডিফল্ট চালু হয়। সাথে সাধারণ ব্যবহারকারী থেকে kernel-এর ঠিকানা লুকানো (kptr_restrict), যাতে ঠিকানা ফাঁস না হয়।
  • SMEP (supervisor mode execution prevention) আর SMAP (… access prevention): Intel ২০১২ ও ২০১৪-এর দিকের প্রসেসরে আনে (AMD-ও পরে)। SMEP থাকলে kernel mode-এ থাকা CPU user মেমরির কোড চালাবে না; SMAP থাকলে kernel ইচ্ছাকৃতভাবে অনুমতি না খুললে user মেমরি পড়বেও না — kernel শুধু copy_from_user()-এর মতো নির্দিষ্ট পথে সাময়িক অনুমতি খোলে। ফলে kernel-কে ভুল করে user-এর ফাঁদে টেনে আনার একটি বড় শ্রেণির কৌশল অকেজো। ARM-এ সমতুল্য PXN আর PAN.
  • Signed module আর lockdown: শুধু স্বাক্ষরিত kernel module লোড — পর্ব ০৭-এর Secure Boot-এর শিকলের পরের কড়া।

Meltdown, KPTI আর Spectre — যখন হার্ডওয়্যার নিজেই ফাঁক রাখে

২০১৮ সালের জানুয়ারিতে প্রকাশিত দুটি গবেষণা দেখাল, অংশ ৫-এর হার্ডওয়্যারের দেয়াল নিখুঁত নয়। আধুনিক CPU গতি বাড়াতে ফল জানার আগেই সামনের নির্দেশ অনুমানে চালিয়ে রাখে (speculative execution), অনুমান ভুল হলে ফল ফেলে দেয়। কিন্তু ফেলে দেওয়া কাজের ছাপ cache-এ থেকে যায়, আর সময় মেপে সেই ছাপ পড়া যায় — একে বলে side channel.

  • Meltdown: আক্রান্ত প্রসেসরে (প্রধানত তখনকার অনেক Intel মডেল) user mode-এর প্রোগ্রাম অনুমানের ফাঁকে kernel-এর মেমরির ছাপ পেতে পারত, যদিও U/S বিট তা নিষেধ করে। প্রতিকার KPTI (Linux ৪.১৫; Windows-এ KVA Shadow): user mode-এ চলার সময় kernel-এর প্রায় সব মেমরি page table থেকেই সরিয়ে রাখা — যা ম্যাপই নেই, তা অনুমানেও ছোঁয়া যায় না। দাম: প্রতিটি system call আর interrupt-এ page table বদল, তাই syscall-ভারী কাজে লক্ষণীয় ধীরতা (পর্ব ০৯-এ PCID দিয়ে খরচ কমানোর কথা আছে)। নতুন প্রসেসর হার্ডওয়্যারেই এটি সারিয়েছে, সেখানে KPTI লাগে না।
  • Spectre: আরও বিস্তৃত পরিবার — Intel, AMD, ARM-এর বহু প্রসেসরে। একটি প্রোগ্রাম নিজের বা অন্যের অনুমানের পথকে প্রভাবিত করে গোপন তথ্যের ছাপ cache-এ ফেলাতে পারে। একক কোনো সমাধান নেই; প্রতিকার স্তরে স্তরে: CPU microcode আপডেট, compiler-এর retpoline আর বিশেষ বাধা-নির্দেশ, kernel-এ সংবেদনশীল সীমা-যাচাইয়ের পরে অনুমান থামানো, ব্রাউজারে সূক্ষ্ম timer সরানো আর প্রতিটি সাইট আলাদা প্রসেসে।

নিজের মেশিনে এগুলো দেখার সবচেয়ে সহজ পথ — Linux kernel নিজেই /sys/devices/system/cpu/vulnerabilities/-এ প্রতিটি পরিচিত CPU-ত্রুটির জন্য “আক্রান্ত নয়”, “প্রতিকার চালু” বা “ঝুঁকিতে” লিখে রাখে। নিচের স্ক্রিপ্ট user-space ASLR আর kernel-এর দিক — দুটিই শুধু পড়ে দেখে:

echo "ASLR: randomize_va_space = $(cat /proc/sys/kernel/randomize_va_space)  (0 off, 1 partial, 2 full)"
for run in 1 2 3; do   # every grep is a NEW process, so /proc/self = that grep
  grep -E '\[(heap|stack)\]' /proc/self/maps |
    awk -v r="$run" '{split($1, a, "-"); printf "run %s  %-8s starts at %s\n", r, $6, a[1]}'
done
echo "--- kernel side (read-only checks, no root) ---"
echo "kptr_restrict = $(cat /proc/sys/kernel/kptr_restrict 2>/dev/null || echo hidden)"
echo "first /proc/kallsyms line for uid $(id -u): $(head -n 1 /proc/kallsyms 2>/dev/null || echo hidden)"
d=/sys/devices/system/cpu/vulnerabilities
for f in meltdown spectre_v1 spectre_v2; do
  printf '%-11s %s\n' "$f:" "$(cat "$d/$f" 2>/dev/null || echo 'not visible here')"
done

একটি আসল রানের আউটপুট (ঠিকানা প্রতিবার আলাদা হবে):

ASLR: randomize_va_space = 2  (0 off, 1 partial, 2 full)
run 1  [heap]   starts at 644353d71000
run 1  [stack]  starts at 7ffddc01d000
run 2  [heap]   starts at 6091d860c000
run 2  [stack]  starts at 7ffda49bb000
run 3  [heap]   starts at 603816884000
run 3  [stack]  starts at 7ffc799b7000
--- kernel side (read-only checks, no root) ---
kptr_restrict = 1
first /proc/kallsyms line for uid 999: 0000000000000000 A fixed_percpu_data
meltdown:   Not affected
spectre_v1: Mitigation: usercopy/swapgs barriers and __user pointer sanitization
spectre_v2: Mitigation: Retpolines; IBPB: conditional; STIBP: always-on; RSB filling; PBRSB-eIBRS: Not affected; BHI: Not affected

2 মানে পূর্ণ ASLR. তিনবার একই grep চালানো হলো, কিন্তু প্রতিবার নতুন প্রসেস — heap শুরু হলো 6443…, 6091…, 6038…-এ, stack 7ffddc…, 7ffda4…, 7ffc79…-এ; কোনো দুবার এক নয়। Kernel-এর দিকে kptr_restrict = 1: বিশেষ অধিকার (CAP_SYSLOG) ছাড়া কেউ kernel-এর ঠিকানা দেখবে না — তাই /proc/kallsyms-এ symbol-এর নাম আছে, ঠিকানার জায়গায় শুধু শূন্য। এভাবে KASLR-এর গোপনীয়তা রক্ষা হয়। uid 999 হলো এই runner-এর সাধারণ ব্যবহারকারী। CPU-ত্রুটির তালিকা: meltdown: Not affected — এই CPU হার্ডওয়্যারেই সুরক্ষিত, তাই KPTI লাগে না; spectre_v1-এর জন্য kernel-এর সফটওয়্যার বাধা আর user pointer যাচাই; spectre_v2-এর জন্য retpoline (compiler), IBPB ও STIBP (microcode-এর নির্দেশ) আর RSB filling — এগুলো host মেশিনের kernel আর CPU-র অবস্থা, কারণ container host-এর kernel ভাগ করে (পর্ব ৫১)। নিজের মেশিনে grep . /sys/devices/system/cpu/vulnerabilities/* পুরো তালিকা দেখায়।

শিকড় থেকে সমাধান — memory-safe ভাষা

এত স্তরের পরও কেন নতুন দুর্বলতা আসে? কারণ বাগের শ্রেণিটি থেকেই যায়। Microsoft-এর নিরাপত্তা-প্রকৌশলীরা ২০১৯ সালে জানান, বহু বছর ধরে তাঁদের পণ্যে প্রতি বছর যে CVE দেওয়া হয়, তার প্রায় ৭০% memory-safety সমস্যা; Google-এর Chromium দলও ২০২০ সালে গুরুতর নিরাপত্তা-বাগের মোটামুটি একই অনুপাতের কথা বলে। (এগুলো তাঁদের নিজেদের কোডভিত্তির হিসাব, সব সফটওয়্যারের সাধারণ সূত্র নয়।) সমাধানের পথ: নতুন কোড এমন ভাষায় লেখা, যেখানে compiler নিজেই এই ভুলগুলো আটকায় — Rust, Go, Swift, Java, C#. Linux kernel-এ Rust-এ driver লেখার প্রাথমিক সমর্থন ঢোকে ৬.১ সংস্করণে (২০২২-এর ডিসেম্বর), এখনো সীমিত পরিসরে বেড়ে চলেছে; Windows-এর kernel-এ আর Android-এ Rust-এর ব্যবহার বাড়ছে, আর Google জানিয়েছে Android-এ নতুন কোড memory-safe ভাষায় লেখার পর memory-safety দুর্বলতার অনুপাত কয়েক বছরে উল্লেখযোগ্যভাবে কমেছে।

আরও গভীরে: হার্ডওয়্যারও memory-safety-তে নামছে। ARM-এর MTE (memory tagging extension) প্রতিটি ১৬-বাইট মেমরি-খণ্ড আর pointer-এ একটি ছোট tag বসায়; না মিললে CPU ধরে ফেলে — use-after-free আর সীমা-লঙ্ঘন ধরার জন্য, আর কিছু নতুন Android ফোনে এটি চালু করার বিকল্প আছে বলে জানা যায়। Cambridge-এর CHERI গবেষণা pointer-কে “capability”-তে বদলায়, যার ভেতরে সীমা আর অনুমতি লেখা থাকে (পর্ব ৪৬-এর capability ধারণার হার্ডওয়্যার রূপ). Linux-এ কোন CPU কোন সুরক্ষা দেয়, তা /proc/cpuinfo-এর flags-এ (nx, smep, smap, shstk, ibt) দেখা যায়।

৯ · প্রতিদিনের নিরাপত্তা — patch, log, antivirus/EDR আর বাংলাদেশের প্রেক্ষাপট

Patch আর update — সবচেয়ে কার্যকর একক কাজ

একটি দুর্বলতা প্রকাশিত হলে, আর তার patch আসার পর, সময়টা আক্রমণকারী আর প্রতিরক্ষাকারীর দৌড় — patch নিজেই বলে দেয় কোথায় সমস্যা ছিল। যে দুর্বলতার patch এখনো নেই, তাকে বলে zero-day; কিন্তু বাস্তবের বেশিরভাগ ক্ষতি হয় জানা, patch-থাকা দুর্বলতায়, যা কেউ ইনস্টল করেননি। অভ্যাস: OS-এর স্বয়ংক্রিয় নিরাপত্তা-আপডেট চালু রাখা (Ubuntu-তে unattended-upgrades, Windows Update, macOS Software Update), kernel আপডেটের পর reboot (বা live patching), আর যে OS বা ফোনের নিরাপত্তা-আপডেট বন্ধ হয়ে গেছে, সেটি সংবেদনশীল কাজে ব্যবহার না করা।

Logging আর auditing — কে কখন কী করল

  • Linux: systemd-এর journalctl আর /var/log/auth.log (বা secure)-এ লগইন ও sudo-র রেকর্ড; আরও সূক্ষ্ম নজরের জন্য kernel-এর audit subsystem আর তার daemon auditd — নির্দিষ্ট ফাইল বা system call-এ নিয়ম বসিয়ে প্রতিটি ঘটনা লেখা।
  • Windows: Event Log-এর Security log-এ সফল লগইন (event ID 4624) আর ব্যর্থ লগইন (4625)-এর মতো ঘটনা; Event Viewer দিয়ে দেখা যায়।
  • নিয়ম: log অন্য একটি মেশিনে পাঠানো, যাতে আক্রমণকারী মুছতে না পারে; আর কেউ সত্যিই log দেখেন — সতর্কবার্তা ছাড়া log শুধু ময়নাতদন্তে কাজে লাগে।
# watch writes and attribute changes to /etc/shadow, tag them "shadow-watch"
$ sudo auditctl -w /etc/shadow -p wa -k shadow-watch
$ sudo passwd rahima            # a legitimate change, just to create an event
$ sudo ausearch -k shadow-watch -i | tail -n 3
type=SYSCALL ... syscall=openat success=yes ... comm=passwd exe=/usr/bin/passwd auid=karim uid=root ...
type=PATH ... name=/etc/shadow ...
# auid = the person who originally logged in (karim), even after sudo

Antivirus আর EDR

প্রথাগত antivirus পরিচিত malware-এর “চিহ্ন” (signature) মিলিয়ে ধরে — জানা হুমকিতে ভালো, নতুনটিতে দুর্বল। আধুনিক EDR (endpoint detection and response) প্রসেসের আচরণ দেখে: Word থেকে হঠাৎ একটি shell চালু হওয়া, কয়েক মিনিটে হাজারো ফাইল এনক্রিপ্ট হওয়া — আর প্রতিষ্ঠানের নিরাপত্তা-দলকে জানায় বা মেশিনটি network থেকে আলাদা করে। Windows-এ Microsoft Defender ডিফল্টভাবেই থাকে। মনে রাখুন, এরা শেষ স্তর — patch, least privilege আর backup-এর বিকল্প নয়।

বাংলাদেশের প্রেক্ষাপট — মোবাইল ব্যাংকিং আর OTP

বাংলাদেশে বিপুল মানুষ bKash, Nagad, Rocket-এর মতো মোবাইল আর্থিক সেবা আর ব্যাংকের অ্যাপ ব্যবহার করেন। এই পর্বের নীতিগুলো সেখানে সরাসরি খাটে:

১০ · AI-এর যুগে OS নিরাপত্তা — সাহায্য নিন, অন্ধভাবে নয়

নিরাপত্তার প্রশ্নে AI-এর ভুল উত্তর সরাসরি দুর্বলতা তৈরি করে। বারবার দেখা ভুলগুলো:

AI-এর ভুলকেন বিপজ্জনককীভাবে যাচাই করবেন
“Permission error? chmod 777 বা sudo দিয়ে চালান”সবাইকে লেখার অধিকার, বা পুরো প্রোগ্রাম root হিসেবে — least privilege-এর উল্টোঠিক কোন ফাইলে কার কী অধিকার দরকার, পর্ব ৪৭-এর নিয়মে নিজে ঠিক করুন
পাসওয়ার্ড রাখতে MD5/SHA-256, salt ছাড়াদ্রুত hash অফলাইন অনুমানে দুর্বলArgon2id/bcrypt/scrypt; OWASP-এর Password Storage নির্দেশিকা দেখুন
“Build কাজ করছে না, -fno-stack-protector বা -z execstack দিন”সমস্যা লুকাতে সুরক্ষা বন্ধআসল কারণ খুঁজুন; build-এর পর readelf দিয়ে সুরক্ষা আছে কি না দেখুন
“KPTI/mitigation বন্ধ করলে গতি বাড়বে” — mitigations=offপ্রমাণিত CPU-ত্রুটির প্রতিকার সরে যায়/sys/.../vulnerabilities দেখুন; নিজের workload-এ মেপে, ঝুঁকি বুঝে সিদ্ধান্ত
পুরোনো বা ভুল OS-এর তথ্য (Windows প্রশ্নে Linux কমান্ড, পুরোনো kernel-এর সংখ্যা)সুরক্ষার নাম ও ডিফল্ট সংস্করণভেদে বদলায়OS, distro আর version উল্লেখ করে প্রশ্ন; man page আর kernel-এর ডকুমেন্টেশন

নিরাপত্তা-প্রশ্নে প্রসঙ্গ দিন, আর প্রতিরক্ষামূলক উত্তর ও যাচাইয়ের উপায় চান:

আমি একটি ছোট অফিসের Ubuntu 24.04 LTS সার্ভারের নিরাপত্তা-অবস্থা যাচাই আর শক্ত করতে চাই (SSH দিয়ে ব্যবহার হয়, একটি PHP ওয়েব অ্যাপ চলে)। ১. পাসওয়ার্ড-লগইন বনাম SSH key আর MFA — কোনটি কেন, আর PAM-এ কী বদলাতে হবে তা ধাপে ধাপে বলো; প্রতিটি পরিবর্তনের আগে কীভাবে নিজেকে বাইরে আটকে ফেলা এড়াব, তা-ও বলো। ২. ASLR, NX, KPTI ও Spectre-প্রতিকার চালু আছে কি না যাচাইয়ের কমান্ড দাও — শুধু পড়ার কমান্ড, root লাগলে আলাদা করে চিহ্নিত করো। ৩. চলমান binary-গুলো PIE, full RELRO আর stack protector দিয়ে বানানো কি না দেখার উপায় বলো। ৪. কোনো সুরক্ষা বন্ধ করার পরামর্শ দেবে না; কোথাও অনুমান করলে বা version-ভেদে আলাদা হলে স্পষ্ট বলো, আর প্রতিটি দাবির জন্য অফিসিয়াল ডকুমেন্টেশনের নাম দাও।

AI-এর উত্তর মানার আগে — চেকলিস্ট

পরীক্ষা ও ইন্টারভিউতে এই বিষয়ে প্রায়ই যা জিজ্ঞেস করা হয়:

  • Authentication আর authorization-এর পার্থক্য? — প্রথমটি “আপনি কে” প্রমাণ, দ্বিতীয়টি “আপনি কী করতে পারেন” তার সিদ্ধান্ত।
  • পাসওয়ার্ডে salt কেন, আর SHA-256 কেন যথেষ্ট নয়? — salt একই পাসওয়ার্ডকে আলাদা hash দেয় আর আগে-বানানো টেবিল অকেজো করে; SHA-256 দ্রুত, তাই অফলাইন অনুমান সস্তা — দরকার Argon2/bcrypt/scrypt.
  • Virus, worm আর Trojan-এর পার্থক্য? — virus অন্য ফাইলে জুড়ে মানুষের কাজে ছড়ায়, worm নিজে network দিয়ে ছড়ায়, Trojan ছদ্মবেশে আসে।
  • NX, ASLR আর stack canary — কোনটি কী থামায়? — NX ডেটাকে কোড হিসেবে চালানো, ASLR ঠিকানা আগে জানা, canary একটানা উপচে ফেরার ঠিকানা বদলানো।
  • KPTI কী আর কেন এসেছিল? — Meltdown (২০১৮)-এর প্রতিকার: user mode-এ kernel-এর মেমরি page table থেকেই সরানো; দাম syscall-এর বাড়তি খরচ।

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

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

প্র ০১১৯৮৮ সালের Morris worm কয়েক ঘণ্টায় তখনকার Internet-এর একটি বড় অংশ অচল করেছিল। আজকের OS নিরাপত্তার কোন কোন অভ্যাস সেই ঘটনা থেকে এসেছে?

১৯৮৮ সালের ২ নভেম্বর Cornell-এর স্নাতকোত্তর ছাত্র Robert Tappan Morris একটি স্ব-প্রতিলিপি প্রোগ্রাম ছাড়েন — ইতিহাসের প্রথম দিকের বহুল-আলোচিত worm. এটি ছড়াতে কয়েকটি ভিন্ন দুর্বলতা একসাথে ব্যবহার করত: fingerd সেবার একটি buffer overflow, sendmail-এর একটি debug সুবিধা যা খোলা রাখা ছিল, আর দুর্বল পাসওয়ার্ড অনুমান। প্রোগ্রামে একটি ভুলের কারণে এটি একই মেশিনে বারবার বসে যেত, ফলে হাজারো Unix মেশিন — সে সময়ের Internet-এ যুক্ত কম্পিউটারের উল্লেখযোগ্য অংশ — ধীর হয়ে অচল হয়ে পড়ে।

এই পর্বের ভাষায় ঘটনাটি পড়ুন। প্রথম দরজা ছিল একটি memory-safety বাগ — সীমা না মেপে stack-এ ইনপুট কপি। তখন NX, canary বা ASLR কিছুই ছিল না; এই পর্বের অংশ ৭-এর প্রতিটি স্তর মূলত পরের দুই দশকে এই শ্রেণির বাগের বিরুদ্ধে যোগ হয়েছে। দ্বিতীয় দরজা ছিল অপ্রয়োজনীয় সুবিধা খোলা রাখা — attack surface. তৃতীয়টি দুর্বল পাসওয়ার্ড — অংশ ৩ ও ৪-এর বিষয়। আর একটি গভীর শিক্ষা ছিল monoculture: প্রায় সব মেশিন একই সফটওয়্যার চালাত, তাই একটি বাগ সবখানে খাটত।

প্রতিষ্ঠানের দিক থেকেও পরিবর্তন আসে। ঘটনার পর যুক্তরাষ্ট্রের সরকারি অর্থায়নে Carnegie Mellon-এ CERT Coordination Center গঠিত হয় — দুর্বলতার খবর সমন্বয় করা আর patch ছড়ানোর একটি কেন্দ্র। আজ প্রায় প্রতিটি দেশে এমন জাতীয় CERT বা CIRT আছে। “দুর্বলতা জানানো → patch → সবাইকে আপডেট করতে বলা” — এই চক্রের শুরু অনেকাংশে এখান থেকে।

মূল উপলব্ধি: একটি বাস্তব আক্রমণ প্রায় কখনো একটি দুর্বলতায় দাঁড়িয়ে থাকে না; তাই প্রতিরক্ষাও একাধিক স্তরে — নিরাপদ কোড, ছোট attack surface, শক্ত authentication, আর দ্রুত patch-এর একটি সমন্বিত ব্যবস্থা।

প্র ০২পাসওয়ার্ড hash-কে “ইচ্ছে করে ধীর” করার ধারণা ১৯৭৯ থেকে ২০১৫ পর্যন্ত কীভাবে বদলেছে? Argon2 কেন CPU-র সময়ের সাথে মেমরিও খায়?

১৯৭৯ সালে Morris আর Thompson-এর crypt DES অ্যালগরিদম ২৫ বার চালাত — তখনকার মেশিনে প্রতিটি অনুমানে উল্লেখযোগ্য সময়। কিন্তু হার্ডওয়্যার দ্রুত হয়েছে, আর নির্দিষ্ট cost-এর অ্যালগরিদম সময়ের সাথে দুর্বল হয়ে যায়। ১৯৯৯ সালে Niels Provos আর David Mazières bcrypt প্রস্তাব করেন, যার মূল উদ্ভাবন একটি cost সংখ্যা: প্রতি ১ বাড়ালে কাজ দ্বিগুণ। ফলে হার্ডওয়্যার দ্রুত হলে অ্যালগরিদম না বদলে শুধু cost বাড়ানো যায়, আর নতুন লগইনে নতুন cost-এ hash আবার বানানো যায়।

পরের সমস্যা এল বিশেষ হার্ডওয়্যার থেকে। GPU-তে হাজারো ছোট core, আর বিশেষ চিপে (ASIC) আরও বেশি — শুধু হিসাব-ভারী hash এদের ওপর সস্তায় সমান্তরালে চলে। ২০০৯ সালে Colin Percival-এর scrypt একটি নতুন ধারণা আনে: হিসাবের জন্য অনেক মেমরি লাগবে। সার্ভারের কাছে একটি লগইনে কয়েক মেগাবাইট মেমরি তুচ্ছ, কিন্তু একটি GPU-তে হাজারো অনুমান একসাথে চালাতে হলে প্রতিটির জন্য সেই মেমরি লাগে — আর দ্রুত মেমরি চিপে সবচেয়ে দামি সম্পদ। একে বলে memory-hard.

২০১৩–২০১৫ সালে উন্মুক্ত Password Hashing Competition-এ বিশ্বের গবেষকেরা নকশা জমা দেন; বিজয়ী Argon2 (লুক্সেমবার্গ বিশ্ববিদ্যালয়ের Alex Biryukov, Daniel Dinu ও Dmitry Khovratovich). এতে তিনটি আলাদা মান — মেমরি, পুনরাবৃত্তি আর সমান্তরালতা — যাতে প্রতিটি সার্ভার নিজের হার্ডওয়্যার অনুযায়ী সাজাতে পারে; Argon2id রূপটি পরে RFC 9106 (২০২১)-এ মান হয়। OWASP-এর বর্তমান নির্দেশিকা প্রথম পছন্দ হিসেবে Argon2id-এর কথা বলে, আর বিকল্প হিসেবে scrypt ও bcrypt.

দুটি সূক্ষ্মতা মনে রাখুন। প্রথমত, ধীর hash অনলাইন আক্রমণের সমাধান নয় — সেখানে rate limit আর MFA. দ্বিতীয়ত, cost এত বাড়ানো যায় না যে লগইনের ভিড়ে সার্ভারই বসে যায়; এটি নিরাপত্তা আর availability-র আপস।

মূল উপলব্ধি: পাসওয়ার্ড hash-এর লক্ষ্য বৈধ ব্যবহারকারী আর আক্রমণকারীর খরচের অসমতা বাড়ানো — আর যে সম্পদ আক্রমণকারীর কাছে সবচেয়ে দামি (সময়, তারপর মেমরি), নকশা সেটিকেই কাজে লাগায়।

প্র ০৩Meltdown আর Spectre দেখাল, সফটওয়্যার নির্ভুল হলেও হার্ডওয়্যার তথ্য ফাঁস করতে পারে। এটি OS নকশার কোন মৌলিক অনুমানকে নাড়িয়ে দিল, আর প্রতিকারের দাম কে দিল?

দশকের পর দশক OS নকশা একটি অনুমানে দাঁড়িয়ে ছিল: হার্ডওয়্যার যা নিষেধ করে, তা ঘটে না। Page table-এ U/S বিট বলছে kernel-এর মেমরি user mode ছোঁবে না — ব্যস, kernel নিশ্চিন্তে নিজের মেমরি প্রতিটি প্রসেসের address space-এ ম্যাপ করে রাখত, কারণ এতে system call দ্রুত হয়। ২০১৭ সালে কয়েকটি স্বাধীন দল — Google Project Zero-র Jann Horn, অস্ট্রিয়ার Graz University of Technology-সহ কয়েকটি বিশ্ববিদ্যালয়ের গবেষকেরা — প্রায় একই সময়ে আবিষ্কার করেন, অনুমানে চালানো নির্দেশ সেই নিষেধের আগেই কাজ করে ফেলে, আর ফেলে দেওয়া কাজের ছাপ cache-এর সময় মেপে পড়া যায়। ২০১৮ সালের জানুয়ারির শুরুতে বিষয়টি প্রকাশ্যে আসে।

এর অর্থ গভীর। নিরাপত্তার সীমা এতদিন ছিল স্থাপত্যের (architectural) — নির্দেশ-সেট যা প্রতিশ্রুতি দেয়। কিন্তু CPU-র ভেতরের বাস্তবায়ন (microarchitecture) — cache, branch predictor, অনুমান — সেই প্রতিশ্রুতির বাইরে পার্শ্বপ্রতিক্রিয়া রাখে। এটি কোনো একটি বাগ নয়, কয়েক দশকের গতি-কৌশলের একটি শ্রেণিগত ফল। তাই পরের বছরগুলোতে এই পরিবারের আরও অনেক রূপ প্রকাশিত হয়।

প্রতিকারের দাম দিয়েছে সবাই। OS-গুলোকে কয়েক সপ্তাহের মধ্যে বড় পরিবর্তন আনতে হয় — Linux-এ KPTI, Windows-এ KVA Shadow — যাতে প্রতিটি mode বদলে page table বদলায়; syscall-ভারী কাজ, যেমন database আর storage সার্ভার, লক্ষণীয় ধীরতা দেখে, বিশেষত পুরোনো প্রসেসরে যেখানে PCID নেই। Compiler-কে retpoline-এর মতো নতুন কৌশল শিখতে হয়, ব্রাউজারকে প্রতিটি সাইট আলাদা প্রসেসে নিতে হয়। আর CPU-নির্মাতারা পরের প্রজন্মে হার্ডওয়্যারেই কিছু রূপ সারায়।

মূল উপলব্ধি: নিরাপত্তার সীমা শুধু নির্দেশ-সেটের প্রতিশ্রুতিতে নয়, পুরো বাস্তবায়নে টানতে হয়; আর গতি ও নিরাপত্তার আপস কখনো কখনো বছর পরে হার্ডওয়্যারের গভীর থেকে বিল পাঠায়।

প্র ০৪বড় প্রতিষ্ঠানগুলো বলছে গুরুতর বাগের বড় অংশ memory-safety-র। তাহলে সব কোড Rust-এ নতুন করে লেখা হচ্ছে না কেন? আর Linux kernel-এ Rust আনার বিতর্কের মূল কথা কী?

অংশ ৮-এর সংখ্যাগুলো — Microsoft-এর ২০১৯ সালের আর Chromium-এর ২০২০ সালের প্রায় ৭০% — একটি জিনিস স্পষ্ট করে: NX, ASLR, canary, CFI বাগকে কাজে লাগানো কঠিন করেছে, কিন্তু বাগের উৎস বন্ধ করেনি। Rust-এর মতো ভাষা compile-এর সময়েই নিশ্চিত করে যে একটি মেমরির একজনই “মালিক”, ধার দেওয়া reference মালিকের চেয়ে বেশি দিন বাঁচে না, আর array-র সীমা যাচাই হয় — ফলে use-after-free, double free আর data race-এর বড় শ্রেণি সাধারণ কোডে লেখাই যায় না। আর এর জন্য garbage collector লাগে না, তাই kernel আর driver-এর মতো জায়গাতেও চলে।

তবু সব নতুন করে লেখা বাস্তবসম্মত নয়। Linux kernel-এর কয়েক কোটি লাইন, Windows আর ব্রাউজারের বিশাল কোডভিত্তি দশকের পরীক্ষায় পোড় খাওয়া; নতুন করে লিখলে নতুন বাগ আসে, আর খরচ বিশাল। তাই কৌশলটি ধাপে ধাপে: নতুন কোড memory-safe ভাষায়, পুরোনো কোড যেমন আছে। Google Android-এ ঠিক এটি করে প্রকাশ করেছে যে memory-safety দুর্বলতার অনুপাত কয়েক বছরে উল্লেখযোগ্যভাবে কমেছে — কারণ দুর্বলতা বেশি থাকে নতুন লেখা কোডে, পুরোনো কোডে সময়ের সাথে কমে আসে।

Linux-এ Rust ঢোকে ৬.১ সংস্করণে (২০২২-এর শেষে) প্রাথমিক কাঠামো হিসেবে; Linus Torvalds এটিকে পরীক্ষা হিসেবে গ্রহণ করেন (পরে, ২০২৫ সালের শেষ দিকে, “পরীক্ষা” তকমাটি তুলে নেওয়া হয় বলে জানা যায়)। বিতর্কের বিষয়গুলো প্রকৌশলের: দুই ভাষার সংযোগস্থলে (C-র API-র ওপর নিরাপদ Rust “binding”) কে দায়িত্ব নেবেন; C-র কোনো ইন্টারফেস বদলালে Rust অংশ কে ঠিক করবেন; রক্ষণাবেক্ষণকারীদের নতুন ভাষা শেখার বোঝা; আর কম্পাইলার-টুলচেইনের বাড়তি নির্ভরতা। কিছু রক্ষণাবেক্ষণকারীর সাথে প্রকাশ্য মতবিরোধও হয়েছে।

আর মনে রাখুন, Rust-এর unsafe অংশ আর হার্ডওয়্যার-স্তরের বাগ (Spectre) থেকে যায়; logic বাগ, ভুল অনুমতি বা দুর্বল পাসওয়ার্ড কোনো ভাষা সারায় না।

মূল উপলব্ধি: memory-safe ভাষা একটি পুরো বাগ-শ্রেণিকে উৎসেই বন্ধ করে — সবচেয়ে কার্যকর পথ হলো নতুন কোডে সেটি গ্রহণ আর পুরোনো কোডে স্তরে স্তরে সুরক্ষা বজায় রাখা।

প্র ০৫OTP থাকা সত্ত্বেও মানুষ কেন প্রতারিত হন? Social engineering-এর বিরুদ্ধে প্রযুক্তি কতদূর যেতে পারে, আর passkey ঠিক কোন জায়গায় আলাদা?

OTP-ভিত্তিক MFA পাসওয়ার্ড চুরির বিরুদ্ধে বিশাল উন্নতি — শুধু পাসওয়ার্ড দিয়ে আর ঢোকা যায় না। কিন্তু OTP একটি গোপন সংখ্যা, যা মানুষ পড়েন আর টাইপ করেন। যে সংখ্যা মানুষ পড়তে পারেন, তা মানুষ অন্য কাউকে বলেও দিতে পারেন। প্রতারকেরা তাই প্রযুক্তি নয়, মনস্তত্ত্ব আক্রমণ করেন: তাড়াহুড়ো, কর্তৃত্ব (“আমি অফিস থেকে বলছি”), লোভ বা সহানুভূতি (“ভুল করে আপনার নম্বরে টাকা গেছে”)। বাংলাদেশে মোবাইল আর্থিক সেবার ব্যাপক প্রসারের সাথে এ ধরনের প্রতারণার খবরও প্রায়ই সংবাদমাধ্যমে আসে, আর সেবাদাতারা বারবার সচেতনতা-বার্তা দেয় — PIN বা OTP কাউকে নয়।

প্রযুক্তি কিছুটা সাহায্য করে। OTP-এর SMS-এ লেনদেনের বিবরণ লেখা থাকলে মানুষ বুঝতে পারেন তিনি কী অনুমোদন করছেন। কিন্তু যতক্ষণ গোপন জিনিসটি এমন রূপে আছে যা মানুষ অন্যকে দিতে পারেন, ততক্ষণ ঝুঁকিটি পুরো যায় না। একই যুক্তি TOTP-তেও: অংশ ৪-এর stepper-এর শেষ ধাপে দেখেছেন, নকল সাইট কোডটি তৎক্ষণাৎ আসল সাইটে বসাতে পারে।

Passkey এখানে নকশাগতভাবে আলাদা। এতে মানুষের কাছে কোনো “বলার মতো” গোপন জিনিস নেই — private key ডিভাইসের নিরাপদ চিপে বা পাসওয়ার্ড-ম্যানেজারে থাকে, আর ব্রাউজার বা OS নিজে যাচাই করে সাইটের ঠিকানা আসল কি না। নকল সাইটের জন্য আসল সাইটের সই তৈরিই হয় না। ফলে phishing-এর সফলতা আর মানুষের সতর্কতার ওপর নির্ভর করে না। এই কারণেই নিরাপত্তা-মহলে এ ধরনের পদ্ধতিকে “phishing-resistant MFA” বলা হয়।

মূল উপলব্ধি: যে গোপন জিনিস মানুষ পড়তে পারেন তা মানুষ বলেও দিতে পারেন; সবচেয়ে মজবুত authentication সেটি, যেখানে গোপন চাবি কখনো মানুষের হাতেই আসে না, আর যন্ত্র নিজে যাচাই করে সে কার সাথে কথা বলছে।

অনুশীলন

হাতে হিসাব, আউটপুট অনুমান আর কমান্ড — আগে নিজে চেষ্টা করুন, তারপর উত্তর মেলান।

  1. হাতে হিসাব: (ক) ৬২টি অক্ষর (a–z, A–Z, 0–9) থেকে এলোমেলো ১০ অক্ষরের একটি পাসওয়ার্ড — সম্ভাব্য পাসওয়ার্ড কত, আর কত বিট? (খ) সেকেন্ডে ১০৪ অনুমানের ধীর hash-এ গড়ে খুঁজে পেতে কত বছর? (গ) একই গতিতে ৭,৭৭৬ শব্দের তালিকা থেকে এলোমেলো ৫টি শব্দ?

    (ক) ৬২১০ ≈ ৮.৩৯ × ১০১৭; বিট = ১০ × log২৬২ ≈ ১০ × ৫.৯৫৪ ≈ ৫৯.৫ বিট.

    (খ) গড়ে অর্ধেক খুঁজতে হয়: ৪.২০ × ১০১৭ ÷ ১০৪ = ৪.২০ × ১০১৩ সেকেন্ড; এক বছর ≈ ৩.১৫৬ × ১০৭ সেকেন্ড, তাই প্রায় ১৩.৩ লাখ বছর (scratch script-এ যাচাই: ১.৩৩ × ১০৬)। দ্রুত hash-এ (১০১০/s) একই পাসওয়ার্ড প্রায় ১.৩৩ বছর।

    (গ) ৭,৭৭৬৫ ≈ ২.৮৪ × ১০১৯ (প্রায় ৬৪.৬ বিট); ÷ ২ ÷ ১০৪ ≈ ১.৪২ × ১০১৫ সেকেন্ড ≈ ৪.৫ কোটি বছর. পাঁচটি সাধারণ শব্দ ১০টি এলোমেলো অক্ষরের চেয়ে শক্তিশালী — আর মনে রাখা সহজ। শর্ত: শব্দগুলো সত্যিই এলোমেলো বাছা (যেমন ছক্কা দিয়ে), নিজের পছন্দের বাক্য নয়।

  2. হাতে trace — TOTP: TOTP-এর ধাপ ৩০ সেকেন্ড। (ক) Unix সময় T = 1234567889, 1234567919 আর 1234567920-এ counter C কত? কোন দুটিতে একই কোড দেখাবে? (খ) সার্ভার ঘড়ির পার্থক্যের জন্য বর্তমান counter-এর আগের ও পরের একটি করে ধাপ গ্রহণ করলে, T = 1234567890-এ সার্ভার কোন কোন counter-এর কোড মেনে নেবে, আর মোট কত সেকেন্ডের কোড?

    (ক) ⌊1234567889 ÷ 30⌋ = 41152262 (কারণ 41152263 × 30 = 1234567890, যা ১ সেকেন্ড পরে); ⌊1234567919 ÷ 30⌋ = 41152263; ⌊1234567920 ÷ 30⌋ = 41152264. কোনো দুটিই এক নয় — 1234567889 আর 1234567919 মাত্র ৩০ সেকেন্ড দূরে হলেও ধাপের সীমা পেরিয়েছে। একই কোড দেখায় 1234567890 থেকে 1234567919 পর্যন্ত (counter 41152263, কোড 005924).

    (খ) বর্তমান C = 41152263, তাই 41152262, 41152263 আর 41152264 — তিনটি ধাপ, মোট ৯০ সেকেন্ডের কোড। জানালা যত বড়, ব্যবহার তত সহজ কিন্তু চুরি হওয়া কোডের মেয়াদও তত বেশি — তাই জানালা ছোট রাখা আর একবার ব্যবহৃত কোড বাতিল করা হয়।

  3. আউটপুট অনুমান: অংশ ৭-এর hardening_check.sh-এ WEAK-এর শেষে -Wl,-z,execstack যোগ করলে check weak-এর প্রথম তিন লাইন কেমন হবে? এটি কেন বিপজ্জনক, আর নিজের প্রজেক্টে কীভাবে ধরবেন?
    == weak
      Type:                              EXEC (Executable file)
      GNU_STACK flags=RWE

    Type EXEC থাকে কারণ -no-pie; GNU_STACK-এর flags এখন RWE — stack লেখা এবং চালানো যায়, অর্থাৎ ওই প্রোগ্রামে W^X ভাঙা, NX-এর সুরক্ষা নেই। (নতুন binutils-এর linker এ অবস্থায় একটি সতর্কবার্তাও দিতে পারে।) Norelro বলে GNU_RELRO লাইন নেই। নিজের প্রজেক্টে CI-তে প্রতিটি build-এর পর readelf -lW দিয়ে GNU_STACK-এ E আছে কি না, আর Type DYN কি না, স্বয়ংক্রিয়ভাবে যাচাই করুন; কোনো library executable stack চাইলে কারণ খুঁজে সারান, সুরক্ষা বন্ধ নয়।

  4. কমান্ড লিখুন: একটি Linux সার্ভারে আপনি জানতে চান কে কখন /etc/sudoers ফাইল বদলাচ্ছে। auditd দিয়ে একটি নজরদারি-নিয়ম বসানো, পরে খোঁজা, আর নিয়মটি reboot-এর পরও টিকিয়ে রাখার কমান্ড লিখুন।
    sudo auditctl -w /etc/sudoers -p wa -k sudoers-change     # now, until reboot
    sudo auditctl -l                                         # confirm the rule is loaded
    sudo ausearch -k sudoers-change -i                       # later: who changed it, when
    # permanent: add the same rule to a rules file, then load
    echo '-w /etc/sudoers -p wa -k sudoers-change' | sudo tee /etc/audit/rules.d/sudoers.rules
    sudo augenrules --load

    -w ফাইলটি নজরে রাখে, -p wa মানে লেখা (write) আর অনুমতি-বদল (attribute); -k একটি খোঁজার চাবি। ausearch -i সংখ্যাগুলোকে নাম হিসেবে দেখায়, আর auid বলে আসল লগইন করা মানুষটি কে — sudo-র পরেও। /etc/sudoers.d/ ফোল্ডারও নজরে রাখতে একই নিয়ম সেই ফোল্ডারের জন্য যোগ করুন। log অন্য মেশিনে পাঠানো ভালো অভ্যাস।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমsalt-সহ ধীর hash আর MFA ব্যবহার করা একটি সিস্টেমে লগইনের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. ব্যবহারকারী নাম আর পাসওয়ার্ড দেন (এনক্রিপ্টেড সংযোগে)
  2. সার্ভার ব্যবহারকারীর রেকর্ড থেকে salt, cost আর সংরক্ষিত hash পড়ে
  3. টাইপ করা পাসওয়ার্ড আর সেই salt দিয়ে একই ধীর hash আবার হিসাব হয়
  4. দুই hash constant-time পদ্ধতিতে তুলনা হয়
  5. মিললে দ্বিতীয় factor (যেমন TOTP কোড বা passkey) চাওয়া হয়
  6. সেশন তৈরি হয় আর লগইনের ঘটনা log-এ লেখা হয়

একটি হাসপাতালের সার্ভারে ransomware সব রোগীর ফাইল এনক্রিপ্ট করে দিল, ফলে চিকিৎসকেরা রিপোর্ট খুলতে পারছেন না। CIA triad-এর কোন দিকটি এখানে প্রধানত ক্ষতিগ্রস্ত?

  • Confidentiality
  • Integrity
  • Availability
  • Authentication

পাসওয়ার্ড hash করার আগে প্রতিটি ব্যবহারকারীর জন্য আলাদা এলোমেলো salt মেশানোর প্রধান উদ্দেশ্য কী?

  • পাসওয়ার্ডকে এনক্রিপ্ট করা, যাতে পরে ফেরত আনা যায়
  • একই পাসওয়ার্ডে আলাদা hash দেওয়া আর আগে-বানানো hash-টেবিল অকেজো করা
  • প্রতিটি অনুমানকে লাখো গুণ ধীর করা
  • ব্যবহারকারীর পাসওয়ার্ড লম্বা করে দেওয়া

একটি Linux binary-তে readelf -lW চালিয়ে কোন ফলটি দেখলে বোঝা যায় যে তার stack-এ NX (non-executable stack) চালু আছে?

  • GNU_STACK-এর flags = RWE
  • ELF Type = DYN
  • BIND_NOW লাইন আছে
  • GNU_STACK-এর flags = RW

gcc-এর -fstack-protector-strong দিয়ে বসানো stack canary মূলত কী ধরে?

  • একটানা উপচে পড়া buffer যখন ফাংশনের ফেরার ঠিকানার দিকে লেখে — ফেরার ঠিক আগে
  • Heap-এ free করা মেমরির পুনর্ব্যবহার
  • প্রতিবার প্রোগ্রামের ঠিকানা এলোমেলো করা
  • Stack-এর বাইট নির্দেশ হিসেবে চালানো

২০১৮ সালে Linux-এ KPTI চালু করা হয় কোন সমস্যার প্রতিকারে, আর এর প্রধান দাম কী?

  • Morris worm; দাম — বেশি মেমরি
  • Stack buffer overflow; দাম — বড় binary
  • Meltdown; দাম — system call ও interrupt-এ বাড়তি খরচ
  • Phishing; দাম — ধীর লগইন

একজন ব্যবহারকারী ভুল করে আসল ব্যাংকের মতো দেখতে একটি নকল ওয়েবসাইটে লগইন করতে গেলেন। কোন authentication পদ্ধতি এ অবস্থাতেও আক্রমণকারীকে লগইন করতে দেয় না?

  • পাসওয়ার্ড + SMS-এ আসা OTP
  • Passkey (FIDO2/WebAuthn)
  • পাসওয়ার্ড + authenticator অ্যাপের TOTP কোড
  • শুধু ২০ অক্ষরের লম্বা পাসওয়ার্ড

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. লক্ষ্য: CIA — confidentiality, integrity, availability. Vulnerability সিস্টেমের ত্রুটি, threat বাইরের বা ভেতরের বিপদ, attack দুটির মিলন; প্রতিরক্ষা স্তরে স্তরে (defense in depth).
  2. পাসওয়ার্ড: প্রতি ব্যবহারকারীর salt + ধীর hash (Argon2id, bcrypt, scrypt), constant-time তুলনা, rate limit. নীতি: দৈর্ঘ্য, ফাঁস-হওয়া পাসওয়ার্ড বাতিল, জোর করে জটিলতা বা নিয়মিত বদল নয়। Linux-এ /etc/shadow আর PAM.
  3. MFA: TOTP = HMAC(K, ⌊T/30⌋) থেকে ছয় অঙ্ক — চুরি হওয়া পাসওয়ার্ড ঠেকায়, phishing পুরো নয়। Passkey সাইটের ঠিকানায় বাঁধা, তাই phishing-প্রতিরোধী।
  4. শিকড়: ring 0/3, প্রতি প্রসেসের page table, U/S ও R/W/X বিট; অ্যাপের একমাত্র দরজা system call, যেখানে kernel authorization যাচাই করে। Least privilege ক্ষতি সীমিত রাখে।
  5. Memory-সুরক্ষা: buffer overflow, use-after-free, integer overflow-এর বিরুদ্ধে NX/W^X, canary, ASLR+PIE, full RELRO, CFI/shadow stack; kernel-এ KASLR, SMEP/SMAP, KPTI, Spectre-প্রতিকার। readelf আর /sys/.../vulnerabilities দিয়ে যাচাই; আসল সমাধান বাগ সারানো, patch আর memory-safe ভাষা।

পরের পর্বে: একটি প্রোগ্রাম ভাঙলেও ক্ষতি যেন তার ঘেরাটোপেই আটকে থাকে — পর্ব ৪৯-এ sandbox, seccomp, SELinux/AppArmor-এর মতো mandatory access control, আর secure boot-এর শিকল কীভাবে পুরো সিস্টেমকে বিশ্বাসযোগ্য রাখে।

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

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান