Dependency Cooldown: راهی برای مقابله با حملات زنجیره تامین npm
خلاصهٔ کاملتر
امنیت زنجیره تامین نرمافزار (supply chain security) داره به یکی از داغترین چالشهای دنیای توسعه تبدیل میشه. تا همین چند وقت پیش، نگرانی اصلی تیمها این بود که وابستگیها رو بهروز نگه دارن تا آسیبپذیریهای شناختهشده انباشته نشه. ولی حالا داریم میبینیم که طرف دیگه این معادله هم خطر داره: پکیجهایی که تازه منتشر شدن، میتونن مخرب باشن.
گزارش State of DevSecOps دیتادوگ در سال ۲۰۲۶ نشون میده که نصب سریع آپدیتهای جدید (ظرف یه روز از انتشار) ریسک جدی داره. نصف سازمانهای بررسیشده حداقل یه پکیج رو همون روز انتشار نصب کردن، و اپلیکیشنهای جاوااسکریپت با ۵۴ درصد بالاتر از میانگین بودن.
ماجرای Axios آخرین و شاید بزرگترین نمونه از این دسته حملاته. این پکیج بیش از ۱۰۰ میلیون دانلود هفتگی داره و ۱۷۴ هزار پکیج npm دیگه بهش وابستهان. مهاجمها با بهخطر انداختن حساب یه نگهدارنده (maintainer)، نسخه مخربی رو منتشر کردن. قبل از این هم حملات s1ngularity و Shai-Hulud بیش از ۱۳۰۰ پکیج رو آلوده کردن. این مشکل فقط مختص جاوااسکریپت هم نیست؛ Python و GitHub Actions هم قربانی شدن.
چرا npm اینقدر آسیبپذیره؟ چون سرعتش شمشیر دولبهست. انتشار یه نسخه جدید فقط چند ثانیه طول میکشه و بلافاصله در دسترس همهجای دنیاست. CI/CD پایپلاینها هم معمولاً همون لحظه اون رو برمیدارن. برخلاف اکوسیستمهای دیگه که چکپوینتهای طبیعی دارن، npm هیچ friction ای نداره. در نتیجه یه پکیج مخرب میتونه ظرف چند دقیقه و بدون هیچ دخالت انسانی، منتشر بشه.
یه مشکل دیگه هم semantic versioning هست. وقتی توی package.json از ^ یا ~ استفاده میکنی، داری به نسخههای آیندهای که هنوز وجود ندارن اعتماد میکنی:
"dependencies": {
"dep_1": "^1.0.0",
"dep_2": "~2.2.0",
"dep_3": "3.2.2"
}در این مثال، dep_1 و dep_2 میتونن خودبهخود به نسخههای جدیدتری آپدیت بشن، در حالی که dep_3 پین شده و فقط همون نسخه مشخص نصب میشه. «non-breaking» بودن یه نسخه به معنای بیخطر بودنش نیست.
راهحل پیشنهادی: Dependency Cooldown. ایده سادهست: یه تأخیر عمدی قبل از اینکه اجازه بدی یه نسخه تازهمنتشرشده نصب بشه. اگه این تأخیر حداقل ۱۲ ساعت میبود، نه Axios و نه s1ngularity گسترش پیدا نمیکردن؛ چون هر دو ظرف ۳ تا ۴ ساعت شناسایی شدن. توصیه رایج، یه هفته تأخیره.
خوشبختانه ابزارهای اصلی این قابلیت رو اضافه کردن. npm از نسخه ۱۱.۱۰.۰ یه تنظیم جدید داره:
# .npmrc
min-release-age=7pnpm و Yarn هم از سپتامبر ۲۰۲۵ این امکان رو دارن:
# pnpm-workspace.yaml
minimumReleaseAge: 10080 # 7 days, in minutes
# .yarnrc.yml
npmMinimalAgeGate: "7d"Dependabot هم تنظیمات انعطافپذیرتری ارائه میده که میشه برای هر نوع آپدیت (patch، minor، major) و اکوسیستمهای مختلف از جمله GitHub Actions و Python تنظیمش کرد.
البته cooldown رامبد نیست. مهاجمهای صبورتر ممکنه اجرای کد مخرب رو تا بعد از پنجره انتظار به تعویق بندازن. این روش همچنین در برابر آسیبپذیریهای سنتی (مثل Spring4Shell) که توی پکیجهای قبلاً منتشرشده هستن، محافظتی نمیده. Datadog برای کمک به این مشکل دو ابزار اوپنسورس منتشر کرده: GuardDog که پکیجهای npm و PyPI رو قبل از نصب آنالیز میکنه، و Supply-Chain Firewall که نصب پکیجهای مخرب رو مستقیماً روی ورکاستیشن توسعهدهنده بلاک میکنه.
نکات کلیدی:
- حملات زنجیره تامین npm در حال افزایشه؛ Axios، s1ngularity و Shai-Hulud آخرین نمونهها هستن
- نصب پکیج در روز اول انتشار، ریسک بالایی داره
- Semantic versioning با ^ و ~ میتونه بدون اطلاع شما کد ناشناخته وارد پروژه کنه
- Cooldown یه هفتهای در npm (min-release-age=7)، pnpm و Yarn قابل تنظیمه
- Dependabot هم cooldown داره و برای اکوسیستمهای مختلف قابل تنظیمه
- این روش در برابر آسیبپذیریهای قدیمی و مهاجمهای صبور کافی نیست




