IRCNF

ایمنی حافظه اکنون یک مسئله امنیت ملی است — چرا ایالات متحده و اتحادیه اروپا از توسعه‌دهندگان می‌خواهند نوشتن در C را متوقف کنند

اشتراک‌گذاری:
ایمنی حافظه اکنون یک مسئله امنیت ملی است — چرا ایالات متحده و اتحادیه اروپا از توسعه‌دهندگان می‌خواهند نوشتن در C را متوقف کنند

در فوریه ۲۰۲۴، آژانس امنیت سایبری و زیرساخت ایالات متحده (CISA) گزارشی ۱۹ صفحه‌ای با عنوان «موردی برای نقشه‌های راه ایمن حافظه» منتشر کرد. دفتر مدیر سایبری ملی کاخ سفید نیز با گزارشی فنی که از تولیدکنندگان نرم‌افزار می‌خواست آسیب‌پذیری‌های ایمنی حافظه را حذف کنند، همراه شد. مرکز امنیت سایبری ملی بریتانیا، BSI آلمان و اداره سیگنال‌های استرالیا نیز آن را امضا کردند. پیام هر پنج آژانس یکسان بود: نوشتن نرم‌افزارهای حیاتی از نظر ایمنی در C و C++ را متوقف کنید.

این یک موضع حاشیه‌ای در میان دانشگاهیانی نیست که Haskell را ترجیح می‌دهند. این سیاست امنیتی هماهنگ آژانس‌های اصلی اطلاعاتی و امنیت سایبری جهان است که با دو دهه داده آسیب‌پذیری پشتیبانی می‌شود و شروع به تغییر نرم‌افزارهای واقعی عرضه‌شده کرده است.

ایمنی حافظه به چه معناست

ایمنی حافظه ویژگی‌ای است که یک برنامه نمی‌تواند حافظه را خارج از مرزهای تعیین‌شده بخواند یا بنویسد، به حافظه آزاد شده دسترسی پیدا کند یا از مقادیر مقداردهی‌نشده استفاده کند. زبان‌ها ایمنی حافظه را یا از طریق garbage collection (Java، Python، Go) یا از طریق قوانین مالکیت ایستا که در زمان کامپایل اعمال می‌شوند (Rust) اعمال می‌کنند. C و C++ هیچ‌کدام را ارائه نمی‌دهند: برنامه‌نویس مسئول مدیریت صحیح حافظه است و کامپایلر صحت را تأیید نمی‌کند.

نتیجه دسته‌ای از اشکالات است که از زمان ایجاد C در سال ۱۹۷۲ ادامه داشته است: سرریز بافر، آسیب‌پذیری‌های use-after-free، dereference اشاره‌گر null، خرابی heap و confusion نوع. این‌ها موارد لبه‌ای عجیب نیستند — آنها پراستفاده‌ترین کلاس آسیب‌پذیری در طبیعت هستند که به طور مداوم ۶۰–۷۰٪ از CVEهای بحرانی در پروژه‌های نرم‌افزاری بزرگ را تشکیل می‌دهند.

مرکز پاسخ امنیتی مایکروسافت در سال ۲۰۱۹ گزارش داد که حدود ۷۰٪ از تمام CVEهای محصولات مایکروسافت در ۱۲ سال گذشته مسائل ایمنی حافظه بوده‌اند. پروژه صفر گوگل در سال ۲۰۲۰ گزارش داد که ۶۷٪ از اشکالات با شدت بالای Chrome مربوط به ایمنی حافظه بوده است. هر دو رقم تا سال ۲۰۲۶ به طور سرسختانه ثابت باقی مانده‌اند، علیرغم سرمایه‌گذاری قابل توجه در ابزارها (fuzzing، sanitizerها، تحلیل استاتیک) — زیرا مشکل اصلی خود مدل زبان است، نه کیفیت ناکافی برنامه‌نویسان استفاده‌کننده از آن.

مقیاس مشکل به ارث رسیده

شدت وضعیت کنونی تابعی از این است که چه مقدار از زیرساخت‌های حیاتی بر روی کد C اجرا می‌شود. هسته لینوکس — پایه اکثر سرورها، دستگاه‌های Android، سخت‌افزار IoT و سیستم‌های embedded — تقریباً ۹۷٪ C است. کتابخانه OpenSSL که بیشتر ترافیک HTTPS را ایمن می‌کند، C است. SQLite، پراستفاده‌ترین پایگاه داده در جهان، C است. موتور JavaScript V8 که نیمی از مرور وب جهان را اجرا می‌کند، C++ است. هسته‌های Windows، macOS و iOS حاوی ده‌ها میلیون خط کد C و C++ هستند.

بازنویسی هر یک از این‌ها یک پروژه چند ماهه نیست. هسته لینوکس تقریباً ۳۰ میلیون خط کد دارد، با مشارکت‌کنندگانی در هزاران سازمان و فرآیند تغییراتی که عمداً با سرعت زمین‌شناسی حرکت می‌کند. پایگاه کد Google Chrome ۴۰ میلیون خط است. پرسیدن «چرا آن را فقط در Rust بازنویسی نمی‌کنید؟» مقیاس را اشتباه می‌فهمد: با نرخ بازنویسی ۱ میلیون خط در سال به ازای هر تیم، بازنویسی کامل پایگاه کد دهه‌ها طول می‌کشد و در هر مرحله اشکالات جدیدی ایجاد می‌کند.

رویکرد عملی جایگزینی تدریجی است: ابتدا پرخطرترین مؤلفه‌ها (تحلیل، مدیریت ورودی شبکه، رمزنگاری) را بازنویسی کنید، با استفاده از قابلیت هم‌عملی زبان برای اجرای ماژول‌های Rust در کنار C، و بپذیرید که زیرساخت C قدیمی برای ۲۰–۳۰ سال وجود خواهد داشت و به تدریج ایزوله می‌شود.

مسیر Rust

Rust که برای اولین بار در سال ۲۰۱۵ توسط Mozilla منتشر شد، زبان سیستم‌های ایمن حافظه اولیه‌ای است که برای این انتقال به کار گرفته می‌شود. سیستم نوع مالکیت و قرض‌گیری آن کل دسته اشکالات ایمنی حافظه را در زمان کامپایل جلوگیری می‌کند، بدون سربار garbage collection و با عملکرد نزدیک به C. هزینه آن یک منحنی یادگیری تند است: کامپایلر Rust کدی را رد می‌کند که کامپایلر C می‌پذیرد، زیرا کامپایلر Rust صحتی را اثبات می‌کند که C به برنامه‌نویس واگذار می‌کند.

منحنی پذیرش اکنون به اندازه‌ای تند است که یک تغییر ساختاری را نشان دهد. گوگل بخش‌های قابل توجهی از پشته‌های Bluetooth و WiFi اندروید را در Rust بازنویسی کرده است؛ تیم اندروید در سال ۲۰۲۴ گزارش داد که کد جدید در زبان‌های ایمن حافظه نرخ CVE ایمنی حافظه را برای آن مؤلفه‌ها تقریباً به صفر رسانده است، در حالی که مؤلفه‌های C قدیمی نرخ آسیب‌پذیری تاریخی خود را حفظ کرده‌اند. هسته لینوکس به طور رسمی Rust را به عنوان دومین زبان پیاده‌سازی در سال ۲۰۲۲ پذیرفت و اولین درایورهای Rust در هسته اصلی ادغام شده‌اند.

تیم Windows مایکروسافت در حال بازنویسی مؤلفه‌های هسته ویندوز در Rust است، با هدف بلندمدت جلوگیری از ورود اشکالات جدید ایمنی حافظه به پایگاه کد هسته. راهنمای NSA در سال ۲۰۲۲ به طور خاص Rust، Swift، Go، Kotlin و Java را به عنوان زبان‌های ترجیحی برای توسعه جدید در زمینه‌های امنیت ملی نام برد. قانون تاب‌آوری سایبری اتحادیه اروپا که در سال ۲۰۲۵ اجرایی شد، از تولیدکنندگان محصولات با عناصر دیجیتال می‌خواهد شیوه‌های «ایمن با طراحی» را نشان دهند — زبانی قانونی که به طور ضمنی زبان‌های ناایمن از نظر حافظه را در زمینه‌های حیاتی ایمنی جریمه می‌کند.

آنچه «ایمن از نظر حافظه» حل نمی‌کند

فشار سیاستی برای زبان‌های ایمن حافظه به خوبی مستند است، اما گاهی بیش از حد فروخته می‌شود. ایمنی حافظه از یک کلاس خاص از اشکالات جلوگیری می‌کند — اما از خطاهای منطقی، شکست‌های احراز هویت، آسیب‌پذیری‌های تزریق یا اشتباهات پیاده‌سازی رمزنگاری جلوگیری نمی‌کند. یک برنامه Rust می‌تواند به راحتی یک آسیب‌پذیری تزریق SQL داشته باشد، همانطور که یک برنامه C می‌تواند. یک برنامه Go می‌تواند یک خطای منطق تجاری داشته باشد که امکان افزایش امتیاز را فراهم کند. ایمنی حافظه یک شرط لازم برای امنیت است، نه یک شرط کافی.

همچنین تمایز معناداری بین Rust «ایمن» و «ناایمن» وجود دارد. کتابخانه استاندارد Rust حاوی بلوک‌های unsafe است — بخش‌هایی که برنامه‌نویس به طور صریح بررسی‌های مالکیت را برای کد حیاتی از نظر عملکرد غیرفعال می‌کند. این مناطق unsafe باید به صورت دستی تأیید شوند و آسیب‌پذیری‌هایی در آنها ممکن است. به عنوان مثال، race condition CVE-2022-21658 در کتابخانه استاندارد Rust، در پیاده‌سازی std::fs که به دقت بررسی شده بود وجود داشت. Rust کد unsafe را نادر و بسیار قابل مشاهده می‌کند، اما آن را حذف نمی‌کند.

بحث عملکرد علیه زبان‌های ایمن حافظه تا حد زیادی به صورت تجربی حل شده است. در بیشتر بارهای کاری، Rust در محدوده ۵–۱۵٪ کد معادل C عمل می‌کند و در برخی معیارها از C بهتر عمل می‌کند زیرا کامپایلر می‌تواند با اثبات ضمانت‌های aliasing و طول عمر، بهینه‌سازی‌های تهاجمی‌تری انجام دهد. سربار باقی‌مانده عمدتاً در موارد آسیب‌شناختی است، نه در نوع کد سیستم که بسته‌های شبکه، عملیات سیستم فایل یا تجزیه پروتکل را مدیریت می‌کند.

ده سال آینده

فشار دولت اثرات قابل اندازه‌گیری دارد. ابتکار Secure by Design CISA که در سال ۲۰۲۳ راه‌اندازی شد، تعهداتی از بیش از ۲۰۰ فروشنده بزرگ نرم‌افزار برای ایجاد نقشه‌های راه ایمن حافظه جمع‌آوری کرده است — برنامه‌های مشخص برای مهاجرت پایگاه‌های کد خاص از C و C++ در یک جدول زمانی منتشر شده. اولین گزارش‌های پیشرفت سالانه از آن فروشندگان حرکت متوسط اما واقعی را نشان داد: ماژول‌های جدید در Rust، APIهای ناایمن منسوخ شده، مهاجرت مؤلفه‌های تحلیل پرخطر.

جدول زمانی واقع بینانه برای کاهش معنادار آسیب‌پذیری‌های ایمنی حافظه در سراسر زیرساخت‌های حیاتی ۱۵–۲۰ سال است. کدی که امروز در Rust نوشته می‌شود برای دهه‌ها در تولید خواهد بود؛ C قدیمی که هنوز در حال اجراست منبع آسیب‌پذیری‌های بحرانی برای یک دوره مشابه خواهد بود. سوال سیاستی این نیست که آیا این انتقال را انجام دهیم — شواهد بسیار زیاد است که C و C++ خطر امنیتی غیرقابل قبولی در مقیاس ایجاد می‌کنند — بلکه این است که با توجه به هزینه‌های مهندسی و خطرات معرفی نقص‌های جدید در طول مهاجرت، با چه فشاری سرعت انتقال را افزایش دهیم.

آنچه تغییر کرده این است که این اکنون یک سوال سیاستی است، نه یک سوال آکادمیک. وقتی CISA چیزی را یک مسئله امنیت ملی می‌نامد و کاخ سفید یک گزارش فنی امضا می‌کند، الزامات خرید و مقررات نظارتی به دنبال آن می‌آید. حرکت به سوی پذیرش زبان‌های ایمن حافظه دیگر تنها توسط ترجیح توسعه‌دهندگان هدایت نمی‌شود — در حال کدگذاری در قراردادهای دولتی، قوانین مسئولیت محصول اتحادیه اروپا و الزامات بیمه است. C و C++ برای دهه‌ها در استفاده باقی خواهند ماند، اما موقعیت آنها به عنوان انتخاب پیش‌فرض برای سیستم‌های حیاتی جدید از نظر امنیت تمام شده است.

اشتراک‌گذاری:
ایمنی حافظه اکنون یک مسئله امنیت ملی است — چرا ایالات متحده و اتحادیه اروپا از توسعه‌دهندگان می‌خواهند نوشتن در C را متوقف کنند | IRCNF - Intelligent Reliable Custom Next-gen Frameworks