عنوان:

‫ارتقاء امنیت برنامه‌های دات‌نت از طریق بازرسی بسته‌ها (Package Audits)


نویسنده: وحید نصیری
تاریخ: ۱۴۰۴/۰۲/۰۶ ۰۷:۲۷
آدرس: www.dntips.ir
مقدمه
استفاده از بسته‌های نرم‌افزاری (Packages) مانند بسته‌های نیوگت (NuGet) در اکوسیستم دات‌نت (.NET) به امری رایج تبدیل شده است. این بسته‌ها، که شامل کتابخانه‌ها و ابزارهای آماده هستند، فرآیند توسعه را تسریع می‌کنند، اما در عین حال می‌توانند خطراتی مانند آسیب‌پذیری‌های امنیتی (Vulnerabilities) را به همراه داشته باشند. یک آسیب‌پذیری در بسته‌ای که به پروژه شما اضافه شده، ممکن است منجر به حملات زنجیره تأمین نرم‌افزار (Software Supply Chain Attacks) شود، مانند آنچه در مورد آسیب‌پذیری Log4j مشاهده شد. شناسایی و مدیریت این آسیب‌پذیری‌ها، به‌ویژه در پروژه‌های دات‌نت، از اهمیت بسزایی برخوردار است، زیرا وابستگی‌های پروژه (Dependencies) اغلب شامل زنجیره‌ای پیچیده از بسته‌های مستقیم و غیرمستقیم (Transitive Dependencies) هستند.
این مقاله با هدف آموزش توسعه‌دهندگان دات‌نت، به بررسی روش‌های شناسایی آسیب‌پذیری‌های بسته‌های نوگت با استفاده از ابزارهای داخلی دات‌نت و فرآیندهای یکپارچه‌سازی مداوم (Continuous Integration) می‌پردازد.

۱. چرا شناسایی آسیب‌پذیری‌های بسته‌ها اهمیت دارد؟
هر پروژه دات‌نت معمولاً به چندین بسته نیوگت وابسته است که هر یک ممکن است وابستگی‌های خاص خود را داشته باشند. این زنجیره وابستگی‌ها می‌تواند به ده‌ها یا حتی صدها بسته گسترش یابد. اگر یکی از این بسته‌ها حاوی آسیب‌پذیری شناخته‌شده‌ای باشد، کل برنامه در معرض خطر قرار می‌گیرد. برای مثال، آسیب‌پذیری‌های معروف مانند CVE (Common Vulnerabilities and Exposures) یا GHSA (GitHub Security Advisory) می‌توانند به مهاجمان اجازه دهند کد مخرب اجرا کنند یا داده‌های حساس را به سرقت ببرند.
ابزارهای داخلی دات‌نت، مانند دستور dotnet list package --vulnerable، به توسعه‌دهندگان امکان می‌دهند تا بسته‌های آسیب‌پذیر را شناسایی کنند. این دستور از پایگاه داده مشاوره امنیتی گیت‌هاب (GitHub Advisory Database) استفاده می‌کند که اطلاعات به‌روز و معتبری درباره آسیب‌پذیری‌های شناخته‌شده ارائه می‌دهد. با این حال، شناسایی این آسیب‌پذیری‌ها تنها قدم اول است؛ توسعه‌دهندگان باید بتوانند این فرآیند را در چرخه توسعه خود ادغام کنند تا از امنیت مداوم برنامه اطمینان حاصل کنند.

۲. استفاده از دستورdotnet list package --vulnerable
یکی از قدرتمندترین ابزارهای داخلی دات‌نت برای شناسایی آسیب‌پذیری‌ها، دستور dotnet list package --vulnerable است که از نسخه ۵.۰.۲۰۰ به بعد SDK دات‌نت در دسترس است. این دستور بسته‌های پروژه را اسکن کرده و هرگونه آسیب‌پذیری شناخته‌شده را گزارش می‌دهد. برای اطمینان از بررسی کامل، استفاده از پارامتر --include-transitive ضروری است، زیرا این پارامتر وابستگی‌های غیرمستقیم را نیز در نظر می‌گیرد.
برای مثال، فرض کنید پروژه‌ای دارید که به بسته Newtonsoft.Json وابسته است. اجرای دستور زیر در مسیر پروژه یا راه‌حل (Solution) انجام می‌شود:
dotnet list package --vulnerable --include-transitive
خروجی این دستور ممکن است به این صورت باشد:
Project `MyProject` has the following vulnerable packages
   [net8.0]:
   Transitive Package      Resolved   Severity   Advisory URL
   System.Text.Json        8.0.0      High       https://github.com/advisories/GHSA-1234
این خروجی نشان می‌دهد که نسخه ۸.۰.۰ از بسته System.Text.Json دارای آسیب‌پذیری با شدت بالا (High Severity) است و لینک مشاوره امنیتی مربوطه را ارائه می‌دهد. توسعه‌دهندگان می‌توانند با مراجعه به این لینک، جزئیات بیشتری درباره آسیب‌پذیری و راه‌حل‌های پیشنهادی دریافت کنند.
نکته مهم این است که این دستور به‌تنهایی خطایی ایجاد نمی‌کند، حتی اگر آسیب‌پذیری پیدا شود. بنابراین، برای استفاده در خط لوله‌های CI/CD (Continuous Integration/Continuous Deployment)، نیاز به اسکریپت‌های اضافی برای توقف فرآیند در صورت کشف آسیب‌پذیری است.

۳. ادغام شناسایی آسیب‌پذیری در خط لوله CI/CD
برای اطمینان از امنیت مداوم، بررسی آسیب‌پذیری‌ها باید بخشی از فرآیند CI/CD باشد. این کار به توسعه‌دهندگان اجازه می‌دهد تا پیش از استقرار برنامه (Deployment)، هرگونه مشکل امنیتی را شناسایی و برطرف کنند. یک روش ساده برای این منظور، استفاده از اسکریپت‌های بش (Bash Script) است که خروجی دستور dotnet list package --vulnerable را بررسی کرده و در صورت وجود آسیب‌پذیری، فرآیند ساخت (Build) را متوقف می‌کند.
به عنوان مثال، اسکریپت زیر می‌تواند در خط لوله CI/CD استفاده شود:
#!/bin/bash
dotnet list package --vulnerable --include-transitive > vuln.txt
if grep -q "has the following vulnerable packages" vuln.txt; then
    echo "Vulnerable packages found. Build failed."
    cat vuln.txt
    exit 1
else
    echo "No vulnerable packages found."
    exit 0
fi
این اسکریپت خروجی دستور را در فایلی ذخیره می‌کند و اگر عبارتی مبنی بر وجود بسته‌های آسیب‌پذیر پیدا شود، فرآیند ساخت را با خطا متوقف می‌کند. این روش به‌ویژه در ابزارهایی مانند GitHub Actions یا Azure DevOps بسیار کاربردی است.

نقش فایل .csproj و ویژگی NuGetAudit

فایل .csproj به عنوان منبع اصلی برای تمام مراجع بسته (Package references) عمل می‌کند. وجود حتی یک بسته آسیب‌پذیر در این فایل، به طور مستقیم یا غیرمستقیم، می‌تواند کل برنامه کاربردی را به خطر بیندازد.
نیوگت 6.8 ویژگی NuGetAudit را به عنوان یک پراپرتی ام‌اس‌بیلد (MSBuild property) معرفی کرده است که تشخیص آسیب‌پذیری را در زمان بازیابی (Restore) یا ساخت (Build) بهبود می‌بخشد. هنگامی که NuGetAudit روی مقدار true تنظیم شود، نیوگت یک بازرسی از وابستگی‌های نیوگت پروژه انجام داده و هشدارهایی را برای هرگونه آسیب‌پذیری شناسایی شده تولید می‌کند. این امکان را فراهم می‌سازد تا مسائل امنیتی قبل از استقرار برنامه کاربردی شناسایی و برطرف شوند. برای فعال کردن NuGetAudit، می‌توان قطعه کد زیر را به فایل .csproj اضافه کرد:
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <NugetAudit>true</NugetAudit>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="Refit" Version="7.2.1" />
    </ItemGroup>
</Project>
هنگامی که NuGetAudit فعال باشد، فرآیند ساخت برای هر بسته نیوگت با آسیب‌پذیری شناخته شده، هشدار تولید می‌کند. این هشدارها شامل اطلاعاتی درباره آسیب‌پذیری، مانند شدت و نسخه بسته آسیب‌دیده خواهد بود.

پیکربندی سطح جزئیات هشدارهای NuGet Audit

می‌توان سطح جزئیات هشدارهای نیوگت اودیت (NuGet audit) را با استفاده از پراپرتی NuGetAuditLevel پیکربندی کرد. این پراپرتی مقادیر زیر را می‌پذیرد:
  • None: هیچ هشدار بازرسی نمایش داده نمی‌شود.
  • Low: فقط هشدارهایی برای آسیب‌پذیری‌هایی با شدت پایین (Low) یا بالاتر نمایش داده می‌شوند. این مقدار پیش‌فرض است.
  • Moderate: فقط هشدارهایی برای آسیب‌پذیری‌هایی با شدت متوسط (Moderate) یا بالاتر نمایش داده می‌شوند.
  • High: فقط هشدارهایی برای آسیب‌پذیری‌هایی با شدت بالا (High) یا بحرانی (Critical) نمایش داده می‌شوند.
  • Critical: فقط هشدارهایی برای آسیب‌پذیری‌هایی با شدت بحرانی (Critical) نمایش داده می‌شوند.
برای مثال، برای تعیین سطح هشدار فقط برای آسیب‌پذیری‌های بحرانی، می‌توان پراپرتی NuGetAuditLevel را به صورت زیر در فایل .csproj تنظیم کرد:
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <NugetAudit>true</NugetAudit>
        <NugetAuditLevel>critical</NugetAuditLevel>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="Refit" Version="7.2.1" />
    </ItemGroup>
</Project>

اجبار به شکست ساخت در صورت وجود آسیب‌پذیری

در حالی که هشدارها مفید هستند، ممکن است نادیده گرفته شوند و در نتیجه آسیب‌پذیری‌ها به کد تولید راه پیدا کنند. برای جلوگیری از این امر، پراپرتی ام‌اس‌بیلد WarningsAsErrors می‌تواند با تبدیل هشدارهای مشخص شده به خطا، منجر به شکست ساخت شود. جدول زیر کدهای هشداری مرتبط را نشان می‌دهد:
کد هشدار (Warning Code)دلیل (Reason)
NU1900خطا در ارتباط با منبع بسته در هنگام دریافت اطلاعات آسیب‌پذیری.
NU1901بسته با شدت پایین آسیب‌پذیری.
NU1902بسته با شدت متوسط آسیب‌پذیری.
NU1903بسته با شدت بالا آسیب‌پذیری.
NU1904بسته با شدت بحرانی آسیب‌پذیری.
NU1905یک منبع بازرسی پایگاه داده آسیب‌پذیری ارائه نمی‌دهد.
برای مثال، برای تبدیل هشدار مربوط به آسیب‌پذیری‌های بحرانی به خطا، می‌توان پراپرتی WarningsAsErrors را به صورت زیر در فایل .csproj تنظیم کرد:
<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <TargetFramework>net8.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <NugetAudit>true</NugetAudit>
        <NugetAuditLevel>critical</NugetAuditLevel>
        <WarningsAsErrors>NU1904;</WarningsAsErrors>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
      <PackageReference Include="Refit" Version="7.2.1" />
    </ItemGroup>
</Project>
با این تنظیمات، در صورت وجود آسیب‌پذیری با سطح بحرانی، فرآیند ساخت با خطا مواجه خواهد شد.

۴. ابزارهای مکمل و رویکردهای مدرن
علاوه بر ابزارهای داخلی دات‌نت، ابزارهای شخص ثالث مانند NuGetDefense و Snyk می‌توانند قابلیت‌های پیشرفته‌تری ارائه دهند. برای مثال، NuGetDefense امکان توقف خودکار ساخت بر اساس شدت آسیب‌پذیری را فراهم می‌کند و از چندین منبع داده برای شناسایی آسیب‌پذیری‌ها استفاده می‌کند. همچنین، ابزارهایی مانند Finite State با اسکن پروژه‌های پیچیده دات‌نت، دقت بالایی در شناسایی آسیب‌پذیری‌ها ارائه می‌دهند.
اخیراً، مایکروسافت قابلیت NuGet Audit را معرفی کرده است که به‌صورت خودکار در فرآیند بازگردانی بسته‌ها (Restore) اجرا می‌شود و هشدارهایی درباره آسیب‌پذیری‌ها ارائه می‌دهد. این قابلیت از نسخه ۶.۱۲ نوگت و SDK دات‌نت ۹.۰.۱۰۰ در دسترس است. توسعه‌دهندگان می‌توانند با تنظیم ویژگی‌های MSBuild، مانند NuGetAuditSuppress، هشدارهای خاصی را نادیده بگیرند، که این امکان انعطاف‌پذیری بیشتری در مدیریت آسیب‌پذیری‌ها فراهم می‌کند.

۵. بهترین روش‌ها برای مدیریت آسیب‌پذیری‌ها
مدیریت آسیب‌پذیری‌ها فراتر از شناسایی آن‌هاست. در ادامه، چند توصیه کلیدی برای توسعه‌دهندگان دات‌نت ارائه می‌شود:
  • به‌روزرسانی منظم بسته‌ها: همیشه از آخرین نسخه‌های بسته‌ها استفاده کنید، مگر اینکه محدودیت‌های خاصی وجود داشته باشد. برای مثال، به‌روزرسانی بسته‌ای مانند Newtonsoft.Json به نسخه‌ای که آسیب‌پذیری را برطرف کرده، می‌تواند خطر را کاهش دهد.
  • بررسی وابستگی‌های غیرمستقیم: بسیاری از آسیب‌پذیری‌ها در وابستگی‌های غیرمستقیم یافت می‌شوند. همیشه از --include-transitive استفاده کنید.
  • استفاده از منابع معتبر: اطمینان حاصل کنید که بسته‌ها از منابع معتبر مانند nuget.org دانلود می‌شوند.
  • تست پس از به‌روزرسانی: به‌روزرسانی بسته‌ها ممکن است باعث مشکلات سازگاری (Compatibility Issues) شود. بنابراین، تست‌های خودکار و دستی پس از به‌روزرسانی ضروری است.

نتیجه‌گیری
شناسایی و مدیریت آسیب‌پذیری‌های بسته‌های نوگت در توسعه دات‌نت، یکی از مهم‌ترین جنبه‌های تضمین امنیت نرم‌افزار است. ابزارهایی مانند dotnet list package --vulnerable و قابلیت‌های جدید مانند NuGet Audit، فرآیند شناسایی آسیب‌پذیری‌ها را ساده‌تر کرده‌اند. با این حال، ادغام این ابزارها در خط لوله‌های CI/CD و استفاده از رویکردهای مکمل مانند ابزارهای شخص ثالث، می‌تواند امنیت پروژه‌ها را به سطح بالاتری برساند.
توسعه‌دهندگان دات‌نت باید با آگاهی از خطرات زنجیره تأمین نرم‌افزار و بهره‌گیری از ابزارهای موجود، پروژه‌های خود را در برابر تهدیدات ایمن نگه دارند. با اجرای منظم اسکن‌های امنیتی، به‌روزرسانی بسته‌ها و تست دقیق تغییرات، می‌توان از بسیاری از خطرات احتمالی پیشگیری کرد.


مشاهده مطلب اصلی