أمان تطبيقات C++: أهم 10 ثغرات للمبتدئين

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

أمان تطبيقات C++: أهم 10 ثغرات للمبتدئين

\n\n

تمنح لغة C++ المطور تحكمًا هائلاً في الذاكرة والأداء، لكن هذه الحرية تأتي بمسؤولية كبيرة. وفقًا لـ OWASP و CWE، غالبًا ما تنشأ الثغرات في تطبيقات C++ بسبب سوء التعامل مع الذاكرة، وعدم التحقق من الحدود، وعدم الانتباه عند التعامل مع المؤشرات. في هذه المقالة، سنستعرض 10 من أكثر الثغرات شيوعًا التي يواجهها المبتدئون. ستتعلم كيفية اكتشافها، والأهم من ذلك، كيفية تجنبها.

\n\n

1. تجاوز سعة المخزن المؤقت (Buffer Overflow)

\n

كلاسيكيات هذا المجال. تنشأ هذه الثغرة عندما يكتب البرنامج بيانات تتجاوز حدود المخزن المؤقت المخصص. يمكن للمهاجم الكتابة فوق مناطق الذاكرة المجاورة، بما في ذلك عنوان إرجاع الدالة، والتحكم في تنفيذ الكود.

\n\n
// كود ضعيف\nvoid vulnerable() {\n    char buffer[10];\n    std::cout << "أدخل سلسلة: ";\n    std::cin >> buffer; // لا يوجد فحص للطول!\n    std::cout << buffer << std::endl;\n}\n\n// إصدار آمن\nvoid safe() {\n    char buffer[10];\n    std::cout << "أدخل سلسلة: ";\n    std::cin.getline(buffer, sizeof(buffer));\n    std::cout << buffer << std::endl;\n}
\n\n

كيف تحمي نفسك: استخدم دائمًا الدوال ذات الحد الأقصى للطول (strncpy، snprintf، std::string). تجنب gets() و strcpy().

\n\n

2. تسرب الذاكرة (Memory Leaks)

\n

إذا قمت بتخصيص ذاكرة عبر new ولكن نسيت تحريرها عبر delete، فسيبدأ البرنامج في "استهلاك" ذاكرة الوصول العشوائي تدريجيًا. بالنسبة لتطبيقات الخادم، هذه كارثة - بعد بضع ساعات من التشغيل، سيتعطل الخدمة مع خطأ std::bad_alloc.

\n\n
// مثال على تسرب\nvoid leak() {\n    int* ptr = new int(42);\n    // نسينا delete ptr;\n}\n\n// النهج الصحيح\nvoid noLeak() {\n    std::unique_ptr<int> ptr = std::make_unique<int>(42);\n    // سيتم تحرير الذاكرة تلقائيًا عند الخروج من نطاق الرؤية\n}
\n\n

كيف تحمي نفسك: استخدم المؤشرات الذكية (std::unique_ptr، std::shared_ptr). في الحالات القصوى - استخدم RAII (Resource Acquisition Is Initialization).

\n\n

3. المؤشرات المعلقة (Dangling Pointers)

\n

يشير المؤشر إلى ذاكرة تم تحريرها بالفعل. إلغاء الإشارة إلى مثل هذا المؤشر هو سلوك غير محدد (UB). قد يؤدي ذلك إلى تعطل البرنامج أو، الأسوأ من ذلك، إلى تنفيذ كود ضار.

\n\n
int* dangling() {\n    int x = 10;\n    return &x; // خطأ: نعيد عنوان متغير محلي!\n}\n\n// بشكل صحيح - تخصيص ذاكرة في الكومة\nint* safe() {\n    int* ptr = new int(10);\n    return ptr;\n}
\n\n

كيف تحمي نفسك: بعد delete، قم دائمًا بتعيين nullptr للمؤشر. استخدم المؤشرات الذكية.

\n\n

4. تجاوز سعة الأعداد الصحيحة (Integer Overflow)

\n

عندما تتجاوز نتيجة عملية حسابية نطاق نوع البيانات، يحدث تجاوز. قد يؤدي ذلك إلى عواقب غير متوقعة، مثل تخصيص مخزن مؤقت صغير جدًا.

\n\n
void check_size(size_t user_size) {\n    // ثغرة: إذا كان user_size كبيرًا جدًا، فقد يصبح user_size + 1 صغيرًا\n    char* buffer = new char[user_size + 1];\n    // ...\n}\n\n// حماية\nvoid safe_check(size_t user_size) {\n    if (user_size > std::numeric_limits<size_t>::max() - 1) {\n        throw std::overflow_error("الحجم كبير جدًا");\n    }\n    char* buffer = new char[user_size + 1];\n}
\n\n

كيف تحمي نفسك: تحقق من الحدود قبل العمليات الحسابية. استخدم __builtin_add_overflow (GCC/Clang) أو مكتبات الحساب الآمن.

\n\n

5. المؤشرات الفارغة (Null Pointer Dereference)

\n

إلغاء الإشارة إلى مؤشر فارغ

المدونات

توصيات الكتب