حمله به زنجیره تأمین npm از اعتماد توسعهدهنده به وابستگیها استفاده میکند. برنامه شما ممکن است کد مشکوک مستقیمی نداشته باشد، اما یکی از بستههایی که هنگام نصب یا اجرا وارد پروژه میشود آلوده شده باشد. متن قبلی این صفحه از یک حمله با بیش از ۱۵۰ بسته سخن میگفت، بدون اینکه تاریخ و فهرست نسخهها را معرفی کند. چنین عددی برای تصمیم امنیتی کافی نیست. در این بازنویسی، یک رخداد مستند را از اصول عمومی دفاع جدا میکنیم تا خواننده بداند چه چیزی خبر تاریخی است و چه چیزی روش کار تیم.
رخداد مستند چه بود؟
GitHub در گزارش سپتامبر ۲۰۲۵ توضیح داده که در ۱۴ سپتامبر از حمله Shai-Hulud مطلع شد. در این حمله، حسابهای نگهدارنده آلوده شدند و اسکریپتهای مخرب پس از نصب به بستهها راه یافتند. تاریخ این گزارش را نباید به یک حادثه فرضی در ۲۰۲۶ تبدیل کرد. نام بسته و نسخه آلوده نیز باید از اطلاعیه مربوط به همان رخداد خوانده شود؛ تعداد دانلود یک بسته با تعداد پروژههای واقعاً آسیبدیده برابر نیست.
برای بررسی یک خبر امنیتی، دنبال سه داده بگردید: نسخه آسیبدیده، مسیر اجرای کد و اقدام اصلاحی. اگر خبر فقط از بزرگی حمله حرف میزند، هنوز نمیدانید پروژه شما در محدوده آن هست یا نه. رخدادهای متفاوت npm را هم با یکدیگر ترکیب نکنید. ممکن است در یک مورد کد مرورگر تغییر کرده باشد و در مورد دیگر اسکریپت نصب اطلاعات محیط توسعه را بخواند. این تفاوت محل بررسی، حسابهای درگیر و دامنه پاکسازی را عوض میکند.
اعتماد در کدام مرحله منتقل میشود؟
وقتی یک بسته را اضافه میکنید، به کد منتشرشده و سازوکار انتشار آن اعتماد میکنید. وابستگی مستقیم میتواند چند وابستگی دیگر داشته باشد و آنها هم بستههای تازهای وارد کنند. نام آشنای بسته در package.json همه این درخت را نشان نمیدهد. یک تغییر کوچک در نسخه ظاهراً فرعی ممکن است کد جدیدی وارد مسیر نصب کند. Semantic Versioning قرارداد تغییرات مورد انتظار است؛ برچسب patch تضمین نمیکند که حساب ناشر سالم مانده یا فایل انتشار بررسی امنیتی شده است.
بسته هنگام نصب ممکن است اسکریپت اجرا کند. این قابلیت برای ساخت binding بومی یا آمادهسازی فایلها کاربرد دارد، اما همان مسیر به کد بسته دسترسی اجرایی میدهد. در محیطی که رازهای CI حاضرند، پیامد نصب وابستگی با نصب در محیط محدود فرق میکند. سیاست نصب را پیش از حادثه روشن کنید: کدام بسته واقعاً به اسکریپت نیاز دارد، چه کسی آن نیاز را بررسی میکند و اجرای آن در چه محیطی مجاز است. خاموشکردن بیفکر همه اسکریپتها هم میتواند ساخت مشروع پروژه را متوقف کند.
یک مسیر دیگر، اشتباه در انتخاب نام یا registry است. بستهای با نام نزدیک به کتابخانه معروف ممکن است هنگام تایپ وارد پروژه شود. در سازمانی که بسته خصوصی دارد، تنظیم نادرست منبع دریافت هم مسئله جداگانهای ایجاد میکند. اسامی scope، آدرس registry و فایل تنظیمات پروژه را همراه وابستگیها بازبینی کنید. چنین بازبینیای به خواندن diff محدود نمیشود؛ باید بدانید کد از کدام منبع دریافت میشود و چه کسی امکان انتشار نسخه بعدی را دارد.
Lockfile چه کمکی میکند؟
Lockfile نسخههای حلشده را ثبت میکند تا نصبها قابل تکرارتر باشند. طبق مستندات npm ci، این فرمان به lockfile موجود نیاز دارد و در صورت ناسازگاری آن با package.json خطا میدهد، به جای اینکه فایل قفل را خودکار تغییر دهد. این رفتار برای pipeline مفید است، چون تغییر وابستگی را به فرایند بازبینی منتقل میکند. با این حال، نسخه آلودهای که در lockfile ثبت شده است با نصب تکرارپذیر سالم نمیشود. فایل قفل پاسخ مسئله تغییر ناخواسته است، نه حکم سلامت همه کدها.
در بازبینی تغییر وابستگی، فقط نسخه سطر اول را نبینید. بستههای تازه، تغییر منبع دریافت و تغییر اسکریپتهای پروژه را هم بررسی کنید. اگر یک بهروزرسانی کوچک درخت بزرگی را عوض کرده، دلیلش را در توضیح تغییر بخواهید. تغییر نسخه ابزار نصب هم میتواند شکل lockfile را عوض کند و diff را شلوغ کند. بهتر است این تغییر را از بهروزرسانی کتابخانه جدا انجام دهید تا بازبین بتواند بخش معنایی تغییر را تشخیص دهد.
Audit را با تضمین سلامت اشتباه نگیرید
npm audit برای بررسی گزارشهای آسیبپذیری شناختهشده در وابستگیهاست. راهنمای رسمی این فرمان نحوه تولید گزارش و گزینههای اصلاح را توضیح میدهد. گزارشی بدون مورد شناختهشده، نبود هر نوع بدافزار یا خطای منطقی را ثابت نمیکند. ممکن است آلودگی تازه هنوز در داده گزارش وارد نشده باشد. خروجی ابزار را در کنار اطلاعیه ناشر، تغییرات بسته و سیاست دسترسی تیم بخوانید. ابزار خودکار بخشی از دید شماست و نباید جای همه بررسیها بنشیند.
اصلاح خودکار نیز تصمیم معماری نیست. نسخه جایگزین ممکن است قرارداد API را تغییر دهد و مسیرهای پروژه را تحت تأثیر بگذارد. برای هر پیشنهاد، نسخه مقصد، تغییرات ناسازگار و دامنه وابستگی را بخوانید. استفاده از گزینههای اجباری بدون فهم تغییر ممکن است مسئله جدیدی بسازد. اگر اصلاح فوری ممکن نیست، تصمیم موقت را با دلیل، مسئول و زمان بازبینی ثبت کنید. عبارت «بعداً درست میکنیم» بدون مالک مشخص معمولاً به باقیماندن همان وضعیت منتهی میشود.
دسترسی CI را محدود کنید
یک job ساخت معمولاً برای خواندن کد و تولید خروجی به همه مجوزهای انتشار نیاز ندارد. دسترسی خواندن، نوشتن مخزن، انتشار بسته و استقرار را جدا تعریف کنید. راز انتشار فقط در مرحلهای حاضر باشد که واقعاً انتشار انجام میدهد. اگر یک Pull Request از مشارکتکننده بیرونی میآید، رفتار workflow و منابع در دسترسش را با دقت بررسی کنید. محدودیت مجوز باید از ساختار کار بیاید، نه از این فرض که نام بستهها معروف است و بنابراین اجرای آنها امن خواهد بود.
انتشار مبتنی بر OIDC میتواند نیاز به نگهداری بعضی توکنهای طولانیعمر را کم کند. GitHub در اطلاعیه تغییرات احراز هویت npm مهاجرت به Trusted Publishing را مطرح کرده است. برای استفاده، شرایط فعلی پشتیبانی و تنظیمات repository را از مستندات همان سرویس بخوانید. این روش هم به هویت workflow و قواعد انتشار وابسته است. اگر workflow اجازه تغییر بیمحدودیت داشته باشد، حذف یک secret به تنهایی همه مسیرهای سوءاستفاده را نمیبندد.
محیط ساخت را تا حد ممکن از داده حساس غیرضروری خالی نگه دارید. اتصال مستقیم به پایگاه داده تولید یا کلید شخصی یک توسعهدهنده معمولاً برای نصب وابستگی لازم نیست. رازها را با نام و کاربرد مشخص ثبت کنید و برای تغییر مسئولیت اعضا فرایند لغو دسترسی داشته باشید. فهرست رازهای بیاستفاده را دورهای مرور کنید. هر مجوز اضافه دامنه پیامد یک اجرای مخرب را بیشتر میکند، حتی اگر احتمال رخداد را با یک عدد دقیق نتوانید بیان کنید.
اگر نسخه مشکوک نصب شده است
اول انتشار و اجرای مسیر مشکوک را متوقف کنید و محدوده زمانی را ثبت کنید. بدانید بسته روی دستگاه توسعه، runner یا سرور نصب شده و در آن لحظه چه دادههایی در دسترس بودهاند. فقط حذف پوشه node_modules پاسخ کامل نیست. کد مخرب ممکن است پیش از حذف اجرا شده باشد. شواهد لازم را طبق فرایند تیم نگه دارید و از اجرای دوباره همان نسخه برای «اطمینان» خودداری کنید. بررسی باید با اطلاعات رخداد و محیط واقعی هماهنگ باشد.
اگر رازها در معرض دسترسی بودهاند، لغو و جایگزینی آنها را از محیط مورد اعتماد انجام دهید. تغییر یک متغیر در pipeline بدون ابطال اعتبار قبلی کافی نیست. حسابهایی که امکان انتشار یا تغییر workflow دارند اولویت بررسی بیشتری دارند. رخدادهای دسترسی و انتشار را مرور کنید تا معلوم شود آلودگی به پروژه دیگری منتقل شده یا نه. تعیین دامنه آسیب کار حدسی نیست؛ باید میان دسترسی ممکن، مشاهده واقعی و مورد تأییدشده فرق بگذارید و این تفاوت را در گزارش حفظ کنید.
بازسازی محیط باید از نسخهها و تنظیمات مورد اعتماد شروع شود. پیش از بازگرداندن pipeline، معلوم کنید مسیر اولیه ورود چه بود: حساب نگهدارنده، توکن، تغییر workflow یا بسته اشتباه. اگر علت ناشناخته بماند، ساخت دوباره محیط میتواند همان رفتار را تکرار کند. برای اطلاعرسانی داخلی، نام بسته، نسخه، بازه زمانی و اقدام انجامشده را بنویسید. چنین گزارشی به اعضای دیگر امکان میدهد وضعیت پروژه خودشان را بررسی کنند و از تکرار شایعه یا عدد بیمنبع جلوگیری میکند.
یک روال قابل نگهداری برای تیم
هر وابستگی تازه باید کاربرد مشخص داشته باشد. برای یک تابع کوچک، هزینه ورود و نگهداری بسته را با نوشتن کد محدود مقایسه کنید، بدون اینکه نتیجه بگیرید همه وابستگیها بد هستند. هنگام انتخاب، فعالیت نگهداری، کیفیت مستندات و تناسب API را ببینید. وابستگی متروک که فقط از ترس تغییر باقی مانده، برای تیم هزینه پنهان میسازد. مقاله Code Review مؤثر درباره روشنکردن دلیل تغییر و بازخورد کاربردی توضیح میدهد.
مسئول پیگیری اطلاعیهها و مالک وابستگیهای حساس را مشخص کنید. کار امنیت نباید فقط هنگام انتشار خبر حمله شروع شود. تغییرات کوچک و قابل بررسی، نصب تکرارپذیر، مجوز محدود و گزارش حادثه روشن، روالی میسازند که در روز عادی هم قابل اجراست. اگر تیم شما کوچک است، از فهرست کوتاه بستههای اصلی و مسیرهای انتشار شروع کنید. همین فهرست به شما میگوید هنگام خبر بعدی کجا را نگاه کنید و کدام تصمیم باید بهسرعت گرفته شود.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!