რატომ არ შეიცავს Codex Security SAST ანგარიშს
ათწლეულების განმავლობაში, აპლიკაციის სტატიკური უსაფრთხოების ტესტირება (SAST) უსაფრთხოების გუნდებისთვის კოდის მიმოხილვის მასშტაბირებისთვის ერთ-ერთი ყველაზე ეფექტური გზა იყო.
მაგრამ როდესაც Codex Security შევქმენით, შეგნებული დიზაინის არჩევანი გავაკეთეთ: არ დაგვიწყია სტატიკური ანალიზის ანგარიშის იმპორტით და აგენტისთვის მისი ტრიაჟის დავალებით. სისტემა ისე დავაპროექტეთ, რომ დაიწყოს თავად რეპოზიტორიუმით — მისი არქიტექტურით, ნდობის საზღვრებითა და განზრახული ქცევით — და რაც აღმოაჩენს, ჯერ გადაამოწმოს, სანამ ადამიანს მასზე დროის დახარჯვაზე სთხოვს.
მიზეზი მარტივია: ყველაზე რთული მოწყვლადობები, როგორც წესი, dataflow-ის პრობლემები არ არის. ისინი მაშინ ჩნდება, როცა კოდი თითქოს უსაფრთხოების შემოწმებას ახორციელებს, მაგრამ ეს შემოწმება რეალურად არ იძლევა იმ გარანტიას, რომელსაც სისტემა ეყრდნობა. სხვა სიტყვებით, გამოწვევა მხოლოდ ის არ არის, რომ გავყვეთ, როგორ გადაადგილდება მონაცემი პროგრამაში — არამედ ის, რომ განვსაზღვროთ, ნამდვილად მუშაობს თუ არა კოდში არსებული დაცვა.
SAST-ს ხშირად აღწერენ როგორც სუფთა მილსადენს: იდენტიფიცირდება არასანდო შეყვანის წყარო, ხდება მონაცემის მოძრაობის თვალყურის დევნება პროგრამაში და აღინიშნება შემთხვევები, როცა ეს მონაცემი სენსიტიურ sink-მდე სანიტიზაციის გარეშე აღწევს. ეს ელეგანტური მოდელია და ბევრ რეალურ შეცდომას ფარავს.
პრაქტიკაში, SAST-ს მასშტაბზე მუშაობის შესანარჩუნებლად მიახლოებების გაკეთება უწევს — განსაკუთრებით რეალურ კოდურ ბაზებში, სადაც არის არაპირდაპირობა, დინამიკური dispatch, callback-ები, reflection და framework-ებით დატვირთული კონტროლის ნაკადი. ეს მიახლოებები SAST-ის ნაკლი არ არის; ეს არის იმ რეალობის ნაწილი, როცა კოდზე უნდა იმსჯელო მისი გაშვების გარეშე.
ეს თავისთავად არ არის მიზეზი, რატომაც Codex Security არ იწყებს SAST ანგარიშით.
უფრო ღრმა პრობლემა არის ის, რა ხდება მას შემდეგ, რაც წყაროდან sink-მდე კვალს წარმატებით გაჰყვები.
მაშინაც კი, როცა სტატიკური ანალიზი სწორად გაჰყვება შეყვანას მრავალ ფუნქციასა და ფენაში, მას მაინც უნდა უპასუხოს კითხვას, რომელიც რეალურად განსაზღვრავს, არსებობს თუ არა მოწყვლადობა:
აიღეთ გავრცელებული ნიმუში: კოდი არასანდო შიგთავსის რენდერამდე იძახებს რაღაცას, როგორიცაა sanitize_html(). სტატიკურ ანალიზატორს შეუძლია დაინახოს, რომ sanitizer გაეშვა. მაგრამ ის, რასაც ჩვეულებრივ ვერ განსაზღვრავს, არის ის, ეს sanitizer რეალურად საკმარისია თუ არა კონკრეტული რენდერის კონტექსტისთვის, შაბლონის ძრავისთვის, კოდირების ქცევისთვის და შემდგომი ტრანსფორმაციებისთვის.
აქ ხდება ყველაფერი რთული. პრობლემა მხოლოდ ის არ არის, აღწევს თუ არა მონაცემი sink-მდე. საქმე ის არის, კოდში არსებული შემოწმებები მართლა ზღუდავს თუ არა მნიშვნელობას იმგვარად, როგორც სისტემა ვარაუდობს.
სხვა სიტყვებით: დიდი განსხვავებაა „კოდი sanitizer-ს იძახებს“-სა და „სისტემა უსაფრთხოა“-ს შორის.
ეს არის შაბლონი, რომელიც რეალურ სისტემებში მუდმივად გვხვდება.
ვებაპლიკაცია იღებს JSON payload-ს, ამოიღებს redirect_url-ს, ამოწმებს მას allowlist regex-თან, შემდეგ URL-ს დეკოდირებს და შედეგს redirect handler-ს გადასცემს.
კლასიკურ source-to-sink ანგარიშს შეუძლია ეს ნაკადი აღწეროს:
untrusted input → regex check → URL decode → redirect
მაგრამ ნამდვილი კითხვა ის არ არის, არსებობს თუ არა ეს შემოწმება. საქმე ის არის, კვლავ ზღუდავს თუ არა ეს შემოწმება მნიშვნელობას იმ ტრანსფორმაციების შემდეგ, რომლებიც მოჰყვება.
თუ regex გაეშვა დეკოდირებამდე, მართლა ზღუდავს თუ არა ის დეკოდირებულ URL-ს ისე, როგორც მას redirect handler აღიქვამს?
ამაზე პასუხი ნიშნავს მსჯელობას ტრანსფორმაციების მთელ ჯაჭვზე: რას უშვებს regex, როგორ იქცევა დეკოდირება და ნორმალიზაცია, როგორ ეპყრობა URL-ის პარსინგი სასაზღვრო შემთხვევებს და როგორ წყვეტს redirect-ის ლოგიკა სქემებსა და ავტორიტეტებს.
ბევრი პრაქტიკულად მნიშვნელოვანი მოწყვლადობა სწორედ ასე გამოიყურება: ოპერაციების თანმიმდევრობის შეცდომები, ნაწილობრივი ნორმალიზაცია, პარსინგის ორაზროვნება და ვალიდაციასა და ინტერპრეტაციას შორის შეუსაბამობები. dataflow ხილულია. სისუსტე იმაშია, როგორ ვრცელდება — ან ვერ ვრცელდება — შეზღუდვები ტრანსფორმაციების ჯაჭვში.
ეს მხოლოდ თეორიული შაბლონი არ არის. CVE-2024-29041(იხსნება ახალ ფანჯარაში)-ში Express დაზიანებული იყო open redirect პრობლემით, სადაც დამახინჯებულ URL-ებს შეეძლოთ გავრცელებული allowlist იმპლემენტაციების გვერდის ავლა იმის გამო, თუ როგორ იყო redirect-ის სამიზნეები კოდირებული და შემდეგ ინტერპრეტირებული. dataflow პირდაპირი იყო. უფრო რთული კითხვა — და ის, რომელმაც განსაზღვრა, არსებობდა თუ არა შეცდომა — იყო, რჩებოდა თუ არა ვალიდაცია ძალაში ტრანსფორმაციების ჯაჭვის შემდეგ.
Codex Security აშენებულია მარტივი მიზნის გარშემო: შეამციროს ტრიაჟი უფრო ძლიერი მტკიცებულებების მქონე საკითხების წამოწევით. პროდუქტში ეს ნიშნავს რეპოზიტორიუმისთვის სპეციფიკური კონტექსტის გამოყენებას (მათ შორის საფრთხის მოდელის) და მაღალი სიგნალის მქონე საკითხების ვალიდაციას იზოლირებულ გარემოში მათ წარმოჩენამდე.
როდესაც Codex Security აწყდება საზღვარს, რომელიც ჰგავს „ვალიდაციას“ ან „სანიტიზაციას“, ამას checkbox-ად არ აღიქვამს. ის ცდილობს გაიგოს, რის გარანტირებას ცდილობს კოდი — და შემდეგ ამ გარანტიის უარყოფას ცდილობს.
პრაქტიკაში ეს, როგორც წესი, გულისხმობს შემდეგის ნაზავს:
- შესაბამისი კოდური გზის წაკითხვას რეპოზიტორიუმის სრული კონტექსტით, როგორც ამას უსაფრთხოების მკვლევარი გააკეთებდა, და განზრახვასა და იმპლემენტაციას შორის შეუსაბამობების ძიებას. ეს მოიცავს კომენტარებსაც, მაგრამ მოდელი კომენტარებს აუცილებლობად არ ენდობა, ამიტომ თქვენს კოდზე //Halvar says: this is not a bug-ის დამატება მას ვერ დააბნევს, თუ იქ მართლა არის შეცდომა.
- პრობლემის დაყვანას ყველაზე პატარა, ტესტირებად ნაწილამდე (მაგალითად, ერთი შეყვანის ირგვლივ არსებულ ტრანსფორმაციის მილსადენამდე), რათა მასზე მსჯელობა სისტემის დანარჩენი ნაწილის ჩარევის გარეშე იყოს შესაძლებელი. ამ გაგებით, Codex Security გამოაქვს კოდის მცირე ფრაგმენტები და შემდეგ მათთვის მიკრო-fuzzer-ებს წერს.
- ტრანსფორმაციებს შორის შეზღუდვებზე მსჯელობას, ნაცვლად იმისა, რომ თითოეული შემოწმება დამოუკიდებლად განიხილოს. საჭიროებისამებრ, ეს შეიძლება დაკმაყოფილებადობის ამოცანად ფორმალიზებასაც მოიცავდეს. სხვა სიტყვებით, მოდელს ვაძლევთ წვდომას Python გარემოზე z3-solver-ით და ის საჭიროებისას მის გამოყენებაში კარგია, ზუსტად ისე, როგორც ადამიანს მოუწევდა განსაკუთრებით რთულ შეყვანის შეზღუდვების პრობლემაზე პასუხის გაცემისას. ეს განსაკუთრებით სასარგებლოა არასტანდარტულ არქიტექტურებზე მთელი რიცხვის overflow-ების ან მსგავსი შეცდომების შესასწავლად.
- ჰიპოთეზების გაშვებას sandboxed ვალიდაციის გარემოში, როცა ეს შესაძლებელია, რათა გაიმიჯნოს „ეს შეიძლება პრობლემა იყოს“ და „ეს პრობლემაა“. სრულ end-to-end PoC-ს, კოდის debug რეჟიმში კომპილაციით, უკეთესი მტკიცებულება არ აქვს.
ეს არის მთავარი ცვლილება: „შემოწმება არსებობს“-ზე გაჩერების ნაცვლად, სისტემა მიიწევს „ინვარიანტი სრულდება (ან არა), და აი მტკიცებულება“-სკენ. და მოდელი ამ ამოცანისთვის საუკეთესო ხელსაწყოს ირჩევს.
გონივრული რეაქცია ასეთია: რატომ არა ორივე? დავიწყოთ SAST ანგარიშით და შემდეგ გამოვიყენოთ აგენტი უფრო ღრმა მსჯელობისთვის.
არის შემთხვევები, როცა წინასწარ გამოთვლილი მიგნებები სასარგებლოა — განსაკუთრებით ვიწრო, კარგად ცნობილი შეცდომების კლასებისთვის. მაგრამ აგენტისთვის, რომელიც მოწყვლადობების კონტექსტში აღმოჩენასა და ვალიდაციაზეა შექმნილი, SAST ანგარიშიდან დაწყება ქმნის მარცხის სამ პროგნოზირებად რეჟიმს.
პირველ რიგში, ამან შეიძლება ნაადრევი შევიწროება წაახალისოს. მიგნებების სია არის რუკა იმისა, სად შეხედა ინსტრუმენტმა უკვე. თუ ამას საწყის წერტილად მიიღებ, შეიძლება სისტემა მიკერძოებულად უბიძგო, არაპროპორციულად დიდი ძალისხმევა დახარჯოს იმავე არეალებზე, გამოიყენოს იგივე აბსტრაქციები და გამორჩეს იმ ტიპის საკითხები, რომლებიც ინსტრუმენტის მსოფლმხედველობაში არ ჯდება.
მეორეც, ამას შეუძლია შემოიტანოს იმპლიციტური შეფასებები, რომელთა უკან წაღებაც რთულია. ბევრი SAST მიგნება კოდირებს დაშვებებს სანიტიზაციის, ვალიდაციის ან ნდობის საზღვრების შესახებ. თუ ეს დაშვებები მცდარია — ან უბრალოდ არასრული — მათი მსჯელობის ციკლში მიწოდებამ შეიძლება აგენტი „გამოიძიე“-დან „დაადასტურე ან უარყავი“-ზე გადაიყვანოს, რაც არ არის ის, რისი გაკეთებაც გვინდა, რომ აგენტმა აკეთოს.
მესამეც, ამან შეიძლება გაართულოს მსჯელობის სისტემის შეფასება. თუ მილსადენი SAST-ის შედეგებით იწყება, რთული ხდება იმის გამიჯვნა, რა აღმოაჩინა აგენტმა საკუთარი ანალიზით და რა მიიღო სხვა ინსტრუმენტისგან. ეს გამიჯვნა მნიშვნელოვანია, თუ გსურთ სისტემის შესაძლებლობები ზუსტად გაზომოთ, რაც საჭიროა იმისთვის, რომ სისტემა დროთა განმავლობაში გაუმჯობესდეს.
ამიტომ Codex Security ისე ავაგეთ, რომ დაიწყოს იქ, სადაც უსაფრთხოების კვლევა იწყება: კოდიდან და სისტემის განზრახვიდან, და ვალიდაცია გამოიყენოს ნდობის ზღვარის ასაწევად, სანამ ადამიანს შევაწყვეტინებთ.
SAST ინსტრუმენტები შეიძლება შესანიშნავი იყოს იმაში, რისთვისაც შეიქმნა: უსაფრთხო კოდირების სტანდარტების აღსასრულებლად, მარტივი source-to-sink საკითხების დასაჭერად და ცნობილი ნიმუშების მასშტაბზე საპოვნელად პროგნოზირებადი კომპრომისებით. ისინი შეიძლება defense-in-depth-ის ძლიერი ნაწილი იყოს.
ეს პოსტი უფრო ვიწრო თემაზეა: რატომ არ უნდა დაიწყოს მუშაობა სტატიკურ მიგნებათა სიაზე მიბმულად აგენტმა, რომელიც ქცევაზე მსჯელობისა და მიგნებების ვალიდაციისთვის არის შექმნილი.
ასევე მნიშვნელოვანია აღვნიშნოთ სუფთა source-to-sink აზროვნების დაკავშირებული შეზღუდვაც: ყველა მოწყვლადობა dataflow-ის პრობლემა არ არის. ბევრი რეალური ჩავარდნა მდგომარეობისა და ინვარიანტების პრობლემაა — workflow-ის გვერდის ავლა, ავტორიზაციის ხარვეზები და „სისტემა არასწორ მდგომარეობაშია“ ტიპის შეცდომები. ამ ტიპის შეცდომებში დაბინძურებული მნიშვნელობა ერთ „საშიშ sink“-ს არ აღწევს. რისკი იმაშია, რასაც პროგრამა ვარაუდობს, რომ ყოველთვის ჭეშმარიტი იქნება.
ველით, რომ უსაფრთხოების ხელსაწყოების ეკოსისტემა გაუმჯობესებას გააგრძელებს: სტატიკურ ანალიზს, fuzzing-ს, runtime guard-ებსა და აგენტურ workflow-ებს ყველას თავისი როლი ექნება.
ის, რაშიც გვინდა Codex Security კარგი იყოს, არის ის ნაწილი, რომელიც უსაფრთხოების გუნდებს ყველაზე ძვირი უჯდებათ: „ეს საეჭვოდ ჩანს“-ის გადაქცევა „ეს რეალურია, აი როგორ ფუჭდება და აი გამოსწორება, რომელიც სისტემის განზრახვას შეესაბამება“-დ.
თუ გსურთ მეტი გაიგოთ იმის შესახებ, როგორ ასკანირებს Codex Security რეპოზიტორიუმებს, როგორ ამოწმებს მიგნებებს და როგორ სთავაზობს გამოსწორებებს, იხილეთ ჩვენი დოკუმენტაცია(იხსნება ახალ ფანჯარაში).


