সরাসরি পর্বে যান
পর্ব ৫৫ · ৮০-এর মধ্যে · মডিউল ৯

নিরাপত্তার log — কী রাখবেন, কোথায় রাখবেন আর কতদিন

Security Logging — What to Keep, Where to Keep It & for How Long

Taught in Bangla, this lesson covers security logging for defenders: nine log sources and the questions they answer, what never to log, structured logs and common schemas, clock skew, UTC and NTP, reading a sample auth log with awk, tamper evidence with a real SHA-256 hash chain, volume, cost and retention calculations, alerts for silent log sources, and staff privacy.

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

  • কোন নয় ধরনের log কোন প্রশ্নের উত্তর দেয়, আর কোনটি রাখা বিপজ্জনক
  • Structured log আর common schema, আর ঘড়ির অমিল শুধরে তিনটি উৎস জোড়া
  • একটি নমুনা auth log পড়া, আর awk দিয়ে নিজের log বিশ্লেষণ
  • Hash chain কী ধরে আর কী ধরে না, আর কেন একটি কপি বাইরে থাকা জরুরি
  • Volume, খরচ আর retention-এর পূর্ণ হিসাব
  • Log source inventory, নীরব উৎসের alert আর কর্মীর privacy

১ · Log হলো রক্ষকের স্মৃতি

একটি অফিসের গেটে দারোয়ানের রেজিস্টার খাতা ভাবুন। কে ঢুকলেন, কখন, কার কাছে এলেন, কখন গেলেন। সাধারণ দিনে কেউ এই খাতা খোলে না। কিন্তু যেদিন অফিসের একটি ল্যাপটপ হারায়, সেদিন এই খাতাই একমাত্র সাক্ষী। খাতায় ফাঁকা পাতা থাকলে, বা তিন মাস পরের ঘটনা জানতে গিয়ে খাতাটিই ফেলে দেওয়া হয়েছে দেখলে, প্রশ্নের উত্তর আর পাওয়া যায় না।

Audit log বা নিরাপত্তার log হলো যন্ত্রের সেই রেজিস্টার খাতা। Prevention সবসময় কাজ করবে না, এই ধরে নিয়েই পর্ব ২-এ আমরা detective control দেখেছি। Detection, তদন্ত আর পুনরুদ্ধার তিনটিই দাঁড়িয়ে থাকে log-এর ওপর। SIEM যত দামিই হোক, যে ঘটনা log হয়নি তা সে ধরতে পারে না।

মূল ধারণা

একটি ভালো নিরাপত্তা log ছয়টি প্রশ্নের উত্তর দেয়: কে (user বা service), কী করল, কখন (UTC), কোথায় (কোন system বা resource), কোথা থেকে (উৎস ঠিকানা বা device), আর ফল কী হলো (সফল না ব্যর্থ)। একটি ঘরও ফাঁকা থাকলে তদন্ত সেখানেই আটকে যেতে পারে।

১৯৮৬ সালে যুক্তরাষ্ট্রের Lawrence Berkeley Laboratory-তে জ্যোতির্বিজ্ঞানী Cliff Stoll কম্পিউটার ব্যবহারের হিসাবে ৭৫ সেন্টের একটি গরমিল পান। সেই ছোট গরমিলের সূত্র ধরে accounting log আর printout ঘেঁটে তিনি একজন অনুপ্রবেশকারীর খোঁজ পান, যে ঘটনা তাঁর The Cuckoo's Egg (১৯৮৯) বইয়ে লেখা আছে। শিক্ষাটি আজও একই: হিসাব মিলছে না, এই ছোট খবরটিও detection.

এই পর্বে প্রশ্নটি নিরাপত্তার: কী রাখলে তদন্ত সম্ভব, আর কী রাখলে নতুন ক্ষতি হয়। Agent, buffer, Loki বা Elasticsearch-এর মতো অবকাঠামো চালানোর কাজ দেখতে Centralized logging পর্বটি পড়ুন। আমরা সেগুলো আবার বলব না। Metric আর trace-এর সাথে log-এর সম্পর্ক আছে observability-তে।

২ · কী রাখবেন — নয়টি উৎস আর তাদের প্রশ্ন

“সব log করুন” শুনতে সহজ, কিন্তু কাজের নয়। তাতে খরচ বাড়ে, আসল ঘটনা ডুবে যায়, আর ব্যক্তিগত তথ্য জমে। ভালো পদ্ধতি হলো প্রশ্ন থেকে শুরু করা: তদন্তে আমার কোন প্রশ্নের উত্তর লাগবে? নিচের নয়টি উৎস বেশিরভাগ প্রতিষ্ঠানের ভিত্তি।

উৎসযে প্রশ্নের উত্তর দেয়যা অবশ্যই থাকবে
Authenticationকে ঢুকল, কে ব্যর্থ হলো?User, ফল, উৎস, পদ্ধতি (MFA ছিল কি না)
Authorization failureকে অনুমতির বাইরে যেতে চাইল?User, resource, কাজ, প্রত্যাখ্যানের কারণ
Admin কাজক্ষমতা কে, কখন ব্যবহার করল?Admin, কাজ, লক্ষ্য, ticket থাকলে তার নম্বর
Configuration changeকে নিয়ম বদলাল, আগে কী ছিল?আগের মান, নতুন মান, যিনি বদলালেন
Data accessকে সংবেদনশীল ডেটা পড়ল বা নামাল?User, ডেটার শ্রেণি, row সংখ্যা। ডেটা নিজে নয়
Network flowকে কার সাথে কথা বলল, কতটা?Flow record: ঠিকানা, port, bytes, সময়
DNSকোন যন্ত্র কোন নাম খুঁজল?Client, query, উত্তর
Process executionযন্ত্রে কোন program চলল?Process, parent, user, command line
Cloud audit trailCloud-এ API দিয়ে কে কী বদলাল?Identity, API call, region, উৎস, ফল

এগুলোর জন্য বিশেষ পণ্য লাগবে, এমন নয়। Linux-এ auditd process আর ফাইলের ঘটনা লেখে (পর্ব ৩০). Windows-এ logon আর process creation-এর জন্য Event 4624, 4625 আর 4688 পরিচিত (পর্ব ৩১). Network flow আর sensor-এর সীমা আপনি পর্ব ২৩-এ দেখেছেন। Cloud-এ AWS CloudTrail, Azure Activity Log বা Google Cloud Audit Logs-এর মতো সেবা আছে। অনেক প্রদানকারীর ক্ষেত্রে management কাজ সাধারণত লেখা হয়, কিন্তু ডেটা পড়ার ঘটনা আলাদা করে চালু করতে হয়। নিজের প্রদানকারীর নথি দেখে নিন।

Command line log করা খুব কাজের, কিন্তু মানুষ অনেক সময় command-এ password লিখে ফেলে। তাই এই log নিজেই সংবেদনশীল। Access সীমিত রাখুন, আর command-এ secret না দেওয়ার অভ্যাস তৈরি করুন।

তিনটি পরিচিত নির্দেশিকা কী বলে

NIST SP 800-92

Karen Kent আর Murugiah Souppaya-র Guide to Computer Security Log Management (২০০৬)। Revision 1-এর খসড়া, Cybersecurity Log Management Planning Guide, অক্টোবর ২০২৩-এ মন্তব্যের জন্য বেরিয়েছিল। NIST-এর পাতায় ২০২৬ সালের নভেম্বরেও সেটি খসড়া হিসেবেই আছে। উদ্ধৃতির আগে csrc.nist.gov-এ বর্তমান অবস্থা দেখে নিন।

পরিকল্পনা ও প্রক্রিয়া

CIS Control 8

CIS Controls v8.1 (২০২৪)-এর Audit Log Management, ১২টি safeguard-সহ: documented process, log সংগ্রহ, যথেষ্ট storage, দুটি time source, DNS, URL ও command-line log, কেন্দ্রীয় জমা, অন্তত ৯০ দিন retention, সাপ্তাহিক review আর service provider-এর log.

যাচাইযোগ্য তালিকা

OWASP Logging Cheat Sheet

এই নির্দেশিকা application-এর দিক থেকে সবচেয়ে কাজের তালিকা দেয়: input validation ব্যর্থতা, authentication, access control, session ব্যর্থতা, উচ্চ ঝুঁকির কাজ। সাথে কী সরাসরি লিখবেন না, তারও তালিকা।

Developer-এর জন্য

৩ · কী কখনো রাখবেন না

Log সাধারণত database-এর চেয়ে কম পাহারায় থাকে। বেশি মানুষ পড়তে পারেন, কপি হয় অনেক জায়গায়, মুছতে দেরি হয়। তাই log-এ secret ঢোকা মানে সেই secret-এর ওপর সব নিয়ন্ত্রণ চলে যাওয়া। পর্ব ১৩-এর সব সুরক্ষা অর্থহীন, যদি login request-এর পুরো body কোথাও লেখা হয়ে যায়।

যা লিখবেন নাকেনবদলে কী
Password, OTP, PINপড়লেই account দখল করা যায়শুধু ফল: result=failure
Access token, session id, API keyচলতি token চুরি মানে login ছাড়াই প্রবেশ (পর্ব ১৭)Token-এর id, বা OWASP-এর মতে session id-র hash
পূর্ণ কার্ড নম্বর, CVVPCI DSS এগুলো সংরক্ষণে কড়া শর্ত দেয়শেষ চার সংখ্যা, বা payment প্রদানকারীর reference
Connection string, encryption keyপুরো system-এর চাবিশুধু key-এর id বা version
বাড়তি ব্যক্তিগত তথ্য: NID, পুরো ঠিকানা, স্বাস্থ্য তথ্যতদন্তে লাগে না, ফাঁস হলে ক্ষতিInternal user id, data minimization
# Unsafe: the whole request lands in the log, secrets and all.
logger.info("login request: %s", request.body)

# Safe: an explicit allow-list of fields, nothing else.
logger.info("login", extra={
    "event": "login", "user_id": user.id,
    "result": "failure", "reason": "bad_password",
    "src_ip": client_ip, "request_id": request_id,
})

মূল শিক্ষা হলো allow-list. “এই ক্ষেত্রগুলো বাদ” তালিকা সবসময় অসম্পূর্ণ থাকবে, আর নতুন ক্ষেত্র যোগ হলে সেটি ফাঁকি দেবে। “শুধু এই ক্ষেত্রগুলো লেখা হবে” তালিকা নিরাপদ দিকে ব্যর্থ হয়। সাথে pipeline-এ log redaction রাখুন দ্বিতীয় স্তর হিসেবে, আর repository-তে secret scanning-এর মতো পরীক্ষা চালান।

Log-এর ভেতরে যা ঢোকে, তার অনেকটাই বাইরের মানুষের লেখা: username, URL, User-Agent. এতে নতুন লাইনের চিহ্ন থাকলে কেউ নকল log লাইন বানাতে পারে। একে বলে log injection. প্রতিকার হলো structured log আর control character শোধন (পর্ব ৪৬). আবার log পড়ার পর্দায় সেই লেখা encoding ছাড়া দেখালে XSS-এর ঝুঁকিও আসে (পর্ব ৪০).

৪ · Structured log আর common schema

পাঁচটি অফিসের পাঁচ রকম খাতা ভাবুন। কেউ লেখেন “নাম”, কেউ “আগন্তুক”, কেউ “ভিজিটর”। এক জায়গায় বসে সব মেলাতে গেলে আগে ভাষা এক করতে হবে। Log-এও তাই। Free text লাইন মানুষ পড়তে পারে, কিন্তু যন্ত্রকে প্রতিটি format আলাদা করে শেখাতে হয়। Structured log মানে প্রতিটি তথ্য আলাদা নামের ক্ষেত্রে, সাধারণত JSON আকারে।

Common schema আরেক ধাপ এগোয়: সব উৎস একই ক্ষেত্রের নাম ব্যবহার করবে। তাহলে একটি rule সব উৎসে চলবে। কয়েকটি পরিচিত উদাহরণ:

Schemaকোথা থেকেক্ষেত্রের উদাহরণ
ECSElastic-এর তৈরি। ২০২৩ সালে OpenTelemetry-তে দান করার ঘোষণা হয়, লক্ষ্য তাদের semantic convention-এর সাথে মেলানোuser.name, source.ip, event.outcome
OCSFAWS, Splunk আর আরও কিছু প্রতিষ্ঠানের উদ্যোগ, আগস্ট ২০২২। Symantec-এর পুরোনো schema-র কাজের ওপর গড়া, পরে Linux Foundation-এ গেছেclass_uid, user.name, src_endpoint.ip

এগুলো উদাহরণ, সুপারিশ নয়। আপনার SIEM যেটি ভালো বোঝে সেটি নিন, বা একটি ছোট নিজস্ব অভিধান লিখুন। আসল কথা হলো সবাই একই নাম মানছে কি না। নিচের ডায়াগ্রামে একটি login-এর পুরো যাত্রা দেখুন।

  1. Appapp.logঘটনা লেখা
  2. Agenthostপড়া
  3. TLScollectorবাইরে পাঠানো
  4. Schemafieldsএক নাম
  5. SIEMruleখোঁজা, alert
app.logweb-1, 02:10:00.412Z
{"ts":"2026-10-31T02:10:00.412Z",
 "event":"login", "result":"success",
 "user":"tania", "mfa":"totp",
 "src":"198.51.100.7",
 "request_id":"req-7f31"}
Agentদুটি ক্ষেত্র যোগ হলো
... আগের সব ক্ষেত্র অপরিবর্তিত ...
"host":"web-1"
"read_at":
  "2026-10-31T02:10:00.530Z"
Transportbatch 214, TLS
from:   web-1 agent
to:     collector.example.com
status: delivered
received_at: 2026-10-31T02:10:01.020Z
পথ বন্ধ থাকলে agent-এর buffer-এ অপেক্ষা
NormalizeECS-ধাঁচের নাম, উদাহরণ
{"@timestamp":
  "2026-10-31T02:10:00.412Z",
 "event.category":"authentication",
 "event.outcome":"success",
 "user.name":"tania",
 "source.ip":"198.51.100.7",
 "host.name":"web-1"}
SIEMজমা হলো, rule চলল
asset:     web-1, গুরুত্ব high
user:      tania, হিসাব বিভাগ
rule:      failure-then-success
result:    alert নয়
আগে কোনো ব্যর্থতা নেই
delay:     0.608 s (received − ts)
  1. ঘটনা জন্মাল। App নিজেই একটি JSON লাইন লিখল। ক্ষেত্রগুলো allow-list থেকে এসেছে। Password নেই, token নেই। সময় UTC, শেষে Z সেটিই বলে। request_id পরে অন্য service-এর log জোড়ার সূত্র।
  2. Agent পড়ল। Agent মূল লাইন বদলায় না, শুধু কোন যন্ত্র থেকে এলো আর কখন পড়ল তা যোগ করে। ঘটনার সময় আর পড়ার সময় আলাদা রাখা জরুরি।
  3. যন্ত্রের বাইরে গেল। Log এখন TLS-এ collector-এ। এই মুহূর্ত থেকে web-1 দখল হলেও এই লাইনটি আর মোছা যাবে না। এটিই log forwarding-এর আসল নিরাপত্তা লাভ।
  4. এক ভাষায় এলো। user হলো user.name, src হলো source.ip, result হলো event.outcome. এখন VPN, app আর cloud-এর login একটি rule-এই খোঁজা যায়।
  5. SIEM কাজে লাগাল। Asset আর user-এর তথ্য যোগ হলো, rule চলল। এখানে alert হলো না, আর সেটিই স্বাভাবিক। ঘটনা থেকে পৌঁছাতে ০.৬০৮ সেকেন্ড লেগেছে। এই দেরি হঠাৎ বাড়লে সেটিও একটি সংকেত। Rule লেখার কাজ পর্ব ৫৬-এ আসবে।

৫ · ঘড়ি মিললে তবেই গল্প মেলে

তিনজন সাক্ষী তিনটি আলাদা ঘড়ি দেখে সময় বললে আদালতে গল্প মেলে না। Log-এও তাই। তদন্তের ভিত্তি হলো ক্রম: কোনটি আগে, কোনটি পরে। দুটি ভিন্ন সমস্যা এখানে গুলিয়ে যায়।

  • Time zone: বাংলাদেশের সময় UTC-র ছয় ঘণ্টা আগে (+06:00). একটি লাইনে local সময় আছে কিন্তু offset নেই, তাহলে অন্য উৎসের সাথে মেলানো কঠিন। তাই log-এ UTC লিখুন, দেখানোর সময় বদলান। RFC 3339 ধরনের 2026-10-31T02:10:00Z format এই অস্পষ্টতা দূর করে।
  • Clock skew: যন্ত্রের ঘড়ি সত্যিই আগে বা পিছে চলছে। সমাধান NTP. CIS safeguard 8.4 অন্তত দুটি time source বলে। ঘড়ি হঠাৎ অনেকটা সরলে সেটিও log-এ আসা উচিত, কারণ সময় বদলানো প্রমাণ নষ্ট করার একটি উপায়ও হতে পারে।
# Two approved internal time sources. Host names are placeholders.
server ntp1.example.com iburst
server ntp2.example.com iburst
# On your own Linux server, read the current offset with: chronyc tracking

এবার তিনটি উৎসের ঘটনা জোড়া দেখুন। সংখ্যাগুলো কাল্পনিক। VPN-এর ঘড়ি ঠিক আছে, app server ২ মিনিট পিছিয়ে, আর database local সময় লেখে, ৫ সেকেন্ড এগিয়ে।

কাঁচা logযেমন লেখা আছে
VPN  02:10:00Z  tania login ok
APP  02:08:30Z  tania admin export
DB   08:11:05   select 12000 rows
Login-এর আগেই export?
DB ছয় ঘণ্টা পরে?
ধাপ: time zoneDB: Asia/Dhaka, offset +06:00
VPN  02:10:00Z
APP  02:08:30Z
DB   02:11:05Z   (08:11:05 − 6 ঘণ্টা)
এখন একই ভাষা, কিন্তু APP এখনো VPN-এর আগে
ধাপ: offset মাপাNTP রিপোর্ট থেকে, উৎস − সত্য সময়
VPN  offset    0 s
APP  offset −120 s   (ঘড়ি পিছিয়ে)
DB   offset   +5 s   (ঘড়ি এগিয়ে)
সত্য সময় = লেখা সময় − offset
ধাপ: শুধরানোআসল সময়
VPN  02:10:00Z
APP  02:08:30 + 120 s = 02:10:30Z
DB   02:11:05 −   5 s = 02:11:00Z
Timelineক্রম এখন যুক্তিসঙ্গত
02:10:00Z  VPN  tania login ok
02:10:30Z  APP  tania admin export
02:11:00Z  DB   select 12000 rows
প্রতিটি ধাপে ব্যবধান ৩০ s
মূল সময়গুলো আলাদা ক্ষেত্রে রাখা আছে
  1. কাঁচা log বিভ্রান্ত করে। দেখে মনে হয় export হয়েছে login-এর দেড় মিনিট আগে, যা অসম্ভব। DB-র লাইনে time zone-ই নেই। এই অবস্থায় কোনো সিদ্ধান্ত নেওয়া যাবে না।
  2. আগে time zone. DB local সময় লিখছে, Asia/Dhaka. ছয় ঘণ্টা বাদ দিলে 02:11:05Z. কিন্তু APP তখনও VPN-এর ৯০ সেকেন্ড আগে, অর্থাৎ সমস্যা বাকি।
  3. তারপর offset. NTP monitoring থেকে জানা গেল APP −১২০ সেকেন্ড, DB +৫ সেকেন্ড। NTP-র ইতিহাস না থাকলে একটি জানা ঘটনা, যেমন দুই যন্ত্রের একই request, দিয়েও অনুমান করা যায়। তখন সেটি অনুমান বলেই লিখুন।
  4. হিসাব। সত্য সময় = লেখা সময় − offset. APP: 02:08:30 − (−১২০ সেকেন্ড) = 02:10:30. DB: 02:11:05 − ৫ সেকেন্ড = 02:11:00.
  5. গল্প মিলল। Login, এক মিনিটের মধ্যে export, তারপর database থেকে ১২,০০০ row. এখন প্রশ্ন করা যায়, এই কাজ কি স্বাভাবিক ছিল? মূল সময় মুছবেন না। শুধরানো মান আলাদা ক্ষেত্রে রাখুন, যাতে আপনার হিসাব পরে কেউ যাচাই করতে পারেন। Timeline বানানোর পুরো কাজ পর্ব ৬৪-তে আসবে।

৬ · একটি auth log পড়া

এবার একটি বাস্তব ধাঁচের log পড়ি। Debian ধাঁচের Linux-এ /var/log/auth.log, Red Hat ধাঁচে /var/log/secure, আর systemd-এর journal-এও এই তথ্য থাকে। আপনি নিজের server-এই এই কাজ করবেন। অন্যের system-এর log দেখার অনুমতি লাগে (পর্ব ৬).

Oct 31 02:11:12 web-1 sshd[2215]: Failed password for rafi from 203.0.113.50 port 51133 ssh2
অংশমানেসাবধানতা
Oct 31 02:11:12সময়বছর আর time zone নেই। নতুন কিছু distro ISO সময় লেখে
web-1 sshd[2215]যন্ত্র, program, process idHostname আর program নাম যেকোনো স্থানীয় process দাবি করতে পারে
Failed password for rafiঘটনা আর accountinvalid user থাকলে account-টি নেই। Username বাইরের মানুষের লেখা
from 203.0.113.50উৎসNAT বা VPN-এর পেছনে অনেকজন থাকতে পারেন

নিচের block নিজের ভেতরে একটি নির্দিষ্ট নমুনা ফাইল বানায়, তারপর সেটিই পড়ে। কোনো আসল log বা system-এ হাত দেয় না। Field গোনা হয়েছে লাইনের শেষ থেকে ($(NF-3)), কারণ শুরুর দিকের username বাইরের মানুষ নিয়ন্ত্রণ করে, আর শেষের দিকটি sshd নিজে লেখে।

# Fixed sample built here. Addresses and names are made up.
cat > auth.log <<'EOF'
Oct 31 02:11:04 web-1 sshd[2210]: Failed password for invalid user admin from 203.0.113.50 port 51122 ssh2
Oct 31 02:11:06 web-1 sshd[2210]: Failed password for invalid user test from 203.0.113.50 port 51124 ssh2
Oct 31 02:11:09 web-1 sshd[2213]: Failed password for root from 203.0.113.50 port 51130 ssh2
Oct 31 02:11:12 web-1 sshd[2215]: Failed password for rafi from 203.0.113.50 port 51133 ssh2
Oct 31 02:11:40 web-1 sshd[2218]: Failed password for tania from 198.51.100.7 port 40110 ssh2
Oct 31 02:12:01 web-1 sshd[2219]: Accepted publickey for sohel from 198.51.100.20 port 40220 ssh2
Oct 31 02:12:31 web-1 sshd[2221]: Accepted password for rafi from 203.0.113.50 port 51140 ssh2
Oct 31 02:13:05 web-1 sudo:     rafi : TTY=pts/1 ; PWD=/home/rafi ; USER=root ; COMMAND=/usr/bin/tar czf /tmp/c.tgz /srv/data
EOF
echo "== failed logins by source =="
awk '/sshd.*Failed password/ {print $(NF-3)}' auth.log | sort | uniq -c | sort -k1,1nr -k2
echo "== failed logins by username =="
awk '/sshd.*Failed password/ {print $(NF-5)}' auth.log | sort | uniq -c | sort -k1,1nr -k2
echo "== success from a source that failed earlier =="
awk '/sshd.*Failed password/ {bad[$(NF-3)]++}
     /sshd.*Accepted/ && ($(NF-3) in bad) {
       print $3, $(NF-5), "from", $(NF-3), "after", bad[$(NF-3)], "failures"}' auth.log
echo "== sudo commands =="
awk -F'COMMAND=' '/sudo:/ && NF > 1 {print $2}' auth.log

আউটপুটের মূল অংশ: 4 203.0.113.50 আর 1 198.51.100.7, তারপর 02:12:31 rafi from 203.0.113.50 after 4 failures, আর শেষে /usr/bin/tar czf /tmp/c.tgz /srv/data. এক উৎস থেকে ৮ সেকেন্ডে চারটি ভিন্ন account-এ ব্যর্থতা, ৭৯ সেকেন্ড পরে একটিতে সফল login, আর ৩৪ সেকেন্ড পরে sudo দিয়ে ডেটা আর্কাইভ করা। আলাদা লাইনে কিছুই প্রমাণ হয় না, একসাথে এটি জরুরি তদন্তের কারণ। তবে এটি রায় নয়, শুধু প্রশ্ন। রাফি নিজে কি তখন কাজ করছিলেন? এই উৎস কি তাঁর? আগে যাচাই, তারপর সিদ্ধান্ত। আর একা tania-র একটি ব্যর্থতা সাধারণ ভুল টাইপিংও হতে পারে।

৭ · Log-কে কেউ বদলালে জানবেন কীভাবে

যে যন্ত্র দখল হয়েছে, তার log-কে বিশ্বাস করা যায় না। অনুপ্রবেশকারী root হলে স্থানীয় ফাইল মুছতে বা বদলাতে পারে। অভ্যন্তরীণ ঝুঁকিতেও (insider threat) একই কথা। পোস্ট অফিসের সিলমোহর যেমন চিঠির সময়ের প্রমাণ, কারণ সেটি প্রেরকের হাতে নেই, log-এর প্রমাণও তেমনি থাকতে হবে সন্দেহভাজনের নাগালের বাইরে। তিনটি স্তর একে অন্যের পরিপূরক।

১. Off-host forwarding

Log জন্মানোর সাথে সাথে অন্য যন্ত্রে। Syslog over TLS বা agent, দুটিই চলে। ছোট ব্যবধানে যা পাঠানো হয়নি, শুধু সেটুকুই ঝুঁকিতে।

মুছতে বাধা

২. Append-only জমা

Append-only মানে শুধু যোগ করা যায়, বদলানো নয়। Object lock বা WORM storage এর একটি রূপ। Log-এর admin আর system-এর admin আলাদা মানুষ হবেন, যাকে বলে separation of duties.

বদলাতে বাধা

৩. Hash chain

প্রতিটি লাইনের hash-এ আগের লাইনের hash যুক্ত। একটি বদলালে পরের সব ভেঙে যায়। এটি বদলানো আটকায় না, ধরে ফেলে।

বদল ধরা

Hash chain-এর সূত্র সরল: d[i] = SHA-256(d[i-1] | line[i]). শুরুতে d[0] হলো একটি জানা মান, এখানে ৬৪টি শূন্য। পর্ব ৯-এ আপনি দেখেছেন, input-এর একটি অক্ষর বদলালে hash সম্পূর্ণ বদলে যায়। নিচের সংখ্যাগুলো আসল SHA-256-এর প্রথম ১২ অক্ষর।

লাইন ১d0 = 64টি 0
02:10:00 login ok user=tania
  src=198.51.100.7
d1 = 49f0d3dd3c81
লাইন ২SHA-256(d1 | লাইন ২)
d1 = 49f0d3dd3c81
02:11:30 role change user=tania
  role=admin by=sohel
d2 = 43935149832a
লাইন ৩SHA-256(d2 | লাইন ৩)
d2 = 43935149832a
02:12:05 export rows=12000 user=tania
d3 = 4f9e4bdbf1ef
Anchorhash বাইরে গেল
web-1-এ: লাইন ১–৩, d1, d2, d3
বাইরে:   d3 = 4f9e4bdbf1ef
web-1-এর admin এটি বদলাতে পারেন না
কেউ বদলাললাইন ২
02:11:30 role change user=tania
  role=viewer by=sohel
আগে ছিল role=admin
যাচাইনতুন করে হিসাব
লাইন ১ মিলল
  নতুন 49f0d3dd3c81
  জমা  49f0d3dd3c81
লাইন ২ ভাঙল
  নতুন cb3b7924cec1
  জমা  43935149832a
লাইন ৩ ভাঙল
  নতুন 7e1d54819364
  জমা  4f9e4bdbf1ef
প্রথম ভাঙা লাইন: ২
  1. প্রথম লাইন। শুরুর মান আর লাইন ১ একসাথে hash হয়ে হলো d1, যার শুরু 49f0d3dd3c81.
  2. দ্বিতীয় লাইন। d1 এখন পরের hash-এর input. তাই লাইন ২-এর d2 লাইন ১-এর ওপরও নির্ভরশীল। শিকলের কড়া এভাবেই জোড়া লাগে।
  3. তৃতীয় লাইন। d3 এখন পুরো ইতিহাসের সংক্ষিপ্ত আঙুলের ছাপ। এই একটি মানের ওপর তিনটি লাইনই নির্ভর করে।
  4. Anchor. শেষ hash নিয়মিত অন্য জায়গায় কপি করা হলো। এই বাইরের নির্ভরযোগ্য কপিকেই anchor বলা হচ্ছে। পরের ধাপগুলোতে দেখবেন, এই বাইরের কপিটিই আসল ভরসা।
  5. বদল। কেউ লাইন ২-এ role=admin-কে role=viewer করল, যাতে ক্ষমতা বাড়ানোর চিহ্ন না থাকে।
  6. ধরা পড়ল। লাইন ১ মিলল। লাইন ২-এর নতুন hash cb3b7924cec1 জমা করা মানের সাথে মেলে না, আর লাইন ৩-ও ভাঙল, যদিও সেটি কেউ ছোঁয়নি। প্রথম ভাঙা লাইনই বদলের জায়গা দেখায়।

কিন্তু এখানে একটি বড় ফাঁদ আছে। Hash-এ কোনো গোপন চাবি নেই। যে ফাইল বদলাতে পারে, সে সব hash নতুন করেও লিখতে পারে। নিচের কোড সেটিই দেখায়।

# Toy hash chain over fixed log lines. Real SHA-256, made-up data.
import hashlib
GENESIS = "0" * 64

def link(prev, line):
    return hashlib.sha256(f"{prev}|{line}".encode()).hexdigest()

def chain(lines):
    digests, prev = [], GENESIS
    for line in lines:
        prev = link(prev, line)
        digests.append(prev)
    return digests

def first_bad(lines, stored):
    for i, digest in enumerate(chain(lines)):
        if digest != stored[i]:
            return i + 1
    return None

log = ["02:10:00 login ok user=tania src=198.51.100.7",
       "02:11:30 role change user=tania role=admin by=sohel",
       "02:12:05 export rows=12000 user=tania"]
stored = chain(log)
anchor = stored[-1]            # copied off the host at once
for line, digest in zip(log, stored):
    print(digest[:12], line)
print("clean log, first bad line:", first_bad(log, stored))
edited = log.copy()
edited[1] = edited[1].replace("role=admin", "role=viewer")
print("edited log, first bad line:", first_bad(edited, stored))
rebuilt = chain(edited)        # someone recomputes every digest on the host
print("rebuilt digests, first bad line:", first_bad(edited, rebuilt))
print("rebuilt tip matches off-host anchor:", rebuilt[-1] == anchor)

clean log, first bad line: None মানে কিছু ভাঙেনি। edited log, first bad line: 2 বদলটি ধরেছে। এবার আসল শিক্ষা: rebuilt digests, first bad line: None. কেউ সব hash নতুন করে লিখলে স্থানীয় যাচাই পাস করে! কিন্তু rebuilt tip matches off-host anchor: False, কারণ বাইরের কপি সে ছুঁতে পারেনি। তাই hash chain একা যথেষ্ট নয়, anchor লাগবে। বিকল্প বা বাড়তি উপায় হলো চাবিসহ HMAC, যেখানে চাবি যাচাইকারীর কাছে থাকে। আবার শুধু শেষের লাইনগুলো মুছে ফেললে (truncation) বাকি শিকল ঠিক থাকে, সেটিও ধরা পড়ে শুধু anchor বা ধারাবাহিক sequence number দিয়ে।

৮ · কোথায় রাখবেন, কতদিন, কত খরচে

পুরোনো হিসাবের খাতার কথা ভাবুন। এই মাসের খাতা টেবিলে, গত বছরের খাতা আলমারিতে, আর দশ বছর আগেরটি গুদামে। টেবিলের খাতা সাথে সাথে পাওয়া যায়, গুদামেরটি আনতে সময় লাগে, কিন্তু জায়গা সস্তা। Log-ও এভাবেই রাখা হয়।

Log কোথায় থাকে, কতক্ষণ

From the source host to hot and cold storage, with a digest anchor kept apart (days are examples)

Log-এর জীবনচক্র: উৎস থেকে hot, cold আর মুছে ফেলা উৎস যন্ত্রের স্থানীয় ফাইলঅল্প সময়, দখল হলে অবিশ্বাস্য কেন্দ্রীয় জমাappend-only, আলাদা admin Anchorhash-এর কপি Hot: ধরুন ৩০ দিনসাথে সাথে খোঁজা, detection চলে, দামি Cold: ধরুন মোট ১ বছরফিরিয়ে এনে খোঁজা, সস্তা, compressed মেয়াদ শেষে মুছে ফেলানথিভুক্ত, legal hold থাকলে বাদ TLS, সাথে সাথে
ছবি ৫৫.১ — প্রতিটি ধাপে log-এর দাম কমে, ফিরে পেতে সময় বাড়ে। দিনের সংখ্যা উদাহরণ, নিয়ম নয়।

Hot storage-এ detection আর দ্রুত খোঁজা চলে। Cold storage তদন্তের জন্য, ফিরিয়ে আনতে সময় বা খরচ লাগতে পারে। Log ফিরিয়ে আনার পরীক্ষাও করে দেখুন। যে archive কখনো খোলা হয়নি, তার ওপর ভরসা করা যায় না। মেয়াদ শেষে মুছে ফেলাও নীতির অংশ। তবে মামলা বা তদন্ত চললে সংশ্লিষ্ট log আলাদা করে রাখতে হতে পারে, একে বলে legal hold.

Retention কীভাবে ঠিক করবেন

Retention তিনটি টানের মাঝখানের সিদ্ধান্ত। তদন্ত চায় বেশি দিন, কারণ অনুপ্রবেশ অনেক সময় দেরিতে ধরা পড়ে (dwell time). Privacy চায় কম দিন, কারণ যা নেই তা ফাঁসও হয় না। আর বিল চায় কম। তাই আগে প্রশ্ন করুন: এই log কোন ঝুঁকির তদন্তে লাগবে? কোনো আইন বা চুক্তি কী বলে? নিচের সংখ্যাগুলো সর্বজনীন নিয়ম নয়, শুধু উদাহরণ।

উৎসকী বলেকার জন্য
CIS safeguard 8.10অন্তত ৯০ দিনস্বেচ্ছায় মানা নিরাপত্তা নিয়ন্ত্রণ
PCI DSS v4.x, Requirement 10১২ মাস, শেষ ৩ মাস সাথে সাথে পাওয়া যাবেকার্ড ডেটা নিয়ে কাজ করা প্রতিষ্ঠান
মার্কিন OMB M-26-14 (মে ২০২৬)৬ মাস খোঁজার যোগ্য, এক বছর ফিরিয়ে আনার যোগ্যমার্কিন ফেডারেল সংস্থা

বাংলাদেশের প্রতিষ্ঠানের জন্য নির্দিষ্ট log retention-এর সময়সীমা এখানে দেওয়া হচ্ছে না, কারণ খাত, চুক্তি আর নিয়ন্ত্রক সংস্থা ভেদে তা আলাদা হতে পারে। পর্ব ৬-এ আইনের কাঠামো দেখুন, আর ব্যক্তিগত উপাত্তের দিক আসবে পর্ব ৭০ (Privacy engineering)-এ। সিদ্ধান্তের আগে নিজের নিয়ন্ত্রক সংস্থার নির্দেশনা আর আইনজীবীর পরামর্শ নিন। এই পর্ব আইনি পরামর্শ নয়।

হিসাব করে দেখুন

একটি কাল্পনিক অনলাইন বাজারের জন্য নিচের হিসাব। সূত্র সরল: দৈনিক GB = events × গড় bytes ÷ 109. স্থির অবস্থায় জমা = দৈনিক GB × দিন। সব দাম ধরে নেওয়া, কোনো প্রদানকারীর আসল দাম নয়। নিজের সংখ্যা বসিয়ে চালিয়ে দেখুন।

// Log volume and retention cost. Every volume and price is ASSUMED, not a quote.
const sources = [           // name, events per day, average bytes
  ['network flows',    40e6,  200],
  ['DNS queries',      20e6,  150],
  ['web and app',      15e6,  500],
  ['endpoint process', 10e6,  600],
  ['cloud audit',       2e6, 1000],
  ['auth and admin',  0.5e6,  400],
];
const PRICE = { ingest: 20, hot: 3, cold: 0.4 }; // assumed taka per GB (hot, cold: per month)
const COLD_RATIO = 5;                            // assumed compression in cold storage

let gbDay = 0, events = 0;
for (const [name, n, bytes] of sources) {
  const gb = n * bytes / 1e9;
  gbDay += gb; events += n;
  console.log(name.padEnd(18), gb.toFixed(1).padStart(5), 'GB/day');
}
console.log('total'.padEnd(18), gbDay.toFixed(1).padStart(5), 'GB/day,',
            Math.round(events / 86400), 'events/s on average');

function monthly(gb, hotDays, coldDays) {
  const ingest = gb * 30 * PRICE.ingest;
  const hot = gb * hotDays * PRICE.hot;
  const cold = gb / COLD_RATIO * coldDays * PRICE.cold;
  return Math.round(ingest + hot + cold);
}
const plans = [
  ['A: hot 30 + cold 335',  gbDay, 30, 335],
  ['B: hot 365',            gbDay, 365, 0],
  ['C: hot 180 + cold 185', gbDay, 180, 185],
  ['D: plan A, flows cut 75%', gbDay - 8 * 0.75, 30, 335],
];
for (const [label, gb, h, c] of plans)
  console.log(label.padEnd(26), 'taka per month:', monthly(gb, h, c));

মোট 26.7 GB/day, গড়ে 1013 events/s. Plan A-র হাতে-হিসাব: ingest ২৬.৭ × ৩০ × ২০ = ১৬,০২০; hot ২৬.৭ × ৩০ × ৩ = ২,৪০৩; cold (২৬.৭ ÷ ৫) × ৩৩৫ × ০.৪ ≈ ৭১৬; মোট প্রায় 19139. সব এক বছর hot রাখলে (Plan B) 45257, প্রায় ২.৪ গুণ। Plan C ঝুঁকি কমায়, দাম 30833. Plan D flow log-কে সারাংশে এনে 14838, তবে তার দাম হলো তদন্তের সূক্ষ্মতা হারানো। লক্ষ করুন, ৬টির মধ্যে auth আর admin log মাত্র ০.২ GB, অথচ তদন্তে এটিই সবচেয়ে দামি। তাই খরচ কমাতে গিয়ে আগে সবচেয়ে বড় উৎসের দিকে তাকান, সবচেয়ে মূল্যবানটির দিকে নয়। Pipeline-ভিত্তিক খরচ কমানোর উপায় Centralized logging-এ আছে।

৯ · যে উৎস চুপ, সে সবচেয়ে বিপজ্জনক

SIEM-এর পর্দা সবুজ থাকলে দুটি অর্থ হতে পারে: কিছু ঘটেনি, অথবা খবর আসা বন্ধ হয়ে গেছে। পাহারাদার ঘুমিয়ে পড়লে মহল্লা শান্তই মনে হয়। তাই দুটি নিয়মিত কাজ দরকার।

  • Log source inventory: একটি তালিকা, কোন system কী log পাঠানোর কথা, মালিক কে। এটি asset inventory-র সাথে মেলালে detection gap বেরিয়ে আসে।
  • Silent source alert: প্রতিটি উৎসের জন্য আলাদা সীমা। DNS resolver ৫ মিনিট চুপ মানে সমস্যা। Admin console কয়েক ঘণ্টা চুপ থাকা স্বাভাবিক।

Log বন্ধ হওয়া নিজেই নিরাপত্তা ঘটনা হতে পারে। ATT&CK-এ audit বন্ধ করা বা log মোছা একটি পরিচিত আচরণ হিসেবে তালিকাভুক্ত। তাই audit নীতি বদলের ঘটনাও alert-এর তালিকায় রাখুন। আবার সাধারণ কারণও হয়: disk ভরে গেছে, certificate-এর মেয়াদ শেষ, format বদলে parser ভেঙেছে। শেষেরটি সবচেয়ে চুপিসারে ঘটে। Parser (log-এর লেখা ভেঙে ক্ষেত্র বের করার program) ভাঙলে log আসছে, কিন্তু ক্ষেত্র ফাঁকা। তাই সংখ্যার পাশাপাশি ক্ষেত্রের মানও পরীক্ষা করুন।

// Log source coverage report. Simulated clock and made-up inventory.
const NOW = 720;  // minutes since 00:00 UTC, simulated (12:00)
const sources = [ // host, log type, longest normal silence (min), last event (min)
  { host: 'web-1',  type: 'authentication', maxGap: 30,  last: 716 },
  { host: 'web-2',  type: 'authentication', maxGap: 30,  last: 655 },
  { host: 'dns-1',  type: 'dns',            maxGap: 5,   last: 719 },
  { host: 'fw-1',   type: 'network-flow',   maxGap: 5,   last: 702 },
  { host: 'db-1',   type: 'data-access',    maxGap: 60,  last: 700 },
  { host: 'admin',  type: 'admin-action',   maxGap: 720, last: 310 },
  { host: 'cloud',  type: 'cloud-audit',    maxGap: 60,  last: 690 },
];
const requiredTypes = ['authentication', 'authorization', 'admin-action',
  'config-change', 'data-access', 'network-flow', 'dns', 'process-exec', 'cloud-audit'];
const inventory = ['web-1', 'web-2', 'dns-1', 'fw-1', 'db-1', 'hr-laptop', 'build-1'];

let silent = 0;
for (const s of sources) {
  const gap = NOW - s.last;
  const state = gap > s.maxGap ? 'SILENT' : 'ok';
  if (state === 'SILENT') silent++;
  console.log(s.host.padEnd(6), s.type.padEnd(15), `gap ${gap}m`.padEnd(10),
              `limit ${s.maxGap}m`.padEnd(11), state);
}
const seenTypes = new Set(sources.map(s => s.type));
const seenHosts = new Set(sources.map(s => s.host));
const noType = requiredTypes.filter(t => !seenTypes.has(t));
const noHost = inventory.filter(h => !seenHosts.has(h));
const covered = inventory.length - noHost.length;

console.log('silent sources:', silent, 'of', sources.length);
console.log('log types with no source:', noType.join(', '));
console.log('assets with no logs:', noHost.join(', '));
console.log(`asset coverage: ${covered}/${inventory.length} = ` +
            `${(100 * covered / inventory.length).toFixed(0)}%`);

silent sources: 2 of 7: web-2 ৬৫ মিনিট আর fw-1 ১৮ মিনিট চুপ। অথচ admin ৪১০ মিনিট চুপ থেকেও ok, কারণ তার সীমা আলাদা। একই সীমা সবার জন্য দিলে হয় ভুয়া alert আসত, নয় আসল বিপদ চাপা পড়ত। শেষের লাইনগুলো আরও বড় কথা বলে: log types with no source: authorization, config-change, process-exec, আর asset coverage: 5/7 = 71%. hr-laptop আর build-1 থেকে কিছুই আসছে না। এই দুটি যন্ত্র কখনো alert দেবে না, কারণ তারা কখনো পাঠায়ইনি। নীরব alert শুধু চলতি উৎস দেখে, inventory দেখায় যা কখনো শুরুই হয়নি।

যিনি পাহারা দেন, তাঁর ওপরও পাহারা, আর কর্মীর privacy

Log দেখায় মানুষ কখন কাজ করলেন, কোন সাইটে গেলেন, কোন ফাইল খুললেন। এটি ক্ষমতা। তাই কয়েকটি নিয়ম মানুন। কর্মীদের আগেই জানান কী লেখা হয় আর কেন। উদ্দেশ্য নিরাপত্তা, এর বাইরে ব্যবহার নয়। Log-এ access সীমিত রাখুন, আর SIEM-এ কে কী খুঁজলেন তারও audit রাখুন। নির্দিষ্ট কর্মীকে নিয়ে তদন্ত হবে অনুমোদিত প্রক্রিয়ায়, ব্যক্তিগত কৌতূহলে নয়। সম্ভব হলে pseudonymization ব্যবহার করুন, তবে মনে রাখবেন এটি পুরো নাম-গোপন করা নয়। নিরাপত্তা সংস্কৃতিতে এর প্রভাব পর্ব ৫৪-এ দেখেছেন: মানুষ নজরদারির ভয় পেলে ভুল রিপোর্ট করা কমে যায়।

আরও গভীরে: Tamper-evident log-এর গবেষণায় Schneier আর Kelsey-র কাজ (১৯৯০-এর দশকের শেষ দিকে) forward integrity-র ধারণা জনপ্রিয় করে: প্রতি ধাপে চাবি বদলে যায়, পুরোনো চাবি মুছে ফেলা হয়। ফলে যন্ত্র দখল হলেও আগের লাইন নীরবে বদলানো যায় না। Crosby আর Wallach (USENIX Security, ২০০৯) Merkle tree-ভিত্তিক log দেখান, যাতে পুরো ফাইল না পড়েই একটি লাইনের প্রমাণ দেওয়া যায়। Certificate Transparency (RFC 6962, ২০১৩) একই ধারণার বিশ্বজুড়ে ব্যবহার, দেখুন transparency log আর Merkle tree.

পরীক্ষা ও ইন্টারভিউতে:

  • একটি নিরাপত্তা log-এ কী কী ক্ষেত্র থাকবে? কে, কী, কখন, কোথায়, কোথা থেকে, ফল।
  • Log-এ UTC কেন? এক সময়রেখায় সব উৎস মেলে, দিবালোক সময়ের সমস্যা থাকে না। দেখানোর সময় বদলানো যায়।
  • যন্ত্রের বাইরে log পাঠানো কেন? দখল হওয়া যন্ত্রের স্থানীয় log মোছা বা বদলানো যায়।
  • Hash chain কী দেয়, কী দেয় না? বদল ধরে, আটকায় না। বাইরের anchor বা চাবি ছাড়া সব hash নতুন করে লেখা যায়।
  • Retention কীভাবে ঠিক হয়? ঝুঁকি, আইন বা চুক্তি, privacy আর খরচ মিলিয়ে, উৎস ভেদে আলাদা।

১০ · AI-এর যুগে log নিয়ে কাজ

AI একটি log format বোঝাতে, awk লাইন বানাতে আর লম্বা log-এর সারাংশ করতে দারুণ দ্রুত। কিন্তু log-এর ক্ষেত্রে তিনটি ঝুঁকি বিশেষ।

AI-এর ভুলকেন বিপজ্জনকযাচাই
Debug-এর জন্য পুরো request বা header log করতে বলেPassword আর token log-এ ঢোকেAllow-list দেখুন, পরীক্ষার log-এ secret খুঁজুন
Retention-এর আইনি সময়সীমা বা standard-এর ধারা বানিয়ে বলেভুল ভরসায় নীতি লেখা হয়মূল নথি নিজে পড়ুন
Log-এ না থাকা ক্ষেত্র বা ঘটনা ধরে নেয়, আত্মবিশ্বাসে রায় দেয়মানুষের বিরুদ্ধে ভুল সিদ্ধান্তপ্রতিটি দাবি log লাইনে মিলিয়ে দেখুন
Parser error ঠিক করতে ক্ষেত্র ফেলে দেওয়া বা error চেপে যাওয়ার কোড দেয়চুপিসারে detection হারায়আগে ও পরের ক্ষেত্রের সংখ্যা মেলান
পুরোনো পরামর্শ: integrity-র জন্য MD5, বা চাবি ছাড়া hash-কেই যথেষ্ট বলামিথ্যা নিশ্চিন্তিপর্ব ১৪ মিলিয়ে নিন

আসল log AI-তে পেস্ট করবেন না। তাতে ব্যক্তিগত তথ্য, ঠিকানা আর secret থাকতে পারে। আগে কাল্পনিক মান বসান, বা শুধু format দিন। তারপর AI-কে পর্যালোচকের ভূমিকায় রাখুন:

তুমি একজন defensive security reviewer. নিচের application logging code পর্যালোচনা করো (সব মান কাল্পনিক): [এখানে কোড, কোনো আসল secret বা ব্যক্তিগত তথ্য ছাড়া] ১. কোনো password, token, কার্ড নম্বর বা বাড়তি ব্যক্তিগত তথ্য log-এ যেতে পারে কি? ২. কে, কী, কখন, কোথায়, কোথা থেকে, ফল: কোন ক্ষেত্র নেই? ৩. Log injection-এর ঝুঁকি আছে কি? কীভাবে ঠিক করব? ৪. প্রতিটি পরামর্শের সাথে OWASP Logging Cheat Sheet-এর কোন অংশ মেলে বলো। নিশ্চিত না হলে "নিশ্চিত নই" লেখো, কোনো ধারা বানিয়ে লিখো না।

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

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

প্র ০১একটি নজরদারি যন্ত্র চুপ হয়ে গেলে কেন তা খারাপ যন্ত্রের চেয়েও বিপজ্জনক? Equifax থেকে কী শেখার আছে?

২০১৭ সালের Equifax ঘটনায় ১৪ কোটির বেশি মানুষের তথ্য ফাঁস হয়েছিল বলে প্রকাশিত হয়। আলোচনায় সাধারণত আসে না-করা patch-এর কথা। কিন্তু মার্কিন প্রতিনিধি পরিষদের একটি কমিটির ২০১৮ সালের রিপোর্ট আরেকটি ব্যর্থতা দেখায়। এনক্রিপ্টেড traffic দেখার যে যন্ত্র ছিল, তার একটি certificate-এর মেয়াদ প্রায় ১৯ মাস আগেই শেষ হয়ে গিয়েছিল। ফলে সেই যন্ত্র নীরবে ওই traffic দেখা বন্ধ করে দেয়। রিপোর্ট অনুযায়ী certificate নবায়নের পরপরই সন্দেহজনক traffic চোখে পড়ে, আর তখনই ঘটনা ধরা পড়ে। হামলাকারীরা ততদিনে দুই মাসের বেশি সময় ভেতরে ছিল।

এখানে কোনো সতর্কবার্তা বাজেনি, কারণ যন্ত্রের কাজই সতর্ক করা, আর সে নিজে থামলে কে সতর্ক করবে? একটি খারাপ যন্ত্র ভুল alert দেয়, মানুষ অন্তত সেটি দেখে। চুপ হয়ে যাওয়া যন্ত্র মিথ্যা নিশ্চিন্তি তৈরি করে। প্রতিষ্ঠান ভাবে সে সুরক্ষিত, অথচ চোখ বন্ধ।

প্রতিকার তিনটি স্তরে। প্রথমত, যন্ত্রের নিজের স্বাস্থ্য পর্যবেক্ষণ: event-এর হার শূন্য হলে alert. দ্বিতীয়ত, certificate-এর মেয়াদের তালিকা আর আগাম সতর্কতা। তৃতীয়ত, পরীক্ষা: নিয়মিত একটি নিরীহ পরীক্ষামূলক ঘটনা তৈরি করে দেখা যে সেটি SIEM পর্যন্ত পৌঁছায় আর alert হয়। অনেকে একে detection test বা synthetic event বলেন। মহল্লার পাহারাদারের কাছে রাতে একবার ফোন করে দেখার মতো, তিনি জেগে আছেন কি না। এই পরীক্ষার ফলও লিখে রাখুন, যাতে পথটি কবে শেষবার কাজ করেছে তা প্রমাণ করা যায়।

মূল উপলব্ধি: নিরাপত্তা ব্যবস্থাও একটি system, তারও নজরদারি লাগে। “কোনো alert নেই” কথাটি শুধু তখনই অর্থপূর্ণ, যখন আপনি প্রমাণ করতে পারেন alert আসার পথটি খোলা আছে।

প্র ০২“যত বেশি log, তত নিরাপদ” — মার্কিন সরকারের নিজের অভিজ্ঞতা এই ধারণা সম্পর্কে কী বলে?

২০২০ সালের SolarWinds ঘটনার পরে তদন্তকারীরা একটি সমস্যায় পড়েন। অনুপ্রবেশ বহু মাস আগের, আর অনেক সংস্থার কাছে সেই সময়ের log ছিল না। এর প্রতিক্রিয়ায় ২০২১ সালের আগস্টে OMB M-21-31 নামের নির্দেশ আসে। সেটি বেশিরভাগ log-এর জন্য ১২ মাস active আর আরও ১৮ মাস cold storage-এর ভিত্তি ঠিক করে, মোট ৩০ মাস। যুক্তিটি বোঝা সহজ: দেরিতে ধরা পড়া ঘটনার তদন্তে পুরোনো log লাগে।

কিন্তু গল্প সেখানেই শেষ হয়নি। ২২ মে ২০২৬ তারিখের OMB M-26-14 স্মারক M-21-31 বাতিল করে। নতুন স্মারক বলে, সংস্থাগুলো এখন একটি নমনীয় কাঠামোতে কাজ করবে, যাতে নজরদারি কার্যকর থাকে আর আমলাতান্ত্রিক ঝামেলা ও খরচ সীমিত থাকে। এর পরিশিষ্টে ন্যূনতম ভিত্তি হলো: ৬ মাস সরাসরি খোঁজার যোগ্য, আর এক বছর ফিরিয়ে আনার যোগ্য। ফোকাস সরে গেছে পরিমাণ থেকে ঝুঁকিভিত্তিক পরিকল্পনা আর ক্ষমতার দিকে।

এই পরিবর্তনের মানে এই নয় যে ৩০ মাস “ভুল” ছিল, বা ৬ মাস সবার জন্য “ঠিক”। এগুলো একটি বিশেষ দেশের সরকারি সংস্থার জন্য লেখা। শিক্ষাটি পদ্ধতিগত। যে log কেউ খুঁজতে পারে না, যা SIEM ভরিয়ে রাখে, আর যার উপকার কেউ বলতে পারে না, তা রাখা সুরক্ষা নয়, খরচ আর ঝুঁকি। অন্যদিকে কম দিন রাখলে দেরিতে ধরা পড়া ঘটনার তদন্ত অসম্ভব হতে পারে। তাই নিজের ঘটনার ইতিহাস, dwell time-এর অনুমান আর বাজেট মিলিয়ে সিদ্ধান্ত নিতে হয়।

মূল উপলব্ধি: Retention কোনো সংখ্যা মুখস্থ করার বিষয় নয়। প্রতিটি log-এর পেছনে একটি প্রশ্ন থাকা চাই: এটি কোন তদন্তের কোন উত্তর দেবে? উত্তর না থাকলে রাখার কারণও নেই।

প্র ০৩Hash chain থাকলে কি log নিরাপদ? কোন আক্রমণ এটি ধরে না, আর গবেষকেরা কীভাবে সমাধান করেছেন?

Hash chain একটি শক্ত কিন্তু সীমিত প্রতিশ্রুতি দেয়: যদি আপনি একটি সঠিক শেষ hash জানেন, তাহলে তার আগের কোনো লাইন ধরা না পড়ে বদলানো যাবে না। এই “যদি”-র ভেতরেই সব সমস্যা। শেষ hash যদি একই যন্ত্রে থাকে, দখলকারী সব লাইন বদলে সব hash নতুন করে লিখতে পারে। এই ধারণাটি পুরোনো। Haber আর Stornetta ১৯৯১ সালে digital নথির সময় প্রমাণের জন্য hash-এর শিকল প্রস্তাব করেন, আর সেখানেও মূল কথা ছিল বাইরের সাক্ষী।

দ্বিতীয় সমস্যা হলো truncation: শেষের কয়েকটি লাইন, ঠিক যেগুলোতে হামলার চিহ্ন, মুছে ফেলা। বাকি শিকল নিখুঁত থাকে। তৃতীয় সমস্যা আরও মৌলিক: Hash chain শুধু জমা হওয়ার পরের বদল ধরে। দখলকারী যদি যন্ত্রটি হাতে পাওয়ার পর log লেখাই বন্ধ করে দেয়, বা মিথ্যা লাইন লেখে, chain সেগুলোকে সত্য বলে সিল করে দেবে। Log-এর শুরুর লেখা যে সত্য, এই প্রতিশ্রুতি hash দিতে পারে না।

গবেষণায় কয়েকটি উত্তর এসেছে। Schneier আর Kelsey-র forward integrity-তে চাবি ধাপে ধাপে বদলায়, ফলে দখলের আগের লাইন নিরাপদ থাকে। Crosby আর Wallach Merkle tree ব্যবহার করে ছোট প্রমাণ দেখান। আর Certificate Transparency-তে স্বাধীন পর্যবেক্ষকেরা log-এর সংস্করণ মিলিয়ে দেখেন, যাতে কেউ দুই জনকে দুই রকম ইতিহাস দেখাতে না পারে। বাস্তবে সবচেয়ে সরল প্রতিকারই সবচেয়ে কার্যকর: সাথে সাথে অন্য যন্ত্রে পাঠানো, যেখানে আলাদা মানুষের নিয়ন্ত্রণ।

মূল উপলব্ধি: Cryptography বিশ্বাসকে সরাতে পারে না, শুধু ছোট একটি জায়গায় নিয়ে আসতে পারে। পুরো log-কে বিশ্বাস না করে আপনি একটি hash আর একটি আলাদা জায়গাকে বিশ্বাস করছেন। প্রশ্ন হলো, সেই জায়গাটি সত্যিই আলাদা কি না।

প্র ০৪Password ভুল করে log-এ ঢুকে গেলে কী করবেন? আর log কি নিজেই আক্রমণের পথ হতে পারে?

এটি কাল্পনিক ঝুঁকি নয়। ২০১৮ সালের মে মাসে Twitter জানায়, একটি bug-এর কারণে password hash হওয়ার আগেই একটি অভ্যন্তরীণ log-এ লেখা হচ্ছিল। প্রতিষ্ঠানটি বলেছিল, অপব্যবহারের প্রমাণ পায়নি, তবে সবাইকে password বদলাতে পরামর্শ দেয়। অর্থাৎ শক্তিশালী hashing থাকলেও একটি log লাইন সব সুরক্ষা পাশ কাটিয়ে গেছে।

এমন হলে করণীয় ক্রমিক। প্রথমে কোড ঠিক করুন, যাতে নতুন লাইন না জন্মায়। তারপর হিসাব করুন secret কোথায় কোথায় গেছে: agent-এর buffer, SIEM, cold storage, backup, dashboard-এর export. Log মুছলেই কাজ শেষ নয়, কারণ append-only ব্যবস্থায় মোছা সহজ নয়, আর ঠিক সেটিই তার গুণ। তাই আসল প্রতিকার হলো secret-কে অকেজো করা: password রিসেট, token বাতিল, key rotate. যারা পড়তে পারতেন তাদের access log দেখুন। ব্যক্তিগত তথ্য হলে আইনি জানানোর দায় আছে কি না যাচাই করুন (পর্ব ৬১ আর পর্ব ৭০).

দ্বিতীয় প্রশ্নের উত্তর দিয়েছে Log4Shell (CVE-2021-44228, ডিসেম্বর ২০২১). জনপ্রিয় Java logging library Log4j-র একটি বৈশিষ্ট্যের কারণে শুধু log-এ লেখা একটি বাইরের string দূর থেকে কোড চালানোর পথ খুলতে পারত। সবার ধারণা ছিল log একটি নিরীহ নিষ্ক্রিয় কাজ, অথচ logger নিজে input ব্যাখ্যা করছিল। শিক্ষাটি হলো, log pipeline-ও একটি attack surface. তাকে patch করতে হবে, least privilege দিতে হবে, আর log-এর লেখাকে অবিশ্বস্ত input ধরতে হবে।

মূল উপলব্ধি: Log দুই দিকেই ধারালো। বাইরে থেকে আসা লেখা log-এ ঢোকে, আর ভেতরের secret log দিয়ে বেরিয়ে যেতে পারে। তাই logging-কে একটি নিরাপত্তা-সংবেদনশীল feature হিসেবে নকশা ও পর্যালোচনা করুন।

প্র ০৫নিরাপত্তার নামে কর্মীদের কতটা log করা যায়? ঠিক-বেঠিকের সীমা কোথায়?

দুটি বৈধ স্বার্থ এখানে মুখোমুখি। প্রতিষ্ঠানকে তথ্য রক্ষা করতে হয়, আর অভ্যন্তরীণ ঝুঁকি বাস্তব। অন্যদিকে কর্মী অফিসে ঢুকেই তাঁর মর্যাদা বা privacy ফেলে আসেন না। ইউরোপীয় মানবাধিকার আদালতের Grand Chamber ২০১৭ সালে Bărbulescu v. Romania মামলায় এই প্রশ্নটি সামনে আনে। রোমানিয়ার একজন কর্মীর কাজের messaging account নজরদারি করা হয়েছিল। আদালত বলে, দেশীয় আদালত যথেষ্ট যাচাই করেনি: কর্মীকে আগে থেকে জানানো হয়েছিল কি না, নজরদারির পরিধি কত, যুক্তিসঙ্গত কারণ ছিল কি না, কম হস্তক্ষেপের উপায় ছিল কি না।

এই মামলা ইউরোপের প্রেক্ষাপটে, বাংলাদেশের আইন নয়। কিন্তু প্রশ্নগুলো ভালো নকশার চেকলিস্ট হিসেবে সব জায়গায় কাজে লাগে। কর্মী কি জানেন? উদ্দেশ্য কি নির্দিষ্ট? কম তথ্যে কি একই কাজ হতো? কে দেখতে পারে, আর সেই দেখার log আছে কি? GDPR-ও একই দিকে ঠেলে: storage limitation আর data minimization. বাংলাদেশের প্রেক্ষাপট দেখুন পর্ব ৬-এ, আর আইনি প্রশ্নে নিজের পরামর্শকের সাথে কথা বলুন।

প্রযুক্তিগত নকশাও সাহায্য করে। প্রতিটি কর্মীর ব্রাউজিং সবার জন্য খোলা না রেখে নির্দিষ্ট ক্ষেত্র pseudonymize করা যায়, যাতে তদন্তের অনুমোদন ছাড়া নাম না খোলে। মনে রাখবেন, শুধু username-এর hash নিলে তালিকা মিলিয়ে সহজে ফিরে পাওয়া যায়, তাই চাবিযুক্ত পদ্ধতি লাগে। আর log-এর পাঠকের ওপরও log রাখুন। এটি analyst-কে সন্দেহ করা নয়, তাঁকে অভিযোগ থেকে রক্ষা করাও বটে।

মূল উপলব্ধি: ভালো logging নীতি বলে, আমরা ঘটনা দেখি, মানুষের জীবন নয়। কর্মী যদি নীতিটি জানেন এবং ন্যায্য মনে করেন, তিনিই সবচেয়ে ভালো সেন্সর হয়ে ওঠেন। ভয় থেকে নীরবতা জন্মায়।

অনুশীলন

হিসাব আর নকশা, দুটিই আছে। আগে নিজে চেষ্টা করুন।

  1. হিসাব: ৪০টি server, প্রতিটি দিনে ২০ লাখ event, গড়ে ৩০০ bytes. (ক) দৈনিক GB, (খ) গড় events/s, (গ) hot ৩০ দিন আর cold ৩৩৫ দিনে (cold-এ ৪:১ compression) জমা, (ঘ) ধরে নেওয়া দাম hot ৳৩ আর cold ৳০.৪ প্রতি GB-মাস ধরে মাসিক storage খরচ বের করুন।

    (ক) মোট event = ৪০ × ২০,০০,০০০ = ৮ কোটি। ৮০,০০০,০০০ × ৩০০ ÷ ১০৯ = ২৪ GB/দিন.

    (খ) ৮০,০০০,০০০ ÷ ৮৬,৪০০ ≈ ৯২৬ events/s. মনে রাখবেন এটি গড়, চূড়া আরও বেশি হয়।

    (গ) Hot: ২৪ × ৩০ = ৭২০ GB. Cold: (২৪ ÷ ৪) × ৩৩৫ = ৬ × ৩৩৫ = ২,০১০ GB.

    (ঘ) ৭২০ × ৩ = ২,১৬০ আর ২,০১০ × ০.৪ = ৮০৪, মোট ৳২,৯৬৪ প্রতি মাসে. দামগুলো অনুমান, আসল বিল প্রদানকারী আর ingest খরচের ওপর নির্ভর করে।

  2. আউটপুট অনুমান করুন: a.log-এ পাঁচটি লাইন: তিনটি sshd: Failed password for rafi from 203.0.113.9 port 4000 ssh2, একটি sshd: Failed password for tania from 198.51.100.4 port 4001 ssh2, একটি sshd: Accepted password for rafi from 203.0.113.9 port 4002 ssh2. এই command কী ছাপবে? awk '/Failed/ {print $(NF-3)}' a.log | sort | uniq -c | sort -k1,1nr
          3 203.0.113.9
          1 198.51.100.4

    /Failed/ চারটি লাইন নেয়, Accepted লাইনটি বাদ। প্রতিটির শেষ থেকে চতুর্থ field হলো IP. sort একই মান পাশাপাশি আনে, uniq -c গোনে, শেষ sort বড় সংখ্যা ওপরে আনে। uniq-এর আগে sort না থাকলে অ-পাশাপাশি মান আলাদা গোনা হতো।

  3. Critique: এই log লাইনের সমস্যা খুঁজুন আর ঠিক করে লিখুন: 31/10 08:10 login ok rafi pass=example-pass card=4111111111111111 token=example-token
    • Secret: Password আর token থাকা চলবে না। এখানে মানগুলো নকল, আসল হলে এটি নিজেই ফাঁস।
    • কার্ড: পূর্ণ নম্বর চলবে না। login-এ এর কোনো প্রয়োজনই নেই।
    • সময়: বছর, সেকেন্ড আর time zone নেই।
    • প্রসঙ্গ: উৎস, পদ্ধতি, system আর request id নেই। Free text তাই parse করা কঠিন।

    ঠিক করা রূপ (নকল মান):

    {"ts":"2026-10-31T02:10:00Z","event":"login","result":"success","user_id":"u-1042","src":"198.51.100.7","method":"password+totp","host":"web-1","request_id":"req-7f31"}
  4. নকশা: একটি কাল্পনিক ২০ জনের অনলাইন দোকান: একটি web server, একটি database, cloud account আর কয়েকটি ল্যাপটপ। বাজেট কম। প্রথম ধাপের logging পরিকল্পনা লিখুন: কোন ৫টি উৎস, কোথায় যাবে, কতদিন, কোন alert.

    একটি যুক্তিসঙ্গত উত্তর, একমাত্র নয়:

    • উৎস: App login ও admin কাজ, server-এর auth log আর sudo, database-এ সংবেদনশীল টেবিলের access, cloud audit trail, DNS বা firewall-এর log, যা সস্তায় পাওয়া যায়।
    • কোথায়: সব যন্ত্রের বাইরে একটি আলাদা account বা server-এ, TLS-এ। সেখানে web server-এর admin-এর মোছার অধিকার নেই।
    • কতদিন: ধরুন ৩০ দিন hot আর অন্তত ৯০ দিন মোট (CIS-এর সর্বনিম্ন), কার্ড ডেটা নিজে সামলালে PCI DSS মিলিয়ে বেশি। আইন ও চুক্তি আলাদা করে দেখুন।
    • Alert: অল্প সময়ে অনেক ব্যর্থতার পর সফল login, নতুন admin, audit বন্ধ করা, আর প্রতিটি উৎস নির্দিষ্ট সময়ের বেশি চুপ।

    ল্যাপটপের process log পরের ধাপে রাখা যায়, তবে সেই ফাঁকটি লিখে রাখুন, যাতে তা জানা ঝুঁকি হয়, অজানা নয়।

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

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

ক্রমএকটি login event-এর যাত্রা সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. App allow-list ক্ষেত্র দিয়ে JSON লাইন লেখে
  2. Agent লাইনটি পড়ে host আর পড়ার সময় যোগ করে
  3. TLS-এ collector-এ পাঠানো হয়, যন্ত্রের বাইরে যায়
  4. ক্ষেত্রের নাম common schema-তে আনা হয়
  5. SIEM-এ জমা হয়, detection rule চলে

একটি দখল হওয়া server থেকে সাথে সাথে log অন্য যন্ত্রে পাঠানোর প্রধান নিরাপত্তা লাভ কোনটি?

  • Server-এর disk-এ জায়গা বাঁচে
  • হামলাকারী server-এ ঢুকতেই পারে না
  • পাঠানো লাইন দখলকারীর নাগালের বাইরে থাকে
  • যন্ত্রের ঘড়ি নিজে থেকে ঠিক হয়ে যায়

একটি hash chain-এ শেষ hash একই ফাইলের সাথে একই server-এ রাখা। Root পাওয়া একজন দখলকারী একটি লাইন বদলে সব hash নতুন করে লিখল। স্থানীয় যাচাইয়ে কী হবে?

  • ব্যর্থ হবে, কারণ SHA-256 ভাঙা যায় না
  • পাস করবে, তাই বাইরে রাখা anchor বা চাবি দরকার
  • শুধু প্রথম লাইনে ব্যর্থ হবে
  • ফাইলটি নিজে থেকে মুছে যাবে

একটি app-এর ঘড়ি ১২০ সেকেন্ড পিছিয়ে চলছে (offset = −১২০ s). Log-এ সময় লেখা আছে 02:08:30Z. সত্য সময় কত?

  • 02:08:30Z
  • 02:06:30Z
  • 02:09:30Z
  • 02:10:30Z

Login ব্যর্থ হলে application log-এ কোনটি সবচেয়ে ভালো?

  • user_id, result=failure, reason, src_ip, UTC সময়
  • Username আর যে password দেওয়া হয়েছিল
  • পুরো HTTP request body
  • শুধু “login failed” লেখা

দিনে ১০ GB log, hot-এ ৩০ দিন। স্থির অবস্থায় hot-এ কত জমা থাকবে, আর প্রতি GB-মাস ধরে নেওয়া ৳৩ হলে মাসিক খরচ কত?

  • ১০ GB, ৳৩০
  • ৩০ GB, ৳৯০
  • ৩০০ GB, ৳৯০০
  • ৩,৬৫০ GB, ৳১০,৯৫০

একটি SOC দল দেখল, একটি firewall থেকে গত এক ঘণ্টায় কোনো event আসেনি, যদিও স্বাভাবিকভাবে প্রতি মিনিটে আসে। সঠিক প্রথম ভাবনা কোনটি?

  • Network শান্ত, কোনো সমস্যা নেই
  • এটি একটি detection gap, কারণ খুঁজে যাচাই করতে হবে
  • নিশ্চিতভাবে হামলা চলছে, সব বন্ধ করতে হবে
  • Detection rule মুছে নতুন লিখতে হবে

শব্দকোষ

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

মনে রাখুন

  1. Log রক্ষকের স্মৃতি: কে, কী, কখন, কোথায়, কোথা থেকে, ফল.
  2. Password, token, পূর্ণ কার্ড নম্বর আর বাড়তি ব্যক্তিগত তথ্য কখনো নয়; ক্ষেত্র ঠিক হবে allow-list দিয়ে।
  3. সবাই UTC আর মেলানো ঘড়িতে, এক schema-য়; মূল সময় মুছবেন না।
  4. সাথে সাথে যন্ত্রের বাইরে, append-only, আর hash chain-এর জন্য বাইরে anchor.
  5. Retention হলো ঝুঁকি, আইন, privacy আর খরচের হিসাব। আর নীরব উৎসের alert ছাড়া সবুজ পর্দার অর্থ নেই।

পরের পর্বে: Log এখন জমা হচ্ছে। এবার সেই log থেকে আসল ঘটনা ধরা: SIEM, Sigma rule, correlation আর false positive কমানো।

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

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