فا

‫ برنامه نويسي امن با زبان C – ورودي / خروجي (IO) – قسمت اول

IRCAR201101083
تاريخ: 26/10/89
شماره: IRCAR201101083
عنصر اصلي در برنامه‌نويسي امن با زبان‌هاي مختلف برنامه‌نويسي، مستندسازي خوب و استفاده از استانداردهاي قابل اجرا است. استانداردهاي كدنويسي، برنامه نويسان را ترغيب به پيروي از مجموعه‌اي متحدالشكل از قوانين و راهنمايي‌ها مي‌كند كه بر اساس نيازمندي‌هاي پروژه و سازمان تعيين شده است، نه بر اساس سلايق و مهارت‌هاي مختلف برنامه‌نويسان. به محض تعيين استانداردهاي مذكور، مي توان از آن به عنوان معياري براي ارزيابي كدهاي منبع، چه به صورت دستي و چه به صورت اتوماتيك استفاده كرد.
از استانداردهاي معروف در اين زمينه مي‌توان به استانداردCERT براي كدنويسي امن اشاره كرد كه يك سري از قوانين و پيشنهادات را براي كدنويسي امن با زبان‌هاي برنامه‌نويسي C، C++ و جاوا ارائه مي‌دهد. هدف از اين قوانين و پيشنهادات، حذف عادت‌هاي كدنويسي ناامن و رفتارهاي تعريف نشده است كه منجر به آسيب‌پذيري‌هاي قابل سوءاستفاده مي‌شود. به كارگيري استانداردهاي مذكور منجر به توليد سيستم‌هاي با كيفيت بالاتر مي‌شود كه در برابر حملات بالقوه، پايدارتر و مقاوم‌تر هستند.
در مقاله "آشنايي با استاندارد CERT براي برنامه‌نويسي امن"، كليات استاندارد CERT در زمينه مزبور را توضيح داديم و در سري مقاله‌هاي برنامه‌نويسي امن به زبان C به صورت تخصصي‌تر شيوه برنامه‌نويسي امن با اين زبان را مورد بررسي قرار مي‌دهيم. قابل ذكر است كه در اين استاندارد 89 قانون و 134 پيشنهاد براي برنامه‌نويسي امن با زبان C ارائه شده است كه در اين سري مقالات، مهمترين آنها را كه در سطح يك قرار دارند، شرح خواهيم داد. براي كسب اطلاعات بيشتر در مورد سطح‌بندي قوانين و پيشنهادات به مقاله "آشنايي با استاندارد CERT براي برنامه نويسي امن" مراجعه فرماييد. در مقاله حاضر به پيشنهادات و قوانين ارائه شده سطح اول در مورد ورودي - خروجي خواهيم پرداخت.
30. FIO01-C – در استفاده از توابعي كه از نام فايل براي شناسايي استفاده مي‌كنند، مراقب باشيد.
بسياري از آسيب‌پذيري‌هاي امنيتي مرتبط با فايل‌ها از آنجا ناشي مي‌شود كه برنامه سعي در دسترسي به فايلي نادرست دارد، زيرا نام فايل همانند يك طناب نازك به فايل اصلي وصل شده است. نام فايل هيچ گونه اطلاعاتي را در مورد طبيعت شئ فايل فراهم نمي‌كند. علاوه بر اين اتصال نام فايل به شئ فايل، هر بار كه نام فايل در يك عمليات استفاده مي‌شود، دوباره اعتبار سنجي مي شود. برعكس نام فايل، توصيف كننده هاي فايل (file descriptor) و اشاره گرها به فايل، توسط سيستم عامل به فايل اصلي در لايه هاي پاييني اتصال پيدا مي كنند. دسترسي به فايل توسط توصيف كننده و يا اشاره گر به جاي نام فايل، درجه اطمينان بيشتري را فراهم مي آورد. به همين دليل، توصيه مي‌شود، هر جا كه ممكن است فايل ها از طريق اشاره گرها و يا توصيف كننده ها مورد دسترسي قرار گيرند. توابع زير تنها از نام فايل براي تأييد هويت فايل استفاده مي كنند و در استفاده از آنها بايد دقت لازم را به عمل آورد:
· Remove()
· Rename()
· Fopen()
· Freopen()
در زير يك نمونه برنامه نشان داده شده است كه با اين قانون همخواني ندارد. فايلي با نام file_name باز شده، پردازش شده، بسته و پاك مي شود. با اين وجود احتمال دارد كه شئ فايلي كه توسط file_name در تابع remove() مشخص شده همان شئ فايلي كه در تابع fopen() مشخص شده، نباشد.

براي اصلاح كد مذكور، از لحاظ برنامه نويسي كار خاصي نمي توان انجام داد، به جز اينكه مطمئن شد كه فايل در يك دايركتوري امن باز شده و حق دسترسي به گونه اي است كه از دسترسي افراد غير مجاز به فايل مذكور جلوگيري به عمل مي آورد.
31. FIO30-C – ورودي كاربر را از رشته هاي داراي قالب خارج كنيد.
هرگز هيچ تابع قالب دار ورودي- خروجي را با يك رشته داراي قالب كه از كاربر دريافت شده است، فراخواني نكنيد. يك مهاجم كه به صورت جزئي و يا كامل بتواند محتواي رشته هاي داراي قالب را كنترل كند، مي تواند يك پروسه آسيب پذير را از كار بيندازد، محتواي پشته را مشاهده كند، محتواي حافظه را مشاهده كند و يا بر روي قسمت دلخواهي از حافظه بنويسد و در نهايت كد دلخواه را با حق دسترسي پروسه آسيب پذير اجرا كند.
توابع خروجي داراي قالب، نيز خطرناك هستند زيرا بسياري از برنامه نويسان نسبت به توانايي هاي آنها ناآگاه هستند. براي مثال، آنها مي توانند يك مقدار صحيح را در يك آدرس مشخص با استفاده از تبديل نوع %n بنويسند.
در زير كدي را مي بينيد كه از اين قانون تبعيت نكرده است. در اينجا يك تابع به نام incorrect_password() نشان داده شده است كه در زمان تأييد هويت، در صورتي كه نام كاربري وارد شده پيدا نشود و يا كلمه عبور صحيح نباشد، فراخواني مي شود. اين تابع نام كاربر را به صورت يك رشته كه انتهاي آن كاراكتر null است، مي پذيرد. نام اين متغير user است. اين مثال كاملاً نشان دهنده داده اي است كه از يك منبع غير قابل اعتماد يعني كاربر تأييد نشده دريافت مي شود. تابع مذكور يك پيغام خطا را ايجاد مي كند كه نهايتاً در stderr قرار گرفته و با استفاده از تابع fprintf() در خروجي چاپ مي شود.

اين تابع اندازه پيغام را محاسبه كرده و سپس به صورت دايناميك به آن فضا اختصاص مي دهد. سپس پيغام را با استفاده از تابع snprintf() در فضاي تخصيص داده شده مي سازد. در اينجا امكان ايجاد سرريز عدد صحيح بررسي نشده است، زيرا فرض گرديده كه اندازه متغير user كمتر يا مساوي 256 است. اين اتفاق ممكن است در موارد مشابه ديگر نيز كه ساختن يك پيغام سخت است، رخ دهد و منجر به آسيب پذيري در رشته داراي قالب كه به عنوان آرگومان به fprintf() ارسال مي شود، شود.
در زير نسخه اصلاح شده كد مذكور را مشاهده مي كنيد كه در آن به جاي تابع fprintf() از تابع fputs() استفاده شده است كه با msg همانند يك رشته داراي قالب برخورد نمي كند بلكه مستقيماً آن را به stderr مي فرستد.

راه حل زير نيز كه ساده تر است، ورودي نامطمئن از كاربر را به عنوان آرگومان و نه به عنوان رشته قالب دار به fprintf() مي فرستد و احتمال آسيب پذيري در رشته قالب دار را حذف مي كند.


نظرات

بدون نظر
شما برای نظر دادن باید وارد شوید

نوشته

 
تاریخ ایجاد: 18 مرداد 1393

دسته‌ها

امتیاز

امتیاز شما
تعداد امتیازها: 0