এই পর্বে যা শিখবেন
- Software supply chain-এর পাঁচটি জোড়া আর আপসের পাঁচটি সাধারণ ধরন
- SolarWinds, Log4Shell, event-stream, xz আর Polyfill থেকে প্রতিরক্ষার শিক্ষা
- Lockfile, hash pinning, private registry, scope আর update bot ঠিকভাবে ব্যবহার
- SCA-র ফল পড়া, transitive ঝুঁকি আর reachability বুঝে অগ্রাধিকার ঠিক করা
- SBOM বানানো ও কাজে লাগানো, VEX দিয়ে অপ্রয়োজনীয় সতর্কতা কমানো
- Sigstore, provenance আর SLSA v1.2-এর level, আর build pipeline শক্ত করা
- একটি dependency আপস হলে ধাপে ধাপে কী করবেন
১ · Supply chain কী — আপনার কোডের পেছনের লম্বা শিকল
একটি বিরিয়ানির দোকানের কথা ভাবুন। বাবুর্চি নিজে হাতে রান্না করেন, রান্নাঘর ঝকঝকে। কিন্তু চাল আসে আড়ত থেকে, মসলা আসে বাজার থেকে, মাংস আসে কসাইয়ের কাছ থেকে, আর খাবার পৌঁছায় ডেলিভারির ছেলের হাতে। এর যেকোনো এক জায়গায় ভেজাল ঢুকলে খারাপ খাবারের দায় পড়ে দোকানের নামে। ক্রেতা তো আড়তদারকে চেনেন না।
Software supply chain ঠিক এই পথ। আপনি হয়তো দুই হাজার লাইন কোড লিখেছেন, কিন্তু আপনার পণ্য চলে হাজার হাজার dependency-র লাখো লাইনের ওপর। সেগুলো এসেছে অচেনা মানুষের কাছ থেকে, চলেছে আপনার build মেশিনে, আর পৌঁছেছে আপনার গ্রাহকের কাছে। Supply chain attack মানে সরাসরি আপনাকে না ধরে এই পথের কোনো বিশ্বস্ত জোড়াকে ধরা। OWASP Top 10:2025-এ Software Supply Chain Failures তৃতীয় স্থানে আছে।
শিকলের পাঁচটি জোড়া মনে রাখুন। Source হলো আপনার repository. Dependency হলো বাইরে থেকে আসা package, যা আসে package registry থেকে। Build হলো CI/CD pipeline, যা কোড থেকে পণ্য বানায়। Artifact হলো সেই তৈরি পণ্য: package, container image বা binary. Deploy হলো সেটি production-এ বসানো আর update পৌঁছে দেওয়া।
শিকলের পাঁচ জোড়া: কোথায় ঝুঁকি, কোথায় বাধা
Five links of the chain, the risk at each, and the control that fits
কেন এই পথটি রক্ষকের জন্য কঠিন? পর্ব ৪-এর ভাষায়, প্রতিটি dependency একটি trust boundary পেরিয়ে আসে, অথচ চলে আপনার কোডের সমান অধিকারে। আপনার সার্ভারে বসা একটি ছোট date library-ও একই process-এ চলে, একই secret পড়তে পারে। আর সংখ্যার হিসাবটিও সরল। ধরি প্রতিটি package-এর বছরে আপস হওয়ার সম্ভাবনা ০.১% (অনুমিত সংখ্যা, মাপা তথ্য নয়), আর ঘটনাগুলো স্বাধীন। তাহলে অন্তত একটি আপসের সম্ভাবনা ১ − (১ − p)n:
| মোট package (n) | হিসাব | অন্তত একটি আপস |
|---|---|---|
| ১০০ | ১ − ০.৯৯৯১০০ | ≈ ৯.৫% |
| ৩০০ | ১ − ০.৯৯৯৩০০ | ≈ ২৫.৯% |
| ১,০০০ | ১ − ০.৯৯৯১০০০ | ≈ ৬৩.২% |
বাস্তবে সম্ভাবনা সব package-এ সমান নয়, ঘটনাগুলো স্বাধীনও নয়। তবু চেহারাটি সত্য: dependency-র সংখ্যা attack surface-এর অংশ।
সীমা স্পষ্ট: এই পর্বের সব কোড পাতার ভেতরের খেলনা ডেটায় চলে। কোনো registry-তে অনুরোধ যায় না। আসল নামের কাছাকাছি নামে package প্রকাশ করা, অন্যের প্রতিষ্ঠানের নামে “পরীক্ষা” চালানো বা অন্যের pipeline খোঁচানো নিরীহ কৌতূহল নয়। পরীক্ষা হবে নিজের সিস্টেমে অথবা লিখিত অনুমতিতে। সীমা আর দায়িত্বশীল প্রকাশ নিয়ে পড়ুন পর্ব ৬. এটি আইনি পরামর্শ নয়।
২ · আপসের পাঁচটি পথ — শিকল কোথায় ভাঙে
এখানে শুধু ধারণা। হামলাকারীর দৃষ্টিতে “কেন কাজ করে”, আর রক্ষকের দৃষ্টিতে “কীভাবে থামে আর কীভাবে ধরা পড়ে”। এর বাইরের কোনো ধাপ এই কোর্সে নেই।
| ধরন | কেন কাজ করে | প্রতিরোধ | ধরার সংকেত |
|---|---|---|---|
| Typosquatting | মানুষ বানান ভুল করেন, AI নাম বানিয়ে ফেলে | অনুমোদিত তালিকা, নাম-মিলের যাচাই | নতুন, কম ব্যবহৃত, চেনা নামের কাছাকাছি package |
| Dependency confusion | একাধিক উৎস থাকলে package manager ভুল উৎস বেছে নিতে পারে | একটিমাত্র registry, scope, ভেতরের নাম সুরক্ষিত | ভেতরের নামের package বাইরের উৎস থেকে আসা |
| Maintainer account takeover | একটি দুর্বল login পুরো package-এর চাবি | Maintainer-এর MFA, trusted publishing, cooldown | হঠাৎ নতুন version, নতুন install script |
| Malicious update | পুরোনো বিশ্বাস নতুন version-এ চলে আসে | Pinning, lockfile diff review, ধাপে rollout | নতুন transitive dependency, অচেনা network আচরণ |
| Build system compromise | Build-এর ফল সবার কাছে বিশ্বস্ত, স্বাক্ষরও পায় | Ephemeral runner, কম অধিকার, provenance | Source আর artifact না মেলা, build-এ অচেনা egress |
Dependency confusion-এর ধারণাটি ২০২১ সালে একজন গবেষকের প্রকাশিত কাজের পর ব্যাপকভাবে আলোচনায় আসে। রোগটি নকশার: প্রাইভেট আর public দুটোই দেখা, তারপর যেটির version বড় সেটি নেওয়ার মতো আচরণ। ওষুধের দোকানে মালিকের নিয়ম হলো, হাসপাতালের স্টোর আর বাইরের পাইকার দুই জায়গাতেই খুঁজে যেটি নতুন সেটিই আনতে হবে। ভুল জিনিস ঢোকার রাস্তা এখানেই। সমাধানও নকশার: উৎস একটি, আর নামের মালিকানা স্পষ্ট।
Typosquatting ধরার একটি সরল উপায় edit distance: একটি নামকে আরেকটিতে বদলাতে কম করে কয়টি অক্ষর-বদল লাগে। fast-json থেকে fast-jsno হয় শেষের দুই অক্ষর অদলবদল করে। পাশাপাশি দুই অক্ষরের অদলবদলকে ১ ধরলে দূরত্ব ১. সাধারণ Levenshtein হিসাবে এটি ২, কারণ দুটি অক্ষরই বদলাতে হয়। নিচের কোড একটি রক্ষকের intake যাচাই: কেউ নতুন package চাইলে আগে এই দরজা পেরোতে হয়। সব নাম কাল্পনিক, কোনো registry-তে অনুরোধ যায় না।
// Defender's intake check on fictional names. No registry is contacted.
const approved = ['fast-json', 'date-lite', 'web-router', 'http-client'];
const requests = [
{ name: 'fast-json', ageDays: 2900 },
{ name: 'fast-jsno', ageDays: 3 },
{ name: 'fastjson', ageDays: 12 },
{ name: 'web-rooter', ageDays: 40 },
{ name: 'date-time', ageDays: 3100 },
{ name: 'image-resize', ageDays: 1500 },
];
// Edit distance: insert, delete, replace, or swap two neighbours = 1 edit.
function dist(a, b) {
const d = Array.from({ length: a.length + 1 }, (_, i) => [i]);
for (let j = 0; j <= b.length; j++) d[0][j] = j;
for (let i = 1; i <= a.length; i++) for (let j = 1; j <= b.length; j++) {
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost);
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1])
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
}
return d[a.length][b.length];
}
const norm = s => s.replace(/[-_.]/g, '');
for (const r of requests) {
if (approved.includes(r.name)) { console.log(`${r.name.padEnd(13)} APPROVED`); continue; }
const near = approved.map(p => ({ p, e: Math.min(dist(r.name, p), dist(norm(r.name), norm(p))) }))
.sort((x, y) => x.e - y.e)[0];
let verdict = 'NEW: normal review';
if (near.e <= 2) verdict = r.ageDays < 90 ? 'HOLD: human must check' : 'CHECK: old but similar';
console.log(`${r.name.padEnd(13)} near ${near.p} edits=${near.e} age=${r.ageDays}d -> ${verdict}`);
}আউটপুট:
fast-json APPROVED
fast-jsno near fast-json edits=1 age=3d -> HOLD: human must check
fastjson near fast-json edits=0 age=12d -> HOLD: human must check
web-rooter near web-router edits=1 age=40d -> HOLD: human must check
date-time near date-lite edits=2 age=3100d -> CHECK: old but similar
image-resize near date-lite edits=7 age=1500d -> NEW: normal review
fast-jsno অদলবদলের কারণে দূরত্ব ১, আর বয়স মাত্র ৩ দিন, তাই আটকে গেল। fastjson-এ চিহ্ন বাদ দিলে দূরত্ব ০: -, _ আর . আলাদা করে দেখলে এটি ধরা পড়ত না, তাই norm ধাপটি আছে। date-time লক্ষ করুন। ৩,১০০ দিন পুরোনো, দূরত্ব ২. এটি সম্ভবত আসল package, তাই শুধু “CHECK”. এটি false positive-এর চেহারা, আর সেজন্যই শেষ সিদ্ধান্ত মানুষের। এই check তিনটি জিনিস পারে না: অনুমোদিত তালিকায় নেই এমন নামের নকল ধরা, পুরোনো package-এর ক্ষতিকর update ধরা, আর dependency confusion ধরা।
৩ · প্রকাশিত পাঁচ ঘটনা আর তাদের শিক্ষা
নিচের তথ্য প্রকাশিত প্রতিবেদন আর advisory-র স্তরে। কে করেছে সেটি এখানে প্রশ্ন নয়, কারও নামও নেই। প্রশ্ন একটিই: কোন বাধা থাকলে ক্ষতি কমত?
| ঘটনা | শিকলের জোড়া | প্রকাশিত প্রতিবেদনের সারকথা | রক্ষকের শিক্ষা |
|---|---|---|---|
| SolarWinds, ২০২০ | Build, update | একটি network-management পণ্যের update-এ ক্ষতিকর অংশ ঢোকে, আর সেটি প্রকাশকের স্বাক্ষর নিয়েই পৌঁছায়। প্রতিবেদনে build-পর্যায়ের অনুপ্রবেশের কথা আছে। | স্বাক্ষর প্রকাশক চেনায়, নিরাপত্তা প্রমাণ করে না। Build আলাদা রাখুন, monitoring tool-কেও কম অধিকার আর সীমিত egress দিন। |
| Log4Shell, ২০২১ | Dependency | CVE-2021-44228. এটি আপস নয়, বহুল ব্যবহৃত Log4j 2 library-র গুরুতর দুর্বলতা। অনেক প্রতিষ্ঠান জানতই না library-টি তাদের কোথায় আছে। | Inventory আগে থেকে রাখুন। Transitive অংশও ধরুন। Egress সীমিত হলে ক্ষতি কমে (পর্ব ৩২)। |
| event-stream, ২০১৮ | Dependency, maintainer | একটি জনপ্রিয় npm package-এর দায়িত্ব নতুন একজনের হাতে যায়। পরে যোগ হওয়া একটি dependency-তে একটি নির্দিষ্ট cryptocurrency wallet-কে লক্ষ্য করা ক্ষতিকর অংশ ধরা পড়ে। | দায়িত্ব বদল একটি ঝুঁকির সংকেত। Lockfile diff-এ নতুন transitive dependency খেয়াল করুন। |
| xz, ২০২৪ | Source, release | CVE-2024-3094. xz-এর 5.6.0 আর 5.6.1 release-এ backdoor ধরা পড়ে। প্রতিবেদন অনুযায়ী দীর্ঘ সময় ধরে বিশ্বাস গড়া হয়েছিল, আর release ফাইলে এমন অংশ ছিল যা repository-র সাধারণ দৃশ্যে ছিল না। একজন developer SSH-এর অস্বাভাবিক ধীরগতি দেখে অনুসন্ধান করে এটি ধরেন, বড় আকারে ছড়ানোর আগেই। | Release ফাইল আর source মিলিয়ে দেখুন, reproducible build রাখুন, কম লোকের চালানো জরুরি project-কে সহায়তা দিন। অস্বাভাবিকতার পেছনে যাওয়াও একটি control. |
| Polyfill, ২০২৪ | বিতরণ, third-party script | একটি জনপ্রিয় CDN সেবার domain-এর মালিকানা বদলের পর সেখান থেকে ক্ষতিকর script ছড়ানোর প্রতিবেদন আসে। এক লাখের বেশি সাইট প্রভাবিত বলে জানানো হয়। Sansec-এর প্রতিবেদন এটি সামনে আনে; পুরোনো সেবাদাতা অভিযোগ অস্বীকার করেন। | Domain-এর মালিকও শিকলের অংশ। বাইরের live script কমান, সম্ভব হলে নিজের সার্ভারে রাখুন (পর্ব ৪৪)। |
ঘটনাগুলো একসাথে একটি নকশা দেখায়। SolarWinds আর xz-এ স্বাক্ষর বা hash যাচাই পাস করত, কারণ ক্ষতিকর অংশ আগেই ঢুকেছিল। Log4Shell-এ দরকার ছিল inventory আর দ্রুত patch. event-stream-এ দরকার ছিল সতর্ক update. অর্থাৎ কোনো একটি tool পাঁচটি ঘটনার সবকটি থামায় না। এখান থেকে একটি টানাপোড়েনও আসে: Log4Shell বলে দ্রুত update করুন, event-stream বলে ধীরে update করুন। এর সমাধান পরের অংশে।
৪ · Dependency-র পরিচ্ছন্নতা — lockfile, hash আর registry
রান্নাঘরের নিয়ম সহজ: চেনা আড়ত থেকে কিনুন, রসিদ রাখুন, প্রতিটি বস্তার সিল মিলিয়ে নিন, আর যা লাগে না তা কিনবেন না। Dependency-র নিয়মও এমন।
| অভ্যাস | কী থামায় | যা থামায় না |
|---|---|---|
Lockfile commit করা, CI-তে npm ci ধরনের কড়া install | হঠাৎ অন্য version আসা | Lock করার সময়ই খারাপ version থাকলে |
| Hash pinning | একই version-এর bytes বদলানো | Hash নেওয়ার আগেই ক্ষতিকর থাকলে |
| Private registry বা proxy, scope | Dependency confusion, অননুমোদিত package | অনুমোদিত package-এর ক্ষতিকর update |
| Update bot, release cooldown | পুরোনো হয়ে থাকা, নতুন release-এর প্রথম দিনের ঝুঁকি | দীর্ঘদিন লুকিয়ে থাকা ক্ষতিকর অংশ |
| Dependency review | নতুন package, install script, বড় diff চোখে পড়া | সুপরিকল্পিত, লুকানো কোড সবসময় নয় |
| কম dependency | পুরো attack surface ছোট হয় | যেগুলো থাকল তাদের ঝুঁকি |
একটি lockfile দেখতে কেমন? npm-এর package-lock.json-এ প্রতিটি package-এর integrity মান থাকে, যা SRI-র মতো একটি hash (পর্ব ৪৪)। Python-এ pip-এর hash-checking mode প্রতিটি package-এ hash চায়। go.sum আর Cargo.lock-ও একই কাজ করে। নিচে দুটি উদাহরণ, মান কাল্পনিক:
# সব package একটি নিয়ন্ত্রিত proxy দিয়ে আসবে
registry=https://npm.internal.example/
# @shop scope-এর package শুধু ভেতরের registry-তে খোঁজা হবে
@shop:registry=https://npm.internal.example/
# Package বসানোর সময় script চলবে না (কিছু native package-এ আলাদা ছাড় লাগতে পারে)
ignore-scripts=true# চালান: pip install --require-hashes -r requirements.txt
date-lite==2.1.4 \
--hash=sha256:<64-hex-digest-from-your-lock-tool>
# একাধিক index মেশানো এড়িয়ে চলুন; --index-url একটিই রাখুননিচের Python কোড সত্যিকারের SHA-256 দিয়ে lock যাচাই করে, তবে bytes নকল আর মেমরির ভেতরে। একটি package-এ এক byte বদলানো হয়েছে, একটি lockfile-এ নেই। আর একটি package ইচ্ছা করে রাখা হয়েছে, যার খারাপ কোড lock করার সময়ই ছিল।
# Real SHA-256 on fake artifact bytes held in memory. Nothing is downloaded.
import hashlib
def sha256(data):
return hashlib.sha256(data).hexdigest()
# Bytes the team reviewed and locked earlier.
reviewed = {
"date-lite-2.1.4.tgz": b"fake package bytes: date-lite 2.1.4\n",
"fast-json-3.4.0.tgz": b"fake package bytes: fast-json 3.4.0\n",
"web-router-1.9.2.tgz": b"fake package bytes: web-router 1.9.2 (bad code nobody noticed)\n",
}
lock = {name: sha256(data) for name, data in reviewed.items()}
# Bytes the mirror serves today. One changed byte, one extra file.
served = dict(reviewed)
served["fast-json-3.4.0.tgz"] = b"fake package bytes: fast-json 3.4.0!\n"
served["left-util-1.0.0.tgz"] = b"fake package bytes: left-util 1.0.0\n"
failed = 0
for name, data in sorted(served.items()):
got = sha256(data)
want = lock.get(name)
if want is None:
status = "REJECT: not in lockfile"
elif got != want:
status = "REJECT: hash mismatch"
else:
status = "ok"
failed += status != "ok"
print(f"{name:22} {got[:16]} {status}")
if want and got != want:
print(f"{'':22} {want[:16]} (expected)")
print(f"failed={failed} of {len(served)}; install {'stopped' if failed else 'continues'}")আউটপুট:
date-lite-2.1.4.tgz cd2498d8c8da7d0a ok
fast-json-3.4.0.tgz 5b5d866291310754 REJECT: hash mismatch
49e9f60e4e4c645d (expected)
left-util-1.0.0.tgz 0e22845eb6c53d89 REJECT: not in lockfile
web-router-1.9.2.tgz adfe0a70b7943d9e ok
failed=2 of 4; install stopped
fast-json-এ শুধু একটি ! যোগ হয়েছে, অথচ hash পুরো বদলে গেছে: এটি avalanche effect (পর্ব ৯)। Lockfile-এর বাইরের ফাইলও আটকে গেল। কিন্তু web-router দেখুন। এর bytes-এ “bad code” লেখা, তবু ফল ok, কারণ lock করা হয়েছিল সেই bytes-ই। Lockfile বলে “যা রিভিউ করেছিলেন, এটি সেটিই”। “যা রিভিউ করেছিলেন তা ভালো”, এ কথা বলে না। আসল জীবনে একই version-এর hash বদলে যাওয়া খুব গুরুতর সংকেত। Hash মুছে আবার lock করে ফেলা তাই ভুল সমাধান।
দ্রুত, না ধীরে? Update-এর টানাপোড়েন
নিয়মটি দুই ভাগে ভাগ করুন। সাধারণ update ধীরে আসুক: update bot pull request খুলবে, test চলবে, মানুষ দেখবে। কিছু tool-এ নতুন release নেওয়ার আগে কয়েক দিন অপেক্ষার setting আছে, যাকে এখানে release cooldown বলছি। অনেক ক্ষতিকর release প্রকাশের অল্প সময়ের মধ্যে ধরা পড়ে বলে প্রকাশিত ঘটনায় দেখা গেছে, তাই এই অপেক্ষা কাজের। নিরাপত্তা update আলাদা পথে আসুক: KEV বা নিশ্চিত reachable দুর্বলতায় cooldown বাদ, দ্রুত review, দ্রুত ধাপে ধাপে rollout. Bot-কে production-এ সরাসরি auto-merge করতে না দেওয়াই ভালো। নীতি লিখে রাখুন, যাতে সংকটের দিনে তর্ক করতে না হয়।
নতুন dependency নেওয়ার আগে নিজেকে জিজ্ঞেস করুন: এটি কি দশ লাইনে নিজে লেখা যায়? কতজন রক্ষণাবেক্ষণ করেন? শেষ release কবে? এটি কতগুলো transitive dependency আনে? install script আছে কি? OpenSSF Scorecard এখানে কাজে লাগে। এটি একটি open source project-এর branch protection, code review, pinned dependency, token permission, signed release ইত্যাদি স্বয়ংক্রিয়ভাবে দেখে ০ থেকে ১০ নম্বর দেয়। নম্বর অভ্যাসের ইঙ্গিত, নিরাপত্তার প্রমাণ নয়। কম নম্বর মানে আরও প্রশ্ন, বেশি নম্বর মানে পরীক্ষা বাদ নয়।
এবার একটি package-কে registry থেকে production পর্যন্ত অনুসরণ করুন। “পরে” চাপুন, আর প্রতিটি ধাপে কোন যাচাই হচ্ছে দেখুন। সব মান কাল্পনিক।
- Registryপ্রকাশ
- Intakeঅনুমোদন
- LockfilePR-এ review
- CIBuild ও scan
- SignProvenance
- Deployযাচাই করে চালু
package date-lite 2.1.4 published 41 days ago maintainers 3 install script: none
name similarity exact match on approved list
known advisories 0
scorecard (toy) 7.4 / 10
proxy copy stored in npm.internal.example
decision: allowed
+ date-lite 2.1.4 + integrity sha512-<example-value> new transitive packages: 0 reviewer: approved
npm ci --ignore-scripts integrity ok tests 212 passed SCA findings 0 reachable SBOM generated
image shop-api@sha256:64f28b2e... sign short-lived certificate log transparency log entry saved attach provenance + SBOM
signature valid
builder identity expected workflow
source example/shop-api v1.4.2
decision: deploy to 5% first
- ধাপ ১ · Registry.
date-lite 2.1.4public registry-তে আছে। ৪১ দিন পুরোনো, ৩ জন maintainer, install script নেই। এগুলো শুধু তথ্য, এখনো কিছু আপনার সিস্টেমে আসেনি। - ধাপ ২ · Intake আর proxy. নাম হুবহু অনুমোদিত তালিকায় মিলেছে, জানা advisory ০টি, Scorecard ৭.৪. অনুমোদনের পর একটি কপি ভেতরের proxy-তে রাখা হলো। এরপর আপনি বাইরের registry-র ওপর সরাসরি নির্ভর করছেন না।
- ধাপ ৩ · Lockfile আর review. Pull request-এ version আর integrity hash যোগ হলো। Reviewer দেখলেন নতুন transitive package ০টি। এই diff পড়াই এখানে আসল কাজ।
- ধাপ ৪ · CI. নতুন ephemeral runner-এ
npm ci --ignore-scriptsচলল, hash মিলল, ২১২টি test পাস। SCA-তে reachable কিছু নেই। SBOM তৈরি হলো। - ধাপ ৫ · Signing. আলাদা release job image স্বাক্ষর করল, রেকর্ড public log-এ গেল, আর provenance ও SBOM image-এর সাথে যুক্ত হলো।
- ধাপ ৬ · Deploy. Admission control স্বাক্ষর, builder-এর পরিচয় আর source মিলিয়ে দেখল। সব ঠিক, তবু প্রথমে ৫% ট্রাফিকে। ছয়টি দরজার যেকোনো একটিতে ব্যর্থ হলে package production-এ পৌঁছাত না।
৫ · SCA আর transitive ঝুঁকি — কোনটি আসলে আপনাকে ছোঁয়
SCA (Software Composition Analysis) tool আপনার lockfile পড়ে, আর প্রতিটি package-কে advisory তালিকার সাথে মেলায়। উদাহরণ হিসেবে npm audit, pip-audit, OSV-Scanner, OWASP Dependency-Check, Trivy বা Grype-এর নাম করা যায়। এটি অনেকটা গ্রাহকের তালিকা নিয়ে ব্যাংকের কালো তালিকা মেলানোর মতো। একটি সীমা শুরুতেই মনে রাখুন: SCA জানা সমস্যা খোঁজে। নতুন ক্ষতিকর package, আর কপি করে বসানো কোড সে ধরতে নাও পারে।
আসল ঝুঁকি থাকে গভীরে। আপনি ৩টি package যোগ করেছেন, সেগুলো আরও অনেক এনেছে। Advisory এলে দুটি প্রশ্ন: এটি আমার সিস্টেমে কোন পথে এসেছে? আর দুর্বল function কি আমি ডাকছি? দ্বিতীয় প্রশ্নের নাম reachability. নিচের walker একটি খেলনা lockfile ঘুরে এই উত্তর বের করে।
// Toy lockfile and toy advisory. All names and ids are fictional.
const lock = {
'shop-api@1.0.0': ['web-router@1.9.2', 'report-kit@4.0.1', 'date-lite@2.1.4'],
'web-router@1.9.2': ['path-match@0.8.0'],
'report-kit@4.0.1': ['pdf-make@2.2.0', 'date-lite@2.1.4'],
'pdf-make@2.2.0': ['xml-lite@1.2.0'],
'date-lite@2.1.4': [],
'path-match@0.8.0': ['report-kit@4.0.1'], // second road to report-kit
'xml-lite@1.2.0': [],
};
const advisory = { id: 'TOY-2026-0042', pkg: 'xml-lite', bad: ['1.2.0'], func: 'parseEntity' };
const appCalls = { 'xml-lite': ['parseText'] }; // toy call graph
const root = 'shop-api@1.0.0';
const paths = [], seen = new Set();
function walk(node, path) {
if (path.includes(node)) return; // never loop forever on a cycle
const next = [...path, node];
seen.add(node);
const [name, ver] = node.split('@');
if (name === advisory.pkg && advisory.bad.includes(ver)) paths.push(next);
for (const dep of lock[node] || []) walk(dep, next);
}
walk(root, []);
const direct = lock[root].length, total = seen.size - 1;
console.log(`packages: ${total} (direct ${direct}, transitive ${total - direct})`);
console.log(`${advisory.id} in ${advisory.pkg}: ${paths.length} path(s)`);
for (const p of paths) console.log(` depth ${p.length - 1}: ` + p.map(x => x.split('@')[0]).join(' > '));
const inManifest = lock[root].some(d => d.startsWith(advisory.pkg + '@'));
console.log('listed in your manifest:', inManifest);
const reach = (appCalls[advisory.pkg] || []).includes(advisory.func);
console.log(`${advisory.func} called by app:`, reach);
console.log('priority:', paths.length && reach ? 'fix now' : paths.length ? 'plan fix, record reason' : 'none');আউটপুট:
packages: 6 (direct 3, transitive 3)
TOY-2026-0042 in xml-lite: 2 path(s)
depth 5: shop-api > web-router > path-match > report-kit > pdf-make > xml-lite
depth 3: shop-api > report-kit > pdf-make > xml-lite
listed in your manifest: false
parseEntity called by app: false
priority: plan fix, record reason
xml-lite আপনার manifest-এ নেই, তবু দুটি পথে এসেছে। তাই “আমরা তো এটি ব্যবহার করি না” বলা ভুল হতো। আবার দুটি পথই একই pdf-make দিয়ে যায়, তাই সেটি update করলে দুটি পথই সারে। দুর্বল parseEntity আমাদের খেলনা call graph-এ ডাকা হয় না, তাই অগ্রাধিকার “এখনই” নয়, “পরিকল্পনা করে সারান, আর কারণ লিখে রাখুন”। সাবধান: বাস্তবের reachability বিশ্লেষণ reflection বা dynamic call-এ ভুল করতে পারে। “Reachable নয়” মানে কম জরুরি, নিরাপদ নয়।
এবার অগ্রাধিকারের হিসাব। ধরি একটি service-এ SCA ১২০টি finding দিল, আর প্রতিটি যাচাইয়ে ৩০ মিনিট লাগে (অনুমিত সংখ্যা)। সব দেখতে ১২০ × ০.৫ = ৬০ ঘণ্টা। Reachability আর পর্ব ৩২-এর EPSS ও KEV দিয়ে ছেঁকে ১৫টি থাকলে ৭.৫ ঘণ্টা। সাশ্রয় ৮৭.৫%. বাকি ১০৫টি মুছে যায় না, পরের নিয়মিত update-এ সারে। Transitive package সরাসরি update করা না গেলে npm-এর overrides বা Yarn-এর resolutions-এর মতো ব্যবস্থায় version বদলানো যায়, তবে তা test করে আর লিখে রেখে করুন।
৬ · SBOM আর VEX — উপকরণের তালিকা আর তার ব্যাখ্যা
বিস্কুটের প্যাকেটের গায়ে উপাদানের তালিকা থাকে। কোনো উপাদানে সমস্যা পাওয়া গেলে আপনি প্যাকেট পড়েই জানবেন এটি আপনার ঘরে আছে কি না। SBOM (Software Bill of Materials) software-এর সেই তালিকা। Log4Shell-এর সময় যাঁদের তালিকা ছিল, তাঁরা অনুসন্ধান চালিয়েই উত্তর পেয়েছিলেন। যাঁদের ছিল না, তাঁরা সার্ভার ধরে ধরে খুঁজেছেন।
| ফরম্যাট | উৎস আর standard | জোর যেখানে |
|---|---|---|
| SPDX | Linux Foundation; ISO/IEC 5962:2021 | লাইসেন্স থেকে শুরু, এখন নিরাপত্তাও |
| CycloneDX | OWASP থেকে শুরু; ECMA-424 (প্রথম সংস্করণ ২০২৪) | নিরাপত্তা-কেন্দ্রিক, VEX-ও প্রকাশ করতে পারে |
SBOM কখন বানাবেন? সবচেয়ে কাজের সময় build-এর মধ্যে, lockfile আর তৈরি artifact দেখে। Syft বা CycloneDX-এর নিজস্ব tool এমন কাজ করে। নিচে কিছু নিয়ম, যা পরে অনেক ঝামেলা বাঁচায়। প্রতিটি release-এর জন্য আলাদা SBOM রাখুন, আর artifact-এর সাথে স্বাক্ষরসহ যুক্ত করুন। হাতে লেখা SBOM দ্রুত পুরোনো হয়। Package চেনাতে purl ব্যবহার করুন। SBOM যাচাই করুন, কারণ tool base image বা copy-করা ফাইল বাদ দিতে পারে। আর SBOM একটি index-এ রাখুন, যাতে “এই package কোন কোন service-এ আছে” এক প্রশ্নেই জানা যায়। আমেরিকার NTIA ২০২১ সালে SBOM-এর ন্যূনতম উপাদানের একটি তালিকা প্রকাশ করে, CISA জুলাই ২০২৬-এ তার হালনাগাদ রূপ আনে, আর ইউরোপের Cyber Resilience Act-ও পণ্য-নির্মাতাদের জন্য SBOM-এর বাধ্যবাধকতা আনছে। এই আইনগুলো ধাপে ধাপে কার্যকর হচ্ছে, তাই আপনার ক্ষেত্রে কী প্রযোজ্য তা বর্তমান পাঠ্য দেখে নিন।
SBOM-এর পাশে একটি সমস্যা আছে। Scanner SBOM দেখে বলবে “এখানে একটি দুর্বল library আছে”। কিন্তু হয়তো দুর্বল অংশটি আপনার পণ্যে চলেই না। VEX (Vulnerability Exploitability eXchange) সেই ব্যাখ্যা। এতে চারটি অবস্থা থাকে: not_affected, affected, fixed আর under_investigation. not_affected লিখলে কারণও দিতে হয়, যেমন দুর্বল কোড চলার পথে নেই। CISA-র ন্যূনতম প্রয়োজনের নথি (২০২৩) এই কাঠামোই বলে। VEX হলো ডাক্তারের লেখা নোট: “রিপোর্টে এটি লাল দেখালেও এই রোগীর ক্ষেত্রে সমস্যা নয়, কারণ…”।
// Minimal SBOM + VEX filter on toy data. Clock is fixed; names are fictional.
const lock = [
['web-router', '1.9.2'], ['date-lite', '2.1.4'], ['xml-lite', '1.2.0'], ['fast-json', '3.4.1'],
];
const sbom = {
bomFormat: 'CycloneDX', specVersion: '1.6', version: 1,
metadata: { timestamp: '2026-10-31T00:00:00Z', component: { name: 'shop-api', version: '1.0.0' } },
components: lock.map(([name, version]) =>
({ type: 'library', name, version, purl: `pkg:npm/${name}@${version}` })),
};
console.log('SBOM components:', sbom.components.map(c => c.purl).join(' '));
const advisories = [ // a scanner matched these against the SBOM
{ id: 'TOY-2026-0042', purl: 'pkg:npm/xml-lite@1.2.0', sev: 'high' },
{ id: 'TOY-2026-0077', purl: 'pkg:npm/fast-json@3.4.1', sev: 'critical' },
{ id: 'TOY-2026-0090', purl: 'pkg:npm/date-lite@2.1.4', sev: 'medium' },
{ id: 'TOY-2026-0101', purl: 'pkg:npm/old-cache@0.1.0', sev: 'high' },
];
const vex = { // statements written by the team that owns shop-api
'TOY-2026-0042': { status: 'not_affected', justification: 'vulnerable_code_not_in_execute_path' },
'TOY-2026-0090': { status: 'under_investigation' },
};
const inSbom = new Set(sbom.components.map(c => c.purl));
const rows = advisories.filter(a => inSbom.has(a.purl))
.map(a => ({ ...a, status: (vex[a.id] || { status: 'affected' }).status,
why: (vex[a.id] || {}).justification || '-' }));
for (const r of rows) console.log(`${r.id} ${r.sev.padEnd(8)} ${r.status.padEnd(19)} ${r.why}`);
const act = rows.filter(r => r.status !== 'not_affected');
console.log(`matched ${rows.length} of ${advisories.length}; action queue: ${act.length}`);
console.log('queue:', act.map(r => r.id).join(', '));আউটপুট:
SBOM components: pkg:npm/web-router@1.9.2 pkg:npm/date-lite@2.1.4 pkg:npm/xml-lite@1.2.0 pkg:npm/fast-json@3.4.1
TOY-2026-0042 high not_affected vulnerable_code_not_in_execute_path
TOY-2026-0077 critical affected -
TOY-2026-0090 medium under_investigation -
matched 3 of 4; action queue: 2
queue: TOY-2026-0077, TOY-2026-0090
SBOM-টি CycloneDX-এর আকারে, তবে খুব সংক্ষিপ্ত। চারটি advisory-র একটি old-cache নিয়ে, যা SBOM-এ নেই, তাই সেটি বাদ: ৪টির ৩টি মিলেছে। TOY-2026-0042-এ not_affected আর কারণ আছে, তাই কাজের তালিকা থেকে সরল। 0077-এ কোনো statement নেই, আর কোড নিরাপদ পথ বেছে নেয়: statement না থাকলে affected ধরে। under_investigation তালিকায় থাকে, কারণ “দেখছি” মানে “ঠিক আছে” নয়। VEX বিশ্বাসের ওপর চলে, তাই কে লিখেছে আর স্বাক্ষর আছে কি না দেখা জরুরি। পুরোনো not_affected সিদ্ধান্ত কোড বদলালে আবার যাচাই করুন।
৭ · Signing আর provenance — কে বানাল, কীভাবে বানাল
পর্ব ১১-এ দেখেছেন, digital signature প্রমাণ করে কোন private key দিয়ে স্বাক্ষর হয়েছে, আর ফাইল তারপর বদলায়নি। পোস্ট অফিসের সিলমোহরের মতো। Code signing-এর পুরোনো সমস্যা ছিল key: দীর্ঘদিন রাখতে হয়, চুরি হতে পারে, আর ছোট project-এ সামলানো কঠিন।
Sigstore এই সমস্যার একটি উত্তর, যা OpenSSF-এর অধীনে চলে। মূল অংশ তিনটি। Fulcio একটি certificate authority, যা OIDC login-এর পরিচয় দেখে প্রায় ১০ মিনিটের short-lived certificate দেয়। Rekor একটি transparency log, পর্ব ১২-এর Certificate Transparency-র মতো শুধু যোগ করার খাতা। আর cosign স্বাক্ষর ও যাচাইয়ের tool. একে keyless signing বলে, যদিও key থাকে: কাজের সময় তৈরি হয়, কাজ শেষে ফেলে দেওয়া হয়। Certificate-এর মেয়াদ পেরিয়ে গেলেও স্বাক্ষর যাচাই করা যায়, কারণ log প্রমাণ করে স্বাক্ষরটি মেয়াদের ভেতরেই হয়েছিল।
Provenance আরেক ধাপ এগোয়। স্বাক্ষর বলে “কে”। Provenance বলে “কীভাবে”: কোন repository, কোন commit, কোন build system, কোন build-এর নির্দেশ। এটি একটি build attestation, সাধারণত in-toto ফরম্যাটে, ঠিক ওষুধের প্যাকেটের ব্যাচ নম্বরের মতো: কোন কারখানা, কোন তারিখ, কোন উপাদান। npm আর PyPI-র মতো কিছু registry এখন package-এর সাথে provenance বা trusted publishing-এর সুবিধা দেয়।
নিচের ধাপগুলো একটি artifact-এর পূর্ণ যাচাই। Digest দুটি আসল SHA-256, নকল bytes-এর ওপর আমাদের চালানো। সময় আর পরিচয় কাল্পনিক।
| Digest | |
| স্বাক্ষর | |
| পরিচয় | |
| Log | |
| Provenance | |
| সিদ্ধান্ত |
- Digest বের করা। যাচাই শুরু হয় হাতে পাওয়া ফাইল থেকে। SHA-256-এর শুরু
64f28b2e. বাকি সব যাচাই এই সংখ্যার ওপর, নাম বা version লেখার ওপর নয়। - স্বাক্ষর মেলানো। Certificate-এর public key দিয়ে স্বাক্ষর এই digest-এর সাথে মিলল। অর্থাৎ ফাইল স্বাক্ষরের পরে বদলায়নি। কিন্তু কে স্বাক্ষর করেছে, তা এখনো জানা হয়নি।
- পরিচয় মেলানো। Certificate Fulcio-র root পর্যন্ত যাচাই হলো, আর তার ভেতরের পরিচয় আমাদের প্রত্যাশিত release workflow-এর সাথে মিলল। সবচেয়ে বেশি ভুল হয় এখানে: “কেউ একজন স্বাক্ষর করেছে” দেখে থেমে গেলে যে কেউ পাস করবে।
- Log আর সময়। Certificate-এর মেয়াদ ০৯:১৪:০২ থেকে ০৯:২৪:০২. Rekor-এর রেকর্ড ০৯:১৪:০৫, মেয়াদের ভেতরে। Inclusion proof-ও মিলেছে, তাই রেকর্ডটি সত্যিই খাতায় আছে।
- Provenance পড়া। Provenance-এর স্বাক্ষরও একইভাবে যাচাই হলো। ভেতরে লেখা source
example/shop-api, tagv1.4.2, build হয়েছে hosted builder-এ, developer-এর ল্যাপটপে নয়। সবই নীতির সাথে মিলছে। - সিদ্ধান্ত। পাঁচটি ঘর ঠিক, তাই অনুমতি। এই সিদ্ধান্ত স্বয়ংক্রিয় policy নেয়, মানুষের মনে রাখার ওপর ছাড়া হয় না। তারপরও এর অর্থ শুধু “প্রত্যাশিত পথে তৈরি”, “কোডে ভুল নেই” নয়।
- একটি ভিন্ন ফাইল ধরুন। কেউ bytes-এ একটি অক্ষর যোগ করল। Digest হলো
0b0cd267, স্বাক্ষর আর মিলল না, বাকি ঘর দেখারই দরকার নেই। যাচাই ব্যর্থ হলে থেমে যান। “আপাতত ছেড়ে দিই” এখানে ঠিক নয়।
নিজের artifact-এ যাচাই দেখতে এমন হয়। এই command-গুলো আমরা চালাইনি, তাই নিচের ফলটি নমুনা। Tool-এর version অনুযায়ী flag বদলাতে পারে, ব্যবহারের আগে official docs দেখুন।
# নিজের image: tag নয়, digest দিয়ে
cosign verify registry.example.com/shop/api@sha256:<digest> \
--certificate-identity https://ci.example.com/shop/api/release.yml@refs/tags/v1.4.2 \
--certificate-oidc-issuer https://ci.example.com
# নিজের release ফাইলের provenance
slsa-verifier verify-artifact shop-api-1.4.2.tgz \
--provenance-path shop-api.intoto.jsonl \
--source-uri github.com/example/shop-api \
--source-tag v1.4.2নমুনা আউটপুট — version-ভেদে আলাদা হতে পারে
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority certificates
আরও গভীরে: Rekor ভেতরে Merkle tree ব্যবহার করে, তাই কোনো রেকর্ড আছে কি না অল্প কয়েকটি hash দিয়েই প্রমাণ করা যায়। Provenance সাধারণত একটি in-toto Statement, যার ভেতরে SLSA Provenance predicate, আর বাইরে DSSE নামের স্বাক্ষরিত খাম। TUF (The Update Framework) আরেকটি দিক দেখে: update ব্যবস্থার key চুরি হলেও ক্ষতি সীমিত রাখা, পুরোনো version-এ ঠেলে দেওয়া ঠেকানো। Sigstore নিজেও তার trust root বিতরণে TUF ব্যবহার করে।
৮ · SLSA আর build শক্ত করা
SLSA (উচ্চারণ “সালসা”, Supply-chain Levels for Software Artifacts) একটি ধাপে ধাপে উন্নতির কাঠামো, এখন OpenSSF-এর অধীনে। ২০২৬ সালের অক্টোবরে slsa.dev-এ অনুমোদিত সংস্করণ v1.2. এতে দুটি track: Build আর Source. Source track অনুমোদিত অংশ হিসেবে যুক্ত হয়েছে v1.2-তে। পুরোনো লেখায় L4 পর্যন্ত এক সিঁড়ি দেখলে বুঝবেন সেটি v0.1-এর কথা। v1.0-তে কাঠামো বদলেছে।
| Level | প্রয়োজন | যা ঠেকায় | বাস্তবে |
|---|---|---|---|
| Build L0 | কিছু নয় | কিছু নয় | ল্যাপটপে build, SLSA নেই |
| Build L1 | Provenance আছে | ভুল, নথির অভাব | কীভাবে তৈরি তা জানা যায়, তবে জাল করা সহজ |
| Build L2 | Hosted build platform-এর স্বাক্ষরিত provenance | Build-এর পরে বদল | জাল করতে ইচ্ছাকৃত হামলা লাগে |
| Build L3 | Hardened build platform | Build চলাকালে বদল | Build-গুলো একে অপর থেকে আলাদা, স্বাক্ষরের key build-এর নাগালের বাইরে |
Source track: L1 version control, L2 ইতিহাস রক্ষা আর source provenance, L3 ধারাবাহিক technical control, L4 দুইজনের review. Git নিরাপত্তা আর code review-এর পর্বগুলো এই কাজের ভিত্তি।
SLSA যা বলে না: এটি বলে artifact প্রত্যাশিত পথে তৈরি হয়েছে। কোডে দুর্বলতা নেই, বা dependency-গুলো ভালো, এ কথা বলে না। একটি artifact-এর Build L3 তার dependency-দের L3 বানায় না। আর level একটি দাবি, তাই যাচাইকারীকে নিজে provenance মিলিয়ে দেখতে হয়।
Build pipeline শক্ত করার নিয়ম
Build মেশিন কারখানার মতো: এখানে যা ঢোকে, তাতেই আপনার সিল পড়ে। গভীর আলোচনা আছে DevSecOps আর container registry-র পর্বে। এখানে নিরাপত্তার মূল নিয়মগুলো:
Pinned action কেন? Tag একটি নামফলক, যা নতুন commit-এর দিকে সরানো যায়। ২০২৫ সালের মার্চে tj-actions/changed-files নামের একটি জনপ্রিয় GitHub Action-এর আপসে এমন tag সরানোর প্রতিবেদন আসে, আর build log-এ secret উন্মুক্ত হওয়ার ঝুঁকি দেখা দেয়। CISA এটি নিয়ে সতর্কবার্তা দেয় (CVE-2025-30066). Commit hash বদলানো যায় না, তাই পূর্ণ hash-এ বাঁধা থাকলে সেই সরানো আপনাকে ছোঁয় না। নিচে একটি GitHub Actions-এর উদাহরণ। ধারণাটি অন্য CI-তেও একই।
# উদাহরণ: হ্যাশটি নিজের যাচাই করা commit থেকে নিন
permissions:
contents: read # ডিফল্ট: শুধু পড়া
jobs:
build:
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write # শুধু keyless signing-এর পরিচয়ের জন্য
steps:
- uses: actions/checkout@<full-40-char-commit-sha> # v4
with:
persist-credentials: false
- run: npm ci --ignore-scripts
- run: npm testHash-এ বাঁধলে একটি দাম আছে: নিজে থেকে update আসে না। তাই update bot দিয়ে hash আপডেট করুন, যাতে নিরাপত্তা-সংশোধনও পৌঁছায়। একই যুক্তি container image-এ: :latest নয়, @sha256:…. Reproducible build সবচেয়ে শক্ত যাচাই: দুটি আলাদা build ব্যবস্থায় একই bit এলে একটি ব্যবস্থার আপস ধরা পড়ে। এটি কঠিন, তবে Debian-এর মতো কিছু project এই পথে অনেক দূর এগিয়েছে।
৯ · Vendor software, standard আর আপস হলে কী করবেন
কেনা software-ও শিকলের অংশ
SolarWinds ছিল কেনা পণ্য, npm package নয়। কেনা software-এর ক্ষেত্রে আপনি lockfile দেখতে পান না, তাই প্রশ্ন করেই জানতে হয়। পূর্ণ প্রক্রিয়া আসবে পর্ব ৭১-এ। Intake-এর জন্য ছোট তালিকাটি এমন:
| প্রশ্ন | কেন |
|---|---|
| SBOM আর VEX দেবেন কি? | Zero-day-র দিনে উত্তর পেতে |
| Update কি স্বাক্ষরিত? আপনি কি ধাপে ছাড়তে পারবেন? | খারাপ update সবার কাছে একসাথে না পৌঁছাক |
| দুর্বলতা জানানোর পথ আর patch-এর সময়সীমা কী? | পর্ব ৬-এর দায়িত্বশীল প্রকাশ তাঁদের আছে কি না |
| Agent কী অধিকারে চলে, কোথায় যোগাযোগ করে? | Least privilege আর egress নিয়ম বানাতে |
| Secure development-এর প্রমাণ আছে কি? | SSDF, SOC 2 ইত্যাদির স্বীকৃতি, যদিও কাগজ একাই যথেষ্ট নয় |
| Support কবে শেষ? | End-of-life পণ্য নিজেই একটি ঝুঁকি |
দুটি NIST নথি এখানে চিনে রাখুন। NIST SP 800-161 Rev. 1 (২০২২, ২০২৪ সালে হালনাগাদ) হলো প্রতিষ্ঠানের স্তরের C-SCRM নির্দেশিকা: সরবরাহকারী বাছাই, চুক্তি, পর্যবেক্ষণ। SSDF, NIST SP 800-218 (v1.1, ২০২২) নির্মাতার দিকের নির্দেশিকা, চারটি দলে: প্রতিষ্ঠান প্রস্তুত করা (PO), software রক্ষা করা (PS), ভালোভাবে নিরাপদ software তৈরি (PW), আর দুর্বলতায় সাড়া দেওয়া (RV). ২০২৫ সালের ডিসেম্বরে v1.2-এর একটি খসড়া (Rev. 1) প্রকাশিত হয়। নভেম্বর ২০২৬-এর শুরুতেও NIST-এর পাতায় এটি খসড়া, তাই চালু সংস্করণ v1.1. সর্বশেষ অবস্থা সেখানে দেখে নিন।
একটি dependency আপস হলে
ঘটনা ঘটলে মনে রাখুন, প্রশ্ন শুধু “কোন version” নয়। Install-এর সময় কোড চলতে পারে, তাই build মেশিন আর তার secret-ও ঝুঁকিতে পড়তে পারে। নিচে একটি কাল্পনিক সকাল। বড় কাঠামো আছে পর্ব ৬১ আর পর্ব ৬২-এ, আর incident management-এ।
| সময় | |
| Service ঝুঁকিতে | |
| Deploy | |
| Registry proxy | |
| CI secret | |
| Version |
- ০৯:০০ · সংকেত। Registry-র security advisory এলো:
fast-json 3.4.1ক্ষতিকর। প্রথম কাজ প্রাথমিক উৎসে মিলিয়ে দেখা, শুধু একটি social media পোস্টে নির্ভর না করা। Incident খোলা হলো। - ০৯:২০ · পরিধি। SBOM index-এ এক অনুসন্ধানে দেখা গেল ৩টি service-এ এই version আছে। SBOM না থাকলে এই ধাপটি অনেক ঘণ্টার।
- ০৯:৩০ · থামানো। Deploy আর update bot বন্ধ, proxy-তে 3.4.1 নিষিদ্ধ, যাতে নতুন build-এ আর না ঢোকে। ঝুঁকি ছড়ানো বন্ধ হলো, এখনো কিছু সারেনি।
- ১০:১৫ · সময়ের জানালা। Lockfile ইতিহাস আর build log থেকে দেখা গেল ৭টি build 3.4.1 নামিয়েছে। Advisory বলছে install-এর সময় কোড চলে, তাই ধরে নিতে হবে এই build-গুলোতে পাওয়া CI secret ঝুঁকিতে।
- ১১:০০ · Secret বদল। ওই runner-এ পাওয়া সব token আর credential বদলানো হলো। শুধু package সরালে চুরি যাওয়া secret ফিরে আসে না। এই কাজটি সবচেয়ে বেশি বাদ পড়ে।
- ১২:৩০ · পরিষ্কার build. 3.4.0-তে hash-সহ ফেরত, নতুন ephemeral runner-এ build, স্বাক্ষর, তারপর ধাপে rollout. পুরোনো image বাতিল। Rollback-এর আগে দেখে নিতে হয় পুরোনো version-টিও পরিষ্কার কি না।
- ১৪:০০ · খোঁজা। Advisory-র IOC ধরে build runner আর production-এর egress log দেখা হলো, যেমন
updates.example.netবা203.0.113.50. কিছু পেলে এটি পূর্ণ incident response-এ যায়। না পেলেও log-এর সীমা লিখে রাখা হয়। - পরের সপ্তাহ · শেখা। Post-incident review: কী কাজ করল, কত সময় লাগল, কোন check যোগ হবে। গ্রাহক বা নিয়ন্ত্রকের কাছে জানানোর দায় আছে কি না আইনি দলের সাথে দেখা হলো। ক্ষতিকর package registry-কে জানানো হলো।
Detection আগে থেকে সাজিয়ে রাখুন। ভালো সংকেত হলো: একই version-এর hash বদলানো, review ছাড়া lockfile বদলানো, অচেনা install script, স্বাক্ষরহীন image-এর deploy চেষ্টা, আর build runner থেকে অচেনা গন্তব্যে সংযোগ। শেষটির একটি Sigma-ধাঁচের উদাহরণ (কেন্দ্রীয় log থাকতে হবে, বিস্তারিত পর্ব ৫৬-এ):
title: Build runner connects to an unapproved host
status: experimental
logsource:
category: network_connection
product: linux
detection:
selection:
ComputerName|startswith: 'build-'
Initiated: 'true'
approved:
DestinationHostname|endswith:
- '.internal.example'
condition: selection and not approved
falsepositives:
- A new mirror that is not on the approved list yet
level: highপরীক্ষা ও ইন্টারভিউতে: Transitive dependency কী? যা আপনি সরাসরি যোগ করেননি, আপনার dependency টেনে এনেছে। SBOM আর SCA-র পার্থক্য? SBOM তালিকা, SCA তালিকাকে দুর্বলতার সাথে মেলায়। Signature থাকলেই কি নিরাপদ? না, এটি উৎস আর অখণ্ডতা প্রমাণ করে, ভেতরের কোড ভালো কি না তা নয়। Dependency confusion থামাবেন কীভাবে? একক registry, scope, আর ভেতরের নাম সুরক্ষিত রেখে। Build L2 আর L3-র পার্থক্য? L2 build-এর পরের বদল ঠেকায়, L3 build চলাকালের বদলও ঠেকায়।
১০ · AI-এর যুগে supply chain
AI এই শিকলে নতুন একটি জোড়া যোগ করেছে। AI কোড লিখতে গিয়ে এমন package-এর নাম দিতে পারে, যার অস্তিত্বই নেই। কেউ সেই নামে package প্রকাশ করলে পরের জন যিনি কোডটি হুবহু চালাবেন, তিনি সেটি বসিয়ে ফেলবেন। এই ঝুঁকিকে অনেকে “slopsquatting” বলছেন। মডেলের ফাইল আর AI agent-এর tool-ও এখন dependency, যা পর্ব ৫১-এ আসবে।
| AI যা করে | ঝুঁকি | যাচাই |
|---|---|---|
| Package-এর নাম বা version বানায় | ভুয়া বা নকল package | Registry-তে নিজে দেখা, intake check |
| CVE নম্বর বা standard বানায় | ভুল সিদ্ধান্ত | NVD, OSV বা vendor-এর advisory পড়া |
Error সারাতে যাচাই বন্ধ করতে বলে: verify=False, strict-ssl=false, --trusted-host | TLS আর উৎস যাচাই শেষ | মূল কারণ খোঁজা, flag ছাড়াই ঠিক করা |
| Hash মেলেনি দেখে lockfile মুছতে বা নতুন করে বানাতে বলে | আসল সংকেত মুছে যায় | কেন বদলাল আগে অনুসন্ধান |
Pipeline-এ @main, write-all, :latest বসায় | বদলানো যায় এমন উৎস, বাড়তি অধিকার | Diff review, commit hash, কম অধিকার |
| Triage-এ অতি আত্মবিশ্বাসে “not affected” বলে | ভুল VEX | কোড দেখে মানুষের সিদ্ধান্ত, কারণ লিখে |
AI-কে হামলা নয়, পর্যালোচনার কাজ দিন। Lockfile-এর diff বা pipeline ফাইল দিন, তবে secret, token আর ভেতরের URL আগে সরিয়ে নিন।
AI-এর পরামর্শ নেওয়ার চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১SolarWinds-এর update তো স্বাক্ষরিত ছিল। তাহলে code signing কি ব্যর্থ, নাকি আমরা তার কাছে ভুল জিনিস চেয়েছিলাম?
২০২০ সালের ডিসেম্বরে প্রকাশিত প্রতিবেদনগুলো থেকে জানা যায়, Orion পণ্যের update-এ ক্ষতিকর অংশ ছিল, আর সেটি প্রকাশকের বৈধ স্বাক্ষর নিয়েই গ্রাহকের কাছে পৌঁছেছিল। কোম্পানির নিজের নিয়ন্ত্রক-নথিতে ক্ষতিগ্রস্ত update নেওয়া গ্রাহকের সংখ্যা ১৮,০০০-এর কম বলে উল্লেখ আছে। পরে অনেক কম প্রতিষ্ঠানে গভীর কার্যকলাপের কথা জানা যায়।
Code signing এখানে ঠিক তাই করেছে, যা করার কথা। সে বলেছে, “এই ফাইল এই প্রকাশকের key দিয়ে স্বাক্ষরিত, আর তারপর বদলায়নি।” দুটো কথাই সত্য ছিল। ভুলটি ছিল আমাদের মানসিক অনুবাদে: “স্বাক্ষরিত, তাই নিরাপদ।” স্বাক্ষর হয় শিকলের শেষে। তার আগের কোনো ধাপে ক্ষতিকর অংশ ঢুকলে স্বাক্ষর সেটিকেও সিল মেরে দেয়। পোস্ট অফিসের সিল প্রমাণ করে চিঠি কোন অফিস থেকে এসেছে, চিঠির ভেতরের কথা সত্য কি না নয়।
তাহলে কী করা যেত? প্রথমত, যা স্বাক্ষর হচ্ছে তা যাচাই: source থেকে আলাদা একটি build ব্যবস্থায় আবার তৈরি করে মিলিয়ে দেখা, অর্থাৎ reproducible বা verified build. দ্বিতীয়ত, build ব্যবস্থাকে production-এর সমান গুরুত্বে পাহারা দেওয়া। তৃতীয়ত, গ্রাহকের দিকে: monitoring tool-এর মতো শক্তিশালী পণ্যকেও least privilege আর সীমিত egress দেওয়া। আপসের পরও যদি সার্ভারটি বাইরে যোগাযোগ করতে না পারত, ক্ষতি সীমিত হতো। প্রকৃত ঘটনায় একটি নিরাপত্তা কোম্পানির নিজের অনুসন্ধানেই বিষয়টি প্রকাশ পায়, কোনো স্বাক্ষর-যাচাই থেকে নয়।
এই শিক্ষাই SLSA-র Build track-এর ভিত্তি। Provenance প্রশ্নকে “কে” থেকে “কীভাবে” পর্যন্ত টেনে নেয়। তবে সেটিও কোডের ভালো-মন্দ প্রমাণ করে না, যদি build ব্যবস্থা নিজেই ভেতর থেকে দখল থাকে।
মূল উপলব্ধি: প্রতিটি control-কে জিজ্ঞেস করুন, “তুলনা করছে ঠিক কী কিসের সাথে?” স্বাক্ষর অখণ্ডতা আর উৎসের প্রমাণ, মান বা সদিচ্ছার প্রমাণ নয়।
প্র ০২xz-এর ঘটনা কোনো tool ধরেনি, ধরেছেন একজন কৌতূহলী মানুষ। এ থেকে open source-এর ওপর আমাদের নির্ভরতা সম্পর্কে কী বোঝা যায়?
২০২৪ সালের মার্চে প্রকাশিত CVE-2024-3094 অনেকের চোখ খুলে দেয়। প্রকাশিত বিশ্লেষণ অনুযায়ী xz প্রকল্পে একটি পরিচয় প্রায় দুই বছর ধরে ধীরে ধীরে অবদান রেখে বিশ্বাস অর্জন করে, আর অতিরিক্ত চাপে থাকা রক্ষণাবেক্ষণকারীর কাছ থেকে দায়িত্বের অংশ পায়। শেষে 5.6.0 আর 5.6.1 release-এ backdoor যুক্ত হয়। লক্ষণীয়, release ফাইলের কিছু অংশ repository-র সাধারণ দৃশ্যের চেয়ে আলাদা ছিল। একজন developer আধা সেকেন্ডের মতো অস্বাভাবিক SSH বিলম্ব আর memory tool-এর সতর্কতা দেখে অনুসন্ধান শুরু করেন। তাই বেশিরভাগ stable distribution-এ পৌঁছানোর আগেই এটি ধরা পড়ে।
প্রযুক্তিগত দুর্বলতার চেয়ে এখানে সামাজিক দুর্বলতা বড়। পৃথিবীর অসংখ্য সার্ভারে যে library আছে, তা চলছিল অল্প কয়েকজনের স্বেচ্ছাশ্রমে। MFA, signing, SLSA, কোনোটিই থামাতে পারত না একজন বৈধ, বিশ্বস্ত maintainer-কে, যিনি স্বাভাবিক পথেই কোড ঢোকাচ্ছেন। Provenance সত্যি কথাই বলত: এটি এই maintainer-এর প্রকাশ করা release.
রক্ষকের দিকে কী কী শেখার আছে? এক, release ফাইল আর repository-র পার্থক্য দেখা, আর সম্ভব হলে source থেকেই build করা। দুই, reproducible build, যাতে স্বাধীনভাবে ফল মেলানো যায়। তিন, অস্বাভাবিকতা উপেক্ষা না করার সংস্কৃতি: “আধা সেকেন্ড বেশি তো কী হয়েছে” না বলা। এটিই পর্ব ৪-এর “ধরা পড়লে কীভাবে জানব” প্রশ্ন। চার, নিজের নির্ভরতা জানা, আর গুরুত্বপূর্ণ project-কে অর্থ বা জনবল দিয়ে সহায়তা করা। OpenSSF-এর মতো উদ্যোগ এ কাজেই গড়া। পাঁচ, রক্ষণাবেক্ষণকারীকে অপমান বা চাপ দেওয়া বন্ধ করা, কারণ ক্লান্ত মানুষ social engineering-এর সহজ লক্ষ্য (পর্ব ৫২)।
মূল উপলব্ধি: Supply chain শেষ পর্যন্ত মানুষের শিকল। Tool যাচাই করে প্রক্রিয়া, কিন্তু বিশ্বাস আর ক্লান্তি মানুষের বিষয়। তাই প্রযুক্তিগত control-এর সাথে সামাজিক সহায়তাও নিরাপত্তার বিনিয়োগ।
প্র ০৩Log4Shell শেখায় দ্রুত update করুন, event-stream শেখায় অন্ধভাবে update করবেন না। দুটি একসাথে মানা যায় কীভাবে?
দুটি শিক্ষা আপাতদৃষ্টিতে উল্টো। ২০২১ সালের ডিসেম্বরে Log4Shell প্রকাশের পর যাঁরা দ্রুত update করতে পারেননি, তাঁরা ঝুঁকিতে ছিলেন। আবার ২০১৮ সালের event-stream ঘটনায় বা অন্য malicious update-এ যাঁরা স্বয়ংক্রিয়ভাবে নতুন version নিয়েছেন, তাঁরাই আক্রান্ত হয়েছেন।
সমাধান হলো update-কে এক জিনিস না ভাবা। “কেন” আর “কতটা নিশ্চিত”, এই দুই প্রশ্নে ভাগ করা। সাধারণ feature update-এর কোনো তাড়া নেই। এটি ধীর পথে আসুক: bot PR খুলবে, cooldown চলবে, test আর review হবে। নিরাপত্তা-update-এর পেছনে থাকে একটি প্রকাশিত, যাচাইযোগ্য advisory, তাই সেটি দ্রুত পথে আসুক। দ্রুত পথ মানে যাচাই ছাড়া নয়: advisory প্রাথমিক উৎসে দেখা, ধাপে rollout, আর ফেরার ব্যবস্থা।
হিসাবটি একটি ঝুঁকি-তুলনা। একটি কাল্পনিক নীতি ধরুন: সাধারণ update-এ ৭ দিন অপেক্ষা। নতুন release-এ ক্ষতিকর কিছু থাকলে সমাজের চোখে পড়ার সময় পাওয়া গেল। এর দাম, সাধারণ bug-fix এক সপ্তাহ দেরিতে আসে। KEV-তে থাকা দুর্বলতায় অপেক্ষা ০ দিন, কারণ এখানে অপেক্ষার ঝুঁকিই বড়। লক্ষ করুন, cooldown দীর্ঘদিন লুকিয়ে থাকা ক্ষতিকর কোড ধরে না। xz-এর মতো ঘটনায় ৭ দিন যথেষ্ট না-ও হতে পারত।
আরেকটি জিনিস দুই পথকেই সহজ করে: দ্রুত আর নিরাপদে deploy করার ক্ষমতা। ভালো test, staged rollout, স্বয়ংক্রিয় rollback থাকলে update-এর ভয় কমে। যে দলের একটি update-এ সপ্তাহ লাগে, সেই দলই সবচেয়ে বিপদে পড়ে। তাই Log4Shell-এর দিনে যাঁদের কাছে SBOM আর স্বয়ংক্রিয় pipeline ছিল, তাঁরা ঘণ্টায় কাজ শেষ করেছেন। এই দলগুলো “দ্রুত” ছিল, কারণ “সাজানো” ছিল।
মূল উপলব্ধি: প্রশ্নটি “দ্রুত না ধীর” নয়। দুটি আলাদা পথ রাখুন, প্রতিটির নিয়ম আগে লিখে রাখুন, আর দ্রুত পথকেও পরীক্ষিত রাখুন।
প্র ০৪SBOM থাকলেই কি নিরাপত্তা বাড়ে? আর SBOM প্রকাশ করলে কি হামলাকারীকে মানচিত্র দেওয়া হয় না?
২০২১ সালের মে মাসে আমেরিকার Executive Order 14028-এর পর SBOM আলোচনার কেন্দ্রে আসে, আর একই বছর NTIA ন্যূনতম উপাদানের তালিকা প্রকাশ করে। অনেক প্রতিষ্ঠান তখন SBOM বানাতে শুরু করে, কিন্তু একটি পরিচিত ভুলও শুরু হয়: ফাইল বানিয়ে ফোল্ডারে রেখে দেওয়া। উপাদানের তালিকা রান্না করে না। যা কেউ পড়ে না, তা নিরাপত্তা বাড়ায় না।
SBOM কাজের হয় তিনটি শর্তে। এক, তা সঠিক হতে হবে। Tool ভেদে একই পণ্যের SBOM আলাদা হতে পারে। Base image-এর অংশ, static-link করা কোড বা কপি করে বসানো ফাইল বাদ পড়তে পারে। দুই, তা হালনাগাদ হতে হবে: প্রতিটি build-এ নতুন, আর artifact-এর সাথে বাঁধা। তিন, তা ব্যবহার হতে হবে: একটি index-এ রাখা, যাতে নতুন advisory-র সাথে স্বয়ংক্রিয়ভাবে মিলিয়ে দেখা যায়। এর সাথে আসে VEX, নইলে SBOM থেকে অসংখ্য অপ্রাসঙ্গিক সতর্কতা তৈরি হয়, আর alert fatigue বাড়ে।
এবার মানচিত্রের প্রশ্ন। আপত্তিটি পুরোপুরি ভিত্তিহীন নয়: SBOM বলে দেয় কোথায় কোন version. কিন্তু হামলাকারী অনেক তথ্য অন্য পথেও পান, যেমন fingerprint বা public সেবার আচরণ দেখে। আর রক্ষকের কাছে তালিকা না থাকলে অসমতা আরও বাড়ে। এটি পর্ব ৩-এর open design-এর যুক্তি: লুকিয়ে রেখে নিরাপত্তা টেকে না। তবে “শেয়ার করা” মানে “সবার জন্য খোলা” নয়। অনেক vendor SBOM চুক্তির অধীনে গ্রাহককে দেন, public-এ দেন না। ভেতরের তালিকায় ভেতরের নাম বা path থাকলে সেটিও ভেবে দেখুন। অর্থাৎ বিতরণ একটি access control-এর সিদ্ধান্ত।
শেষ কথা, SBOM জানা দুর্বলতার জন্য শক্তিশালী, কিন্তু ক্ষতিকর package চেনায় না। একটি SBOM-এ fast-json 3.4.1 লেখা থাকা তার ক্ষতিকর হওয়া বলে না। Advisory এলে তখন খুঁজে পেতে সাহায্য করে।
মূল উপলব্ধি: SBOM একটি ভিত্তি, সমাধান নয়। এর মূল্য ফাইলে নয়, “এই package কোথায় আছে” প্রশ্নের দ্রুত আর সঠিক উত্তরে।
প্র ০৫একটি artifact SLSA Build L3 হলেও আপস থাকতে পারে কীভাবে? বিশ্বাসের শিকল কোথায় গিয়ে শেষ হয়?
Build L3 শক্ত দাবি করে: build চলাকালে বদল ঠেকানো, আর স্বাক্ষরের key build-এর নাগালের বাইরে রাখা। তবু এর সীমা আছে, আর সেগুলো জানা জরুরি।
প্রথম, source নিজেই খারাপ হতে পারে। একজন বৈধ contributor ক্ষতিকর কোড ঢোকালে build সেটিকে নির্ভুলভাবে বানাবে। Source track-এর L4-এর দুইজনের review এই ঝুঁকি কমায়, কিন্তু দুজনই না দেখলে বা দ্বিতীয়জন চাপে থাকলে কাজ করে না। দ্বিতীয়, dependency. একটি L3 artifact-এর ভেতরের library-গুলো হয়তো L0. SLSA level একটি artifact-এর, তার পুরো বৃক্ষের নয়। তৃতীয়, build platform-কেই বিশ্বাস করতে হচ্ছে। সেই platform-এর গভীর দুর্বলতা বা অপারেটরের ভুল সব প্রমাণের ভিত নাড়িয়ে দিতে পারে। চতুর্থ, যাচাইকারী যাচাই না করলে পুরো ব্যবস্থার কোনো মূল্য নেই, আর ভুল পরিচয় মেলালে তো কথাই নেই।
আরও গভীরে আছে একটি পুরোনো প্রশ্ন। ১৯৮৪ সালের Turing Award ভাষণ “Reflections on Trusting Trust”-এ দেখানো হয়েছিল, একটি compiler এমনভাবে আপস হতে পারে যে source পড়ে কিছুই ধরা যাবে না, কারণ compiler নিজেই নিজেকে সংক্রমিত করে। উপসংহার ছিল, যে কোড আপনি পুরোপুরি নিজে বানাননি, তাকে পুরোপুরি বিশ্বাস করা যায় না। পরে diverse double-compiling-এর মতো গবেষণা এর আংশিক উত্তর দিয়েছে, আর bootstrappable build-এর উদ্যোগ খুব ছোট যাচাইযোগ্য ভিত্তি থেকে পুরো toolchain গড়ে তুলতে চায়।
বাস্তবে তাই লক্ষ্য “শূন্য বিশ্বাস” নয়, কারণ সেটি অসম্ভব। পর্ব ১১-এর trust anchor-এর মতো কোথাও একটি ভিত্তি মানতেই হয়। লক্ষ্য হলো বিশ্বাসকে ছোট করা, স্পষ্ট করা, আর একাধিক স্বাধীন জায়গায় ভাগ করা। এক ব্যবস্থার আপস যেন একা সব না ভাঙে, আর ভাঙলে যেন ধরা পড়ে।
মূল উপলব্ধি: SLSA ঝুঁকি কমায়, শূন্য করে না। ভালো রক্ষক জানেন তিনি ঠিক কাকে কাকে বিশ্বাস করছেন, আর সেই বিশ্বাস ভাঙলে কী করবেন।
অনুশীলন
সব কাজ নিজের ফোল্ডারে বা কাগজে। কোনো বাইরের registry বা সিস্টেমে পরীক্ষা নয়।
-
হিসাব: (ক) একটি পণ্যে ৪০০টি package, প্রতিটির বছরে আপসের সম্ভাবনা ০.২% (অনুমিত), স্বাধীন ধরে নিন। অন্তত একটি আপসের সম্ভাবনা কত? ২০০টিতে নামালে কত? (খ)
web-routerআরweb-rotuer-এর edit distance কত, যদি অদলবদল ১ ধরা হয়? সাধারণ Levenshtein-এ কত? (গ) ৯০টি SCA finding, প্রতিটিতে ২০ মিনিট; ছাঁকনির পর ১২টি থাকলে কত ঘণ্টা বাঁচে?(ক) ১ − ০.৯৯৮৪০০ ≈ ১ − ০.৪৪৯ = ৫৫.১%. ২০০টিতে ১ − ০.৯৯৮২০০ ≈ ৩৩.০%. অর্ধেক package কমালে ঝুঁকি অর্ধেক হয় না, কিন্তু ২২ শতাংশ-বিন্দু কমে।
(খ)
ut-কেtuকরা হয়েছে, পাশাপাশি অদলবদল, তাই ১. সাধারণ Levenshtein-এ দুটি অক্ষর বদলাতে হয়, তাই ২.(গ) আগে ৯০ × ২০ = ১,৮০০ মিনিট = ৩০ ঘণ্টা। পরে ১২ × ২০ = ২৪০ মিনিট = ৪ ঘণ্টা। সাশ্রয় ২৬ ঘণ্টা। বাকি ৭৮টি মুছে যায় না, নিয়মিত update-এ আসে।
-
Hash যাচাই (command, নিজের ফোল্ডারে): একটি নকল ফাইল বানান, তার
SHA256SUMSতৈরি করুন, যাচাই করুন। তারপর ফাইলে একটি অক্ষর যোগ করে আবার যাচাই করুন। Exit code কত হয়?printf 'fake package bytes: demo 1.0.0\n' > demo-1.0.0.tgz sha256sum demo-1.0.0.tgz > SHA256SUMS sha256sum -c SHA256SUMS printf 'x' >> demo-1.0.0.tgz sha256sum -c SHA256SUMS; echo "exit=$?"আমাদের scratch ফোল্ডারে চালানো আসল ফল:
demo-1.0.0.tgz: OK demo-1.0.0.tgz: FAILED sha256sum: WARNING: 1 computed checksum did NOT match exit=1Exit code ১ হওয়ায় CI-তে এই লাইন job থামিয়ে দেবে। এখানেই তফাত: মানুষ warning উপেক্ষা করতে পারেন, pipeline-কে থামতে শেখানো যায়। লক্ষ করুন,
SHA256SUMSফাইলটিও ফাইলের পাশে একই জায়গা থেকে এলে হামলাকারী দুটিই বদলাতে পারেন। তাই hash তালিকা নিজে স্বাক্ষরিত হওয়া দরকার, অথবা lockfile-এর মতো আপনার repository-তে থাকা দরকার। -
নকশার সমালোচনা: একটি দল বলল, “আমাদের pipeline ঠিক আছে।” ব্যবস্থা এমন: self-hosted runner মাসের পর মাস একই মেশিন; workflow-র শুরুতে সব job-এ
write-all; বাইরের action@main-এ; pull request-এর test job-এ production deploy token; dependency বসেnpm installদিয়ে; দুটি registry মেশানো। অন্তত পাঁচটি সমস্যা আর তার প্রতিকার লিখুন।একই মেশিন: এক job-এর আপস পরের job-এ টিকে থাকে। প্রতিকার ephemeral runner.
write-all: token চুরি হলে repository বদলানো যায়। ডিফল্ট read, দরকারে job ধরে বাড়তি অধিকার।@main: বাইরের কোড যেকোনো সময় বদলাতে পারে। পূর্ণ commit hash, bot দিয়ে update. PR job-এ deploy token: যাচাইহীন কোড সবচেয়ে দামি secret পায়। Secret শুধু আলাদা, সুরক্ষিত release job-এ, workload identity দিয়ে।npm install: lockfile পাল্টে যেতে পারে। CI-তেnpm ci. দুটি registry: dependency confusion-এর রাস্তা। একটি proxy আর scope. -
ফল আন্দাজ করুন: SBOM-এ আছে
a@1,b@2,c@3. Advisory: T1 → a@1, T2 → b@2, T3 → d@4, T4 → c@3, T5 → a@1. VEX: T1not_affected, T4fixed, T5under_investigation. Statement না থাকলেaffected. ফিল্টারের নিয়মstatus !== 'not_affected'. শেষ লাইনগুলো কী হবে? নিয়মটিতে কোনো ত্রুটি আছে কি?T3-এর
d@4SBOM-এ নেই, তাই মিলেছে ৫টির ৪টি। T1 বাদ, কারণnot_affected. বাকি থাকে T2, T4, T5:matched 4 of 5; action queue: 3 queue: T2, T4, T5ত্রুটি আছে। T4
fixed, তবু তালিকায় রয়ে গেল। নিয়মটি হওয়া উচিত!['not_affected', 'fixed'].includes(status). তখন তালিকা হবে T2 আর T5, সংখ্যা ২. তবেfixedবিশ্বাস করার আগে দেখুন, আপনার চালু version-এ সংশোধনটি সত্যিই আছে কি না।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমএকটি dependency আপস হলে করণীয়গুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Advisory প্রাথমিক উৎসে মিলিয়ে দেখা
- SBOM দিয়ে কোথায় কোথায় আছে তা বের করা
- Deploy আর update থামানো, version নিষিদ্ধ করা
- ঝুঁকিতে থাকা build-এর secret বদলানো
- পরিষ্কার version-এ নতুন build করে ধাপে rollout
- Log খোঁজা, রিভিউ আর নতুন check যোগ
CI-তে একটি package-এর hash মিলছে না, যদিও version একই আছে। সবচেয়ে ভালো পদক্ষেপ কোনটি?
- Lockfile মুছে নতুন করে বানানো
- Build থামিয়ে কেন hash বদলাল তা অনুসন্ধান করা
- Hash যাচাই সাময়িকভাবে বন্ধ করা
- কয়েকবার build চালিয়ে দেখা, পাস করলে এগিয়ে যাওয়া
একটি প্রতিষ্ঠানের ভেতরের package আর public registry-র package-এর নাম একই হতে পারে, আর package manager দুই জায়গাতেই খোঁজে। এই ঝুঁকির নাম আর মূল প্রতিকার কী?
- Typosquatting; বানান যাচাই
- Log4Shell; SBOM বানানো
- Dependency confusion; একটি নিয়ন্ত্রিত registry আর scope
- Build compromise; code signing
SBOM-এ একটি library আছে যার advisory প্রকাশিত হয়েছে। VEX-এ লেখা not_affected, কারণ vulnerable_code_not_in_execute_path. এর অর্থ কী?
- Library আছে, কিন্তু দুর্বল কোড এই পণ্যে চলার পথে নেই বলে ঘোষণা করা হয়েছে
- Library-টি পণ্যে একেবারেই নেই
- দুর্বলতাটি patch করা হয়েছে
- দল এখনো অনুসন্ধান করছে
SLSA v1.2-এর Build track-এ L2 আর L3-র মূল পার্থক্য কোনটি?
- L2-তে provenance লাগে না, L3-তে লাগে
- L3 প্রমাণ করে কোডে কোনো দুর্বলতা নেই
- L3-তে দুইজনের code review বাধ্যতামূলক
- L2 build-এর পরের বদল ঠেকায়, L3 build চলাকালের বদলও ঠেকায়
একটি vendor-এর update-এর স্বাক্ষর বৈধ, তবু পরে জানা গেল তাতে ক্ষতিকর কোড ছিল। এটি কীভাবে সম্ভব?
- SHA-256 ভেঙে একই hash-এর অন্য ফাইল বানানো হয়েছে
- ক্ষতিকর অংশ স্বাক্ষরের আগেই, যেমন build পর্যায়ে ঢুকেছিল
- Certificate-এর মেয়াদ শেষ হয়ে গিয়েছিল
- যাচাইয়ের গণিতে সবসময় কিছু ভুলের সম্ভাবনা থাকে
একটি ক্ষতিকর package-এর install script আপনার CI runner-এ চলেছে। Package সরিয়ে পরিষ্কার version বসানোর পরও জরুরি কোন কাজটি বাকি থাকে?
- OpenSSF Scorecard-এ package-এর নম্বর দেখা
- শুধু SBOM আবার তৈরি করা
- Runner-এ পাওয়া সব secret বদলানো আর egress log খোঁজা
- Lockfile-এর ফরম্যাট বদলানো
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- শিকলের পাঁচ জোড়া: source, dependency, build, artifact, deploy. প্রতিটির ঝুঁকি আর বাধা আলাদা।
- Hash আর স্বাক্ষর বলে “একই জিনিস, এই উৎস থেকে”, বলে না “ভালো জিনিস”।
- Hash-সহ lockfile, একটি registry, কম dependency. সাধারণ update ধীর পথে, নিরাপত্তা-update দ্রুত পথে।
- SBOM বলে কী আছে, SCA মেলায়, reachability আর VEX অগ্রাধিকার ঠিক করে। Provenance আর SLSA বলে কীভাবে তৈরি।
- আপস হলে: যাচাই, পরিধি, থামানো, secret বদল, পরিষ্কার build, খোঁজা, শেখা। পরীক্ষা শুধু নিজের বা অনুমোদিত সিস্টেমে।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ৪৯ · নিরাপত্তা পরীক্ষা — SAST, DAST, fuzzing আর code reviewপরবর্তী পর্বনিজের কোডের ভুল খোঁজার পদ্ধতিগুলোর শক্তি আর সীমা।
- সাইবার নিরাপত্তা · কোর্স হোম৮০টি পর্বপুরো কোর্সের রোডম্যাপ।
- DevSecOpsপাশের ট্র্যাকPipeline-এ নিরাপত্তার যাচাই বসানো।
- Container registryপাশের ট্র্যাকImage রাখা, scan আর digest দিয়ে বাঁধা।
- Git নিরাপত্তাগভীরে যানRepository, commit signing আর secret সামলানো।