چگونه یک تست امنیتی بنویسیم

htxt.africa
htxt.africa

قبل شروع موضوعات باید بگم این نوشته طولانی است و اگر حال خواندن این مطلب را نداشتید به طور خلاصه باید بگم اگر می خواهید نرم افزار مورد نظرتان حد اقل های امنیتی را داشته باشد باید در هر مرحله از توسعه نرم افزارتان تست های امنیتی را جدا از تست های دیگر اجرا کنید و به قول آقای یاشار شاهین زاده Continuous Scanning داشته باشید.

اگر بخواهیم برنامه ای بنویسیم که حد اقل های امنیتی را دارا باشد باید امنیت را در چرخه حیات توسعه نرم افزار در نظر بگیریم.چون تست امنیت بعد از تولید نرم افزار هزینه بر تر خواهد بود.

چرخه حیات توسعه نرم افزار یا SDLC

برای تعریف Software Development Life Cycle می شود گفت یک طرح دقیق شامل نحوه توسعه(development)،نگهداری(maintain)،جایگزینی یا تغیر نرم افزاری خاص است.

به بیان دیگر یک روش برای بهبود کیفیت و فرآیند توسعه نرم افزار است که شامل مراحل زیر می شود.

tutorialspoint
tutorialspoint

مدل های معرفی شده برای SDLC را شاید خیلی شنیده باشید مانند

  • مدل Waterfall
  • مدل Iterative
  • مدل Spiral
  • مدل V
  • مدل Agile
  • ...

در چرخه حیات توسعه نرم افزار بحثی با نام چرخه حیات توسعه نرم افزار امن یا S-SDLC مطرح است که به افراد نقشه راه یا roadmap می دهد برای اطلاعات بیشتر در این زمینه به ویکی OWASP مراجعه کنید.

در چرخه حیات هر بخش کار امنیت خاص خود را دارد برای مثال طبق تصویر زیر

guru99
guru99
  • در مرحله پیش نیاز ها یا Requirements باید پش نیاز های لازم برای تست و الزامات و موارد سوء استفاده تجزیه و تحلیل شود.
  • در مرحله طراحی یا Design باید خطرات احتمالی در طراحی بررسی و در تست ها در نظر گرفته شود.
  • در مرحله کد نویسی و تست واحد یا Coding & Unit Testing باید به صورت ثابت یا پویا با در نظر گرفتن کد ها و به صورت White Box تست انجام شود.
  • در مرحله تست یکپارچه یا Integration Testing باید بدون در نظر گفتن کد و به صورت Black Box تست انجام شود.
  • در مرحله تست سیستم یا System Testing باید علاوه بر تست Black Box باید آسیب پذیری های احتمالی بررسی شود.
  • در مرحله پیاده سازی یا Implementation باید تست نفوذ همراه با شناسایی آسیب پذیری ها صورت گیرد.
  • در مرحله آخر چرخه حیات توسعه نرم افزار باید بحث پشتیبانی یا Support در نظر گرفته شود به این معنی که اثرات یا Impact ها تجزیه و تحلیل شود.
  • در تصویر زیر علاوه بر موارد بالا مواردی مثل آموزش توسعه دهندگان هم در نظر گرفته شده است

موارد کاربرد های تست

تست های امنیتی باید موارد زیر را بررسی کنند تا بتوانند طیف وسیعی از آسیب پذیری های احتمالی پوشش دهند.

  • سطح دسترسی و احراز هویت
  • بررسی ورود ها و رمز گذاری(Encoding)
  • رمزگذاری(Encryption)
  • نشست های کاربر
  • مدیریت و کنترل خطاها
  • گزارش گیری یا Logging

سناریو های تست

خواندن و بررسی سناریو ها یک راه خوب برای نوشتن یک تست خوب است.

برای مثال داخل این مخزن و یا این یکی موارد بسیار خوبی قرار گرفته است که با خواندن و بررسی می توان تست بهتری نوشت.

ابتدا چند سناریو را بررسی کنیم

فرم ورودی داریم که نام کاربری و کلمه عبور میگیرد پس تست ما پس باید موارد زیر را بررسی کند.

  • نام کاربری نباید شامل مواردی مانند "Admin" یا "Administrator" باشد.
  • کلمه عبور نباید کمتر از ۸ رقم باشد.
  • پیام ثبت نام نباید شامل پیام های آشکار مانند "ایمیل قبلا موجود است" یا "نام کاربری قبلا ثبت شده است" باشد.
  • هر یک از ورودی ها باید بررسی شود تا از ورود کاراکتر های مخرب جلوگیری شود.
  • درخواست ورود نباید بیشتر از ۳ بار باشد.
  • پیام های خطای سیستمی مانند "syntax error" به هیچ عنوان نباید نشان داده شود.
  • اطلاعات حساس فرم به هیچ عنوان نباید در url استفاده شود.
  • فضاهای خالی در ورودی ها از لحاظ کاراکتر های مخرب و یا رمز شده بررسی شود .

قسمت جست و جو محصولاتی داریم که یک ورودی از کاربر میگیرد.

  • ورودی مربوط باید سمت سرور بررسی شود نه در سمت کاربر
  • ورودی باید شامل کاراکتر های مجاز باشد و مثلا کاراکتر ها و یا کلماتی که سمت سرور و دیتابیس رزرو شده است نباید اجازه اجرا داده شود.
  • بررسی درخواست جست و جو باید دو بار انجام شود
    یکبار موقع ارسال درخواست و یکبار موقع ارسال نتایج که مطمئن شویم این همان مورد جست و جو شده کاربر است.
  • دکمه ارسال درخواست نباید سمت کاربر تایید شود
    خیلی مواقع پیش میاید دکمه ارسال سمت کاربر و با جاوااسکریپت بررسی و سپس فرم ارسال می شود
    این مورد بستر بسیار مناسبی را برای xss به وجود می آورد.
  • تا حد ممکن درخواست رمز و سپس ارسال شود.

نوشتن یک تست

با توجه به زبان و تکنولوژی که با آن کار می کنید فریمورک های تست هم متفاوت است برای مثال

  • JUnit(java)
  • PHPUnit
  • PyUnit(python)
  • NUnit(.net)

اگر بخواهیم لایه به لایه به تست نگاه کنیم پس ابتدا باید Unit Test انجام شود.

مثلا در JUnit برای تست معتبر بودن ورودی می توان از کد زیر استفاده کرد(دقت کنید قرار است پیش نیاز های هر حمله مورد بررسی قرار بگید).

public void testIllegalCharactersInPhoneNumber() {
       String number = "+(23)';[]232 - 321";
       acc.setPhone(number);
       validator.validate(acc, errors); 
       assertTrue(number+" did not cause a validation error.",         
       errors.hasFieldErrors("phone"));
 }    
public void testAlphabeticInPhoneNumber() {
       String number = "12a12121";
       acc.setPhone(number);
       validator.validate(acc, errors); 
       assertTrue(number+" did not cause a validation error.",    
       errors.hasFieldErrors("phone"));  
  }

از مزیت های تست در لایه Unit Test می توان به

  • مشکلات سریعا شناسایی می شوند
  • تست ها به سرعت انجام می شوند
  • پوشش بالا تست

از معایب تست در لایه Unit Test هم می توان به

  • بسیار از آسیب پذیری ها در این لایه قابل شناسایی نیستند

لایه بعدی Integration Test است.

برای مثال برای بررسی سطح دسترسی می توان از کد زیر استفاده کرد.

public class TestAccessControl extends ServletTestCase {
   public void beginUnprivilegedUserAccessControl(WebRequest theRequest) {
       theRequest.setAuthentication(new  	                        
       BasicAuthentication("user", "password"));
    }
    public void testUnprivilegedUserAccessControl() throws  
    IOException, javax.servlet.ServletException {
       AdminServlet admin = new AdminServlet();
       admin.doGet(request, response);
    }
    public void endUnprivilegedUserAccessControl(WebResponse theResponse) throws 
    IOException {
        assertTrue("Normal users must not be able to access 	/admin",
        theResponse.getStatusCode() == 401)
    }
 }

از مزایا تست در لایه Integration می توان به

  • تست نرم افزار ها تحت سرور
  • شناسایی آسیب پذیری های بیشتر نسبت به لایه قبل مانند انواع injection

از معایب هم می توان به

  • بار اضافی برای سیستم
  • عدم شناسایی آسان آسیب پذیری هایی مانند xss

لایه بعدی Acceptance Test است.که بسیار از ابزار های شناسایی آسیب پذیری به صورت Black box در این لایه کار می کنندو برای تست API خارجی کاربردی است.

ابزار های این لایه به دو دسته

۱- HTTP client یا HTML parser

۲-Driver Browser Instance

روش اول مانند ابزار هایی مانند HTTPUnit مانند یک کاربر پروتکل http عمل می کنند.

روش دوم هم مانند WATIR یا Selenium مانند یک مرورگر عمل می کنند.

برای مثال برای تست SQL Injection با WATIR می توان از کد زیر استفاده کرد.

class SQL_Injection_Test < Test::Unit::TestCase
    include Watir
    def test_SQL_Blind_Injection_in_Login()
        $ie.goto('http://localhost:8080/ispatula')
        $ie.link(:url, /signonForm.do/).click
        $ie.text_field(:name, 'username').set('corsaire1\' OR 1=1--')
        $ie.form(:action, "/ispatula/shop/signon.do").submit
        assert($ie.contains_text('Signon failed'));
     end 
  end

خودکار سازی فرآیند تست

در توسعه نرم افزار چابک و سیستم هایی که CI/CD دارند بحث خودکار سازی فرآیند تست می تواند کار ساز باشد.

برای مثال در تصویر زیر بعد از کامیت شدن کد در Jenkins موقع هر build تست ها اجرا و تست دیگری بر اساس زمان بندی تعریف شده اجرا و نتایج در سرور تست ها ذخیره و آسیب پذیری های کشف شده در Vulnerability Management ذخیره می شود.

secodis
secodis


در این سیستم برای بخش Pipline به صورت زمان بندی شده از اسکنری مانند Arachni استفاده می کنند تا آخرین آسیب پذیری های کشف شده بر روی کد شناسایی و گزارش شود(به جای ThreadFix از sonarqube هم می توانید استفاده کنید).

واقعیت با توجه به پیشرفت تکنولوژی و هوش مصنوعی، خودکار سازی فرآیند های تست آسان تر شده است.

ولی این به معنی نیست که باید این تست ها اطمینان شود و گاهی خود این فرآیند خودکار سازی بستر جدید حمله برای هکر خواهد شد.برای اطلاعات بیشتر فایل ارائه آقای وحید بهزادان مراجعه کنید.



معذرت بابت کم و کاستی های فراوان این مطلب
خیلی خوشحال میشوم نظرات خود را اینجا بگذارید

با تشکر از شما

منابع