Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olar

Hey Habr!

İşimizdə şirkətimiz çox vaxt müxtəlif statik kod analizi alətləri (SAST) ilə məşğul olur. Qutudan kənarda hamısı orta səviyyədə işləyir. Təbii ki, hər şey layihədən və orada istifadə olunan texnologiyalardan, eləcə də bu texnologiyaların təhlil qaydaları ilə nə dərəcədə əhatə olunmasından asılıdır. Fikrimcə, SAST alətini seçərkən ən vacib meyarlardan biri onu tətbiqlərinizin xüsusiyyətlərinə uyğunlaşdırmaq bacarığıdır, yəni təhlil qaydalarını yazmaq və dəyişdirmək və ya daha çox adlandırıldığı kimi, Xüsusi Sorğular.

Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olar

Biz ən çox Checkmarx-dan istifadə edirik - çox maraqlı və güclü kod analizatoru. Bu yazıda bunun üçün təhlil qaydaları yazmaq təcrübəmdən danışacağam.

Mündəricat

Giriş

Başlamaq üçün, Checkmarx üçün sorğuların yazılması xüsusiyyətləri haqqında rus dilində bir neçə məqalədən birini tövsiyə etmək istərdim. 2019-cu ilin sonunda Habré-də bu başlıq altında dərc edildi: "Salam, Checkmarks!" Checkmarx SAST sorğusunu necə yazmaq və gözəl zəiflikləri tapmaq olar.

O, bəzi test tətbiqləri üçün CxQL-də (Checkmark Query Language) ilk sorğuların necə yazılmasını təfərrüatlı şəkildə araşdırır və təhlil qaydalarının necə işlədiyinin əsas prinsiplərini göstərir.

Orada təsvir olunanları təkrarlamayacağam, baxmayaraq ki, bəzi kəsişmələr hələ də mövcud olacaq. Məqaləmdə bir növ "reseptlər toplusu", Checkmarx ilə işləyərkən qarşılaşdığım xüsusi problemlərin həlli siyahısını tərtib etməyə çalışacağam. Bu problemlərin çoxu üzərində beynimi qarışdırmalı oldum. Bəzən sənədlərdə kifayət qədər məlumat yox idi, bəzən isə tələb olunanı necə etmək lazım olduğunu başa düşmək belə çətin olurdu. Ümid edirəm ki, təcrübəm və yuxusuz gecələrim əbəs olmayacaq və bu “Xüsusi Sorğu reseptləri toplusu” sizi bir neçə saat və ya bir neçə sinir hüceyrəsinə qənaət edəcək. Beləliklə, başlayaq!

Qaydalar haqqında ümumi məlumat

Əvvəlcə nə baş verəcəyini daha yaxşı başa düşmək üçün bir neçə əsas anlayışa və qaydalarla işləmə prosesinə baxaq. Həm də ona görə ki, sənədlər bu barədə heç nə demir və ya strukturda çox yayılmışdır, bu da çox rahat deyil.

  1. Qaydalar skan zamanı başlanğıcda seçilmiş əvvəlcədən təyin edilmiş parametrdən (aktiv qaydalar toplusu) asılı olaraq tətbiq edilir. Siz qeyri-məhdud sayda əvvəlcədən təyin yarada bilərsiniz və onların tam olaraq necə qurulacağı prosesinizin xüsusiyyətlərindən asılıdır. Siz onları dilə görə qruplaşdıra və ya hər bir layihə üçün əvvəlcədən təyin edə bilərsiniz. Aktiv qaydaların sayı taramanın sürətinə və dəqiqliyinə təsir göstərir.

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarCheckmarx interfeysində Əvvəlcədən ayarın qurulması

  2. Qaydalar CxAuditor adlı xüsusi alətdə redaktə edilir. Bu, Checkmarx ilə işləyən serverə qoşulan masaüstü proqramdır. Bu alətin iki iş rejimi var: qaydaları redaktə etmək və artıq yerinə yetirilən skan nəticələrini təhlil etmək.

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarCxAudit interfeysi

  3. Checkmarx-da qaydalar dilə görə bölünür, yəni hər bir dilin öz sorğu dəsti var. Dildən asılı olmayaraq tətbiq olunan bəzi ümumi qaydalar da var, bunlar əsas sorğular adlananlardır. Əsas sorğular əksər hallarda digər qaydaların istifadə etdiyi məlumatların axtarışını əhatə edir.

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarQaydaların dilə görə bölünməsi

  4. Qaydalar “İcra edilə bilər” və “İcra edilə bilməz” (İcra olunur və İcra olunmur). Fikrimcə, tam doğru ad deyil, amma budur. Nəticə ondan ibarətdir ki, “İcra edilə bilən” qaydaların icrasının nəticəsi UI-də skan nəticələrində göstəriləcək və “İcra edilə bilməyən” qaydalar yalnız onların nəticələrini digər sorğularda (əslində, sadəcə funksiya) istifadə etmək üçün lazımdır.

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarYaradarkən qayda növünün müəyyən edilməsi

  5. Siz yeni qaydalar yarada və ya mövcud olanları əlavə edə/yenidən yaza bilərsiniz. Qaydaları yenidən yazmaq üçün onu ağacda tapmalı, sağa klikləyin və açılan menyudan “Qaydaları ləğv et” seçin. Burada yadda saxlamaq lazımdır ki, yeni qaydalar ilkin olaraq hafızaya daxil edilmir və aktiv deyil. Onlardan istifadə etməyə başlamaq üçün onları alətdəki “Ön təyinat meneceri” menyusunda aktivləşdirməlisiniz. Yenidən yazılmış qaydalar öz parametrlərini saxlayır, yəni qayda aktiv idisə, belə qalacaq və dərhal tətbiq olunacaq.

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarPreset Manager interfeysində yeni qayda nümunəsi

  6. İcra zamanı nədən asılı olan sorğuların "ağacı" qurulur. Məlumat toplayan qaydalar birinci, istifadə edənlər isə ikinci icra olunur. İcra nəticəsi keşlənir, buna görə də mövcud qaydanın nəticələrindən istifadə etmək mümkündürsə, bunu etmək daha yaxşıdır, bu, tarama vaxtını azaldacaq.

  7. Qaydalar müxtəlif səviyyələrdə tətbiq oluna bilər:

  • Bütün sistem üçün - hər hansı bir layihənin hər hansı bir skan edilməsi üçün istifadə olunacaq

  • Komanda səviyyəsində (Komanda) - yalnız seçilmiş komandada layihələri skan etmək üçün istifadə olunacaq.

  • Layihə səviyyəsində - Konkret layihədə tətbiq olunacaq

    Dəli olmadan Checkmarx üçün qaydaları necə yazmaq olarQaydanın tətbiq olunacağı səviyyənin müəyyən edilməsi

Başlayanlar üçün "Lüğət"

Mənə sual yaradan bir neçə şeylə başlayacağam və həyatı əhəmiyyətli dərəcədə asanlaşdıracaq bir sıra üsulları da göstərəcəyəm.

Siyahılarla əməliyyatlar

- вычитание одного из другого (list2 - list1)
* пересечение списков (list1 * list2)
+ сложение списков (list1 + list2)

& (логическое И) - объединяет списки по совпадению (list1 & list2), аналогично пересечению (list1 * list2)
| (логическое ИЛИ) - объединяет списки по широкому поиску (list1 | list2)

Со списками не работает:  ^  &&  ||  %  / 

Bütün tapılan əşyalar

Skan edilmiş dildə siz Checkmarx-ın müəyyən etdiyi tamamilə bütün elementlərin siyahısını əldə edə bilərsiniz (sətirlər, funksiyalar, siniflər, metodlar və s.). Bu, vasitəsilə əldə edilə bilən bəzi obyektlər sahəsidir All. Yəni, müəyyən bir adı olan obyekti axtarmaq searchMe, məsələn, bütün tapılmış obyektlər arasında adla axtarış edə bilərsiniz:

// Такой запрос выдаст все элементы
result = All;

// Такой запрос выдаст все элементы, в имени которых присутствует “searchMe“
result = All.FindByName("searchMe");

Ancaq nədənsə skanda yer almayan başqa bir dildə axtarış etmək lazımdırsa (məsələn, Android layihəsində groovy), dəyişən vasitəsilə obyekt məkanımızı genişləndirə bilərsiniz:

result = AllMembers.All.FindByName("searchMe");

Axın təhlili üçün funksiyalar

Bu funksiyalar bir çox qaydalarda istifadə olunur və burada onların mənasına dair kiçik bir fırıldaq vərəqi var:

// Какие данные second влияют на first.
// Другими словами - ТО (second) что влияет на  МЕНЯ (first).
result = first.DataInfluencedBy(second);

// Какие данные first влияют на second.
// Другими словами - Я (first) влияю на ТО (second).
result = first.DataInfluencingOn(second);

Fayl adı/yolu əldə edilir

Sorğunun nəticələrindən əldə edilə bilən bir neçə atribut var (girişin tapıldığı faylın adı, sətir və s.), lakin sənədlərdə onların necə əldə edilməsi və istifadə edilməsi göstərilmir. Beləliklə, bunu etmək üçün LinePragma xassəsinə daxil olmalısınız və bizə lazım olan obyektlər onun içərisində yerləşəcəkdir:

// Для примера найдем все методы
CxList methods = Find_Methods();

// В методах найдем по имени метод scope
CxList scope = methods.FindByName("scope");

// Таким образом можо получить путь к файлу
string current_filename = scope.GetFirstGraph().LinePragma.FileName;

// А вот таким - строку, где нашлось срабатывание
int current_line = scope.GetFirstGraph().LinePragma.Line;

// Эти параметры можно использовать по разному
// Например получить все объекты в файле
CxList inFile = All.FindByFileName(current_filename);

// Или найти что происходит в конкретной строке
CxList inLine = inFile.FindByPosition(current_line);

Bunu nəzərə almağa dəyər FileName metoddan istifadə etdiyimiz üçün əslində faylın yolunu ehtiva edir GetFirstGraph.

İcra nəticəsi

CxQL daxilində xüsusi dəyişən var result, yazılı qaydanızın icrasının nəticəsini qaytarır. O, dərhal işə salınır və siz ona ara nəticələr yaza, işlədiyiniz zaman onları dəyişdirə və təkmilləşdirə bilərsiniz. Lakin, qayda daxilində bu dəyişənə və ya funksiyaya təyinat yoxdursa return— icra nəticəsi həmişə sıfır olacaq.

Aşağıdakı sorğu icra nəticəsində bizə heç nə qaytarmayacaq və həmişə boş qalacaq:

// Находим элементы foo
CxList libraries = All.FindByName("foo");

Ancaq icra nəticəsini sehrli dəyişən nəticəyə təyin etdikdən sonra bu çağırışın bizə nə qaytardığını görəcəyik:

// Находим элементы foo
CxList libraries = All.FindByName("foo");

// Выводим, как результат выполнения правила
result = libraries

// Или еще короче
result = All.FindByName("foo");

Digər qaydaların nəticələrindən istifadə

Checkmarx-dakı qaydalar adi proqramlaşdırma dilində olan funksiyaların analoqu adlandırıla bilər. Qayda yazarkən digər sorğuların nəticələrindən də istifadə edə bilərsiniz. Məsələn, hər dəfə kodda bütün metod çağırışlarını axtarmağa ehtiyac yoxdur, sadəcə istədiyiniz qaydanı çağırın:

// Получаем результат выполнения другого правила
CxList methods = Find_Methods();

// Ищем внутри метод foo. 
// Второй параметр false означает, что ищем без чувствительности к регистру
result = methods.FindByShortName("foo", false);

Bu yanaşma kodu qısaltmağa və qaydanın icra müddətini əhəmiyyətli dərəcədə azaltmağa imkan verir.

Problemlərin həlli

Giriş

Alətlə işləyərkən bəzən istədiyiniz sorğunu dərhal yazmaq mümkün olmur və müxtəlif variantları sınayaraq sınaqdan keçirməli olursunuz. Belə bir vəziyyət üçün alət aşağıdakı kimi adlanan girişi təmin edir:

// Находим что-то
CxList toLog = All.FindByShortName("log");

// Формируем строку и отправляем в лог
cxLog.WriteDebugMessage (“number of DOM elements =” + All.Count);

Ancaq yadda saxlamaq lazımdır ki, bu metod yalnız giriş kimi qəbul edilir sim, buna görə də ilk əməliyyat nəticəsində tapılan elementlərin tam siyahısını göstərmək mümkün olmayacaq. Sazlama üçün istifadə edilən ikinci seçim, zaman zaman sehrli dəyişənə təyin etməkdir result sorğunun nəticəsi və nə baş verdiyinə baxın. Bu yanaşma çox rahat deyil, əmin olmalısınız ki, kodda bununla bağlı heç bir ləğvetmə və ya əməliyyat yoxdur. result və ya sadəcə aşağıdakı kodu şərh edin. Yoxsa siz də mənim kimi bir neçə belə zəngi hazır qaydadan silməyi unuda bilərsiniz və niyə heç nə işləmir deyə təəccüb edə bilərsiniz.

Daha rahat bir yol metodu çağırmaqdır return tələb olunan parametrlə. Belə olan halda qaydanın icrası bitəcək və yazdıqlarımızın nəticəsində nə baş verdiyini görə biləcəyik:

// Находим что-то
CxList toLog = All.FindByShortName("log");

// Выводим результат выполнения
return toLog

//Все, что написано дальше не будет выполнено
result = All.DataInfluencedBy(toLog)

Giriş problemi

CxAudit alətinə (qaydaları yazmaq üçün istifadə olunur) daxil ola bilməyəcəyiniz vəziyyətlər var. Bunun bir çox səbəbi ola bilər, o cümlədən qəzalar, qəfil Windows yeniləmələri, BSOD və bizim nəzarətimizdən kənarda olan digər gözlənilməz vəziyyətlər. Bu halda bəzən verilənlər bazasında tamamlanmamış seans olur ki, bu da sizin yenidən daxil olmağa imkan vermir. Bunu düzəltmək üçün bir neçə sorğu yerinə yetirməlisiniz:

8.6-dan əvvəl Checkmarx üçün:

// Проверяем, что есть залогиненые пользователи, выполнив запрос в БД
SELECT COUNT(*) FROM [CxDB].[dbo].LoggedinUser WHERE [ClientType] = 6;
 
// Если что-то есть, а на самом деле даже если и нет, попробовать выполнить запрос
DELETE FROM [CxDB].[dbo].LoggedinUser WHERE [ClientType] = 6;

8.6-dan sonra Checkmarx üçün:

// Проверяем, что есть залогиненые пользователи, выполнив запрос в БД
SELECT COUNT(*) FROM LoggedinUser WHERE (ClientType = 'Audit');
 
// Если что-то есть, а на самом деле даже если и нет, попробовать выполнить запрос
DELETE FROM [CxDB].[dbo].LoggedinUser WHERE (ClientType = 'Audit');

Yazı qaydaları

İndi ən maraqlı hissəyə keçirik. CxQL-də qaydalar yazmağa başladığınız zaman, tez-tez çatışmayan şey, müəyyən problemlərin həllinə dair bəzi canlı nümunələr və ümumiyyətlə sorğu əməliyyatı prosesini təsvir etmək üçün çox sənədləşdirmə deyil.

Sorğu dili ilə məşğul olmağa başlayanlar üçün həyatı bir az da asanlaşdırmağa çalışacağam və müəyyən problemləri həll etmək üçün Xüsusi Sorğulardan istifadə etmək üçün bir neçə nümunə verəcəyəm. Onlardan bəziləri kifayət qədər ümumidir və şirkətinizdə praktiki olaraq heç bir dəyişiklik olmadan istifadə edilə bilər, digərləri daha spesifikdir, lakin tətbiqlərinizin xüsusiyyətlərinə uyğun olaraq kodu dəyişdirərək də istifadə edilə bilər.

Beləliklə, ən çox qarşılaşdığımız problemlər:

Vəzifə: Qaydanın icrasının nəticələrində bir neçə Axın var və onlardan biri digərinin yuvasıdır, onlardan birini tərk etməlisiniz.

həll: Həqiqətən, bəzən Checkmarx üst-üstə düşə bilən və digərlərinin qısaldılmış versiyası ola biləcək bir neçə məlumat axını göstərir. Belə hallar üçün xüsusi üsul var Axını azaldın. Parametrdən asılı olaraq, o, ən qısa və ya ən uzun axını seçəcək:

// Оставить только длинные Flow
result = result.ReduceFlow(CxList.ReduceFlowType.ReduceSmallFlow);

// Оставить только короткие Flow
result = result.ReduceFlow(CxList.ReduceFlowType.ReduceBigFlow);

Vəzifə: Alətin reaksiya verdiyi həssas məlumatların siyahısını genişləndirin

həll: Checkmarx-ın nəticələri bir çox digər sorğular tərəfindən istifadə olunan əsas qaydalara malikdir. Bu qaydaların bəzilərini tətbiqinizə xas olan məlumatlarla əlavə etməklə siz dərhal skan nəticələrinizi yaxşılaşdıra bilərsiniz. Aşağıda işə başlamaq üçün nümunə qaydadır:

Ümumi_məxfilik_pozulması_siyahısı

Həssas məlumatları saxlamaq üçün tətbiqimizdə istifadə olunan bir neçə dəyişən əlavə edək:

// Получаем результат выполнения базового правила
result = base.General_privacy_violation_list();

// Ищем элементы, которые попадают под простые регулярные выражения. Можно дополнить характерными для вас паттернами.
CxList personalList = All.FindByShortNames(new List<string> {
	"*securityToken*", "*sessionId*"}, false);

// Добавляем к конечному результату
result.Add(personalList);

Vəzifə: Parollarla dəyişənlərin siyahısını genişləndirin

həll: Kodda parolların müəyyən edilməsinin əsas qaydasına dərhal diqqət yetirməyi və ona şirkətinizdə tez-tez istifadə olunan dəyişən adlarının siyahısını əlavə etməyi tövsiyə edərdim.

Parolun_məxfilik_pozulması_siyahısı

CxList allStrings = All.FindByType("String"); 
allStrings.Add(All.FindByType(typeof(StringLiteral))); 
allStrings.Add(Find_UnknownReference());
allStrings.Add(All.FindByType(typeof (Declarator)));
allStrings.Add(All.FindByType(typeof (MemberAccess)));
allStrings.Add(All.FindByType(typeof(EnumMemberDecl))); 
allStrings.Add(Find_Methods().FindByShortName("get*"));

// Дополняем дефолтный список переменных
List < string > pswdIncludeList = new List<string>{"*password*", "*psw", "psw*", "pwd*", "*pwd", "*authKey*", "pass*", "cipher*", "*cipher", "pass", "adgangskode", "benutzerkennwort", "chiffre", "clave", "codewort", "contrasena", "contrasenya", "geheimcode", "geslo", "heslo", "jelszo", "kennwort", "losenord", "losung", "losungswort", "lozinka", "modpas", "motdepasse", "parol", "parola", "parole", "pasahitza", "pasfhocal", "passe", "passord", "passwort", "pasvorto", "paswoord", "salasana", "schluessel", "schluesselwort", "senha", "sifre", "wachtwoord", "wagwoord", "watchword", "zugangswort", "PAROLACHIAVE", "PAROLA CHIAVE", "PAROLECHIAVI", "PAROLE CHIAVI", "paroladordine", "verschluesselt", "sisma",
                "pincode",
								"pin"};
								
List < string > pswdExcludeList = new List<string>{"*pass", "*passable*", "*passage*", "*passenger*", "*passer*", "*passing*", "*passion*", "*passive*", "*passover*", "*passport*", "*passed*", "*compass*", "*bypass*", "pass-through", "passthru", "passthrough", "passbytes", "passcount", "passratio"};

CxList tempResult = allStrings.FindByShortNames(pswdIncludeList, false);
CxList toRemove = tempResult.FindByShortNames(pswdExcludeList, false);
tempResult -= toRemove;
tempResult.Add(allStrings.FindByShortName("pass", false));

foreach (CxList r in tempResult)
{
	CSharpGraph g = r.data.GetByIndex(0) as CSharpGraph;
	if(g != null && g.ShortName != null && g.ShortName.Length < 50)
	{
		result.Add(r);
	}
}

Vəzifə: Checkmarx tərəfindən dəstəklənməyən istifadə edilmiş çərçivələri əlavə edin

həll: Checkmarx-dakı bütün sorğular dilə görə bölünür, ona görə də hər bir dil üçün qaydalar əlavə etməlisiniz. Aşağıda bu cür qaydaların bəzi nümunələri verilmişdir.

Standart funksionallığı tamamlayan və ya əvəz edən kitabxanalardan istifadə edilərsə, onları əsas qaydaya asanlıqla əlavə etmək olar. Sonra onu istifadə edən hər kəs dərhal yeni təqdimatlar haqqında öyrənəcək. Nümunə olaraq, Android-ə daxil olmaq üçün kitabxanalar Timber və Loggidir. Əsas paketdə qeyri-sistem zənglərini müəyyən etmək üçün heç bir qayda yoxdur, buna görə də parol və ya sessiya identifikatoru jurnala daxil olarsa, biz bu barədə bilməyəcəyik. Checkmarx qaydalarına belə metodların təriflərini əlavə etməyə çalışaq.

Giriş üçün Timber kitabxanasından istifadə edən test kodu nümunəsi:

package com.death.timberdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import timber.log.Timber;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Timber.e("Error Message");
        Timber.d("Debug Message");

        Timber.tag("Some Different tag").e("And error message");
    }
}

Tətbiqdən məlumat üçün çıxış nöqtəsi kimi Timber metodlarını çağırmağın tərifini əlavə etməyə imkan verən Checkmarx sorğusunun bir nümunəsidir:

FindAndroidÇıxışları

// Получаем результат выполнения базового правила
result = base.Find_Android_Outputs();

// Дополняем вызовами, которые приходят из библиотеки Timber
CxList timber = All.FindByExactMemberAccess("Timber.*") +
    All.FindByShortName("Timber").GetMembersOfTarget();

// Добавляем к конечному результату
result.Add(timber);

Qonşu qaydaya da əlavə edə bilərsiniz, lakin bu, birbaşa Android-ə daxil olmağa aiddir:

FindAndroidLog_Outputs

// Получаем результат выполнения базового правила
result = base.Find_Android_Log_Outputs();

// Дополняем вызовами, которые приходят из библиотеки Timber
result.Add(
  All.FindByExactMemberAccess("Timber.*") +
  All.FindByShortName("Timber").GetMembersOfTarget()
);

Həmçinin, əgər Android proqramları istifadə edirsə İş Meneceri asinxron iş üçün, tapşırıqdan məlumat əldə etmək üçün bir üsul əlavə etməklə bu barədə Checkmarx-a əlavə məlumat vermək yaxşı bir fikirdir. getInputData:

FindAndroidRead

// Получаем результат выполнения базового правила
result = base.Find_Android_Read();

// Дополняем вызовом функции getInputData, которая используется в WorkManager
CxList getInputData = All.FindByShortName("getInputData");

// Добавляем к конечному результату
result.Add(getInputData.GetMembersOfTarget());

Vəzifə: iOS layihələri üçün plistdə həssas data axtarılır

həll: iOS tez-tez müxtəlif dəyişənləri və dəyərləri saxlamaq üçün .plist uzantılı xüsusi fayllardan istifadə edir. Parolların, tokenlərin, açarların və digər həssas məlumatların bu fayllarda saxlanması tövsiyə edilmir, çünki onlar heç bir problem olmadan cihazdan çıxarıla bilər.

Plist faylları çılpaq gözlə görünməyən, lakin Checkmarx üçün vacib olan xüsusiyyətlərə malikdir. Gəlin bizə lazım olan məlumatları axtaracaq və parolların və ya tokenlərin haradasa qeyd edilib-edilmədiyini bizə bildirəcək bir qayda yazaq.

Backend xidməti ilə əlaqə üçün işarəni ehtiva edən belə bir fayl nümunəsi:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>DeviceDictionary</key>
	<dict>
		<key>phone</key>
		<string>iPhone 6s</string>
	</dict>
	<key>privatekey</key>
	<string>MIICXAIBAAKBgQCqGKukO1De7zhZj6+</string>
</dict>
</plist>

Və yazarkən nəzərə alınmalı olan bir neçə nüansı olan Checkmarx üçün bir qayda:

// Используем результат выполнения правила по поиску файлов plist, чтобы уменьшить время работы правила и 
CxList plist = Find_Plist_Elements();

// Инициализируем новую переменную
CxList dictionarySettings = All.NewCxList();

// Теперь добавим поиск всех интересующих нас значений. В дальнейшем можно расширять этот список.
// Для поиска значений, как ни странно, используется FindByMemberAccess - поиск обращений к методам. Второй параметр внутри функции, false, означает, что поиск нечувствителен к регистру
dictionarySettings.Add(plist.FindByMemberAccess("privatekey", false));
dictionarySettings.Add(plist.FindByMemberAccess("privatetoken", false));

// Для корректного поиска из-за особенностей структуры plist - нужно искать по типу "If statement"
CxList ifStatements = plist.FindByType(typeof(IfStmt));

// Добавляем в результат, перед этим получив родительский узел - для правильного отображения
result = dictionarySettings.FindByFathers(ifStatements);

Vəzifə: XML-də məlumat tapmaq

həll: Checkmarx XML ilə işləmək və dəyərlər, teqlər, atributlar və s. axtarmaq üçün çox rahat funksiyalara malikdir. Ancaq təəssüf ki, sənədlərdə bir səhv var idi, buna görə heç bir nümunə işləmir. Sənədlərin son versiyasında bu qüsurun aradan qaldırılmasına baxmayaraq, sənədlərin əvvəlki versiyalarından istifadə edirsinizsə, diqqətli olun.

Budur sənədlərdən səhv bir nümunə:

// Код работать не будет
result = All.FindXmlAttributesByNameAndValue("*.app", 8, “id”, "error- section", false, true);

İcra cəhdi nəticəsində bir səhv alacağıq All belə bir üsul yoxdur... Və bu doğrudur, çünki XML ilə işləmək üçün funksiyalardan istifadə etmək üçün xüsusi, ayrıca obyekt məkanı var - cxXPath. Android-də HTTP trafikindən istifadə etməyə imkan verən parametr tapmaq üçün düzgün sorğu belə görünür:

// Правильный вариант с использованием cxXPath
result = cxXPath.FindXmlAttributesByNameAndValue("*.xml", 8, "cleartextTrafficPermitted", "true", false, true);

Gəlin buna bir az daha ətraflı baxaq, çünki bütün funksiyalar üçün sintaksis oxşardır, birini tapdıqdan sonra sizə lazım olanı seçmək kifayətdir. Beləliklə, parametrlərə görə ardıcıl olaraq:

  • "*.xml"— axtarılacaq fayllar maskası

  • 8 — qaydanın tətbiq olunduğu dilin id-si

  • "cleartextTrafficPermitted"— xml-də atribut adı

  • "true" — bu atributun dəyəri

  • false — axtarış zamanı müntəzəm ifadədən istifadə

  • true — o deməkdir ki, axtarış hərflərə məhəl qoyulmadan aparılacaq, yəni hərflərə həssas deyil

Nümunə olaraq, biz HTTP protokolu vasitəsilə serverlə əlaqə saxlamağa imkan verən Android-də təhlükəsizlik baxımından yanlış şəbəkə bağlantısı parametrlərini müəyyən edən bir qaydadan istifadə etdik. Atribut ehtiva edən parametrə nümunə cleartextTrafficPermitted mənası ilə true:

<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
        <domain-config cleartextTrafficPermitted="true">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </domain-config>
</network-security-config>

Vəzifə: Nəticələri fayl adı/yolu ilə məhdudlaşdırın

həll: Android üçün mobil tətbiqetmənin inkişafı ilə bağlı böyük layihələrdən birində biz çaşqınlıq parametrini təyin edən qaydanın yanlış pozitivləri ilə qarşılaşdıq. Fakt budur ki, qutudan kənar qayda faylda axtarış edir build.gradle tətbiqin buraxılış versiyası üçün çaşqınlıq qaydalarının tətbiqinə cavabdeh olan parametr.

Amma böyük layihələrdə bəzən uşaq faylları olur build.gradle, layihəyə daxil olan kitabxanalara istinad edən. Xüsusiyyət ondan ibarətdir ki, bu fayllar çaşqınlığa ehtiyac olduğunu göstərməsə belə, kompilyasiya zamanı ana montaj faylının parametrləri tətbiq olunacaq.

Beləliklə, vəzifə kitabxanalara aid olan uşaq fayllarda tetikleyicileri kəsməkdir. Onlar xəttin mövcudluğu ilə müəyyən edilə bilər apply 'com.android.library'.

Fayldan kod nümunəsi build.gradle, qarışıqlığa ehtiyacı müəyyən edən:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        ...
    }

    buildTypes {
        release {
            minifyEnabled true
            ...
        }
    }
}

dependencies {
  ...
}

Nümunə fayl build.gradle bu parametrə malik olmayan layihəyə daxil edilmiş kitabxana üçün:

apply plugin: 'android-library'

dependencies {
  compile 'com.android.support:support-v4:18.0.+'
}

android {
  compileSdkVersion 14
  buildToolsVersion '17.0.0'
  ...
}

Və Checkmarx qaydası:

ProGuardObfuscationNotInUse

// Поиск метода release среди всех методов в Gradle файлах
CxList releaseMethod = Find_Gradle_Method("release");

// Все объекты из файлов build.gradle
CxList gradleBuildObjects = Find_Gradle_Build_Objects();

// Поиск того, что находится внутри метода "release" среди всех объектов из файлов build.gradle
CxList methodInvokesUnderRelease = gradleBuildObjects.FindByType(typeof(MethodInvokeExpr)).GetByAncs(releaseMethod);

// Ищем внутри gradle-файлов строку "com.android.library" - это значит, что данный файл относится к библиотеке и его необходимо исключить из правила
CxList android_library = gradleBuildObjects.FindByName("com.android.library");

// Инициализация пустого массива
List<string> libraries_path = new List<string> {};

// Проходим через все найденные "дочерние" файлы
foreach(CxList library in android_library)
{
    // Получаем путь к каждому файлу
	string file_name_library = library.GetFirstGraph().LinePragma.FileName;
    
    // Добавляем его в наш массив
	libraries_path.Add(file_name_library);
}

// Ищем все вызовы включения обфускации в релизных настройках
CxList minifyEnabled = methodInvokesUnderRelease.FindByShortName("minifyEnabled");

// Получаем параметры этих вызовов
CxList minifyValue = gradleBuildObjects.GetParameters(minifyEnabled, 0);

// Ищем среди них включенные
CxList minifyValueTrue = minifyValue.FindByShortName("true");

// Немного магии, если не нашли стандартным способом :D
if (minifyValueTrue.Count == 0) {
	minifyValue = minifyValue.FindByAbstractValue(abstractValue => abstractValue is TrueAbstractValue);
} else {
    // А если всё-таки нашли, то предыдущий результат и оставляем
	minifyValue = minifyValueTrue;	
}

// Если не нашлось таких методов
if (minifyValue.Count == 0)
{
    // Для более корректного отображения места срабатывания в файле ищем или buildTypes или android
	CxList tempResult = All.NewCxList();
	CxList buildTypes = Find_Gradle_Method("buildTypes");
	if (buildTypes.Count > 0) {
		tempResult = buildTypes;
	} else {
		tempResult = Find_Gradle_Method("android");
	}
	
	// Для каждого из найденных мест срабатывания проходим и определяем, дочерний или основной файлы сборки
	foreach(CxList res in tempResult)
	{
        // Определяем, в каком файле был найден buildType или android методы
		string file_name_result = res.GetFirstGraph().LinePragma.FileName;
        
        // Если такого файла нет в нашем списке "дочерних" файлов - значит это основной файл и его можно добавить в результат
		if (libraries_path.Contains(file_name_result) == false){
			result.Add(res);
		}
	}
}

Bu yanaşma kifayət qədər universal və yalnız Android proqramları üçün deyil, həm də nəticənin müəyyən bir fayla aid olub-olmadığını müəyyən etmək lazım olan digər hallar üçün faydalı ola bilər.

Vəzifə: Sintaksis tam dəstəklənmirsə, üçüncü tərəf kitabxanası üçün dəstək əlavə edin

həll: Kod yazma prosesində istifadə olunan müxtəlif çərçivələrin sayı sadəcə olaraq qrafiklərdən kənardır. Əlbəttə, Checkmarx həmişə onların mövcudluğu haqqında bilmir və bizim vəzifəmiz ona müəyyən metodların xüsusi olaraq bu çərçivəyə aid olduğunu başa düşməyi öyrətməkdir. Bəzən bu, çərçivələrin çox geniş yayılmış funksiya adlarından istifadə etməsi və müəyyən bir çağırışın konkret kitabxana ilə əlaqəsini birmənalı şəkildə müəyyən etmək mümkün olmaması ilə çətinləşir.

Çətinlik ondadır ki, bu cür kitabxanaların sintaksisi həmişə düzgün tanınmır və çoxlu sayda yanlış müsbət nəticə əldə etməmək üçün təcrübə aparmalısınız. Skanlama dəqiqliyini artırmaq və problemi həll etmək üçün bir neçə variant var:

  • Birinci seçim, kitabxananın müəyyən bir layihədə istifadə edildiyini və komanda səviyyəsində qaydanı tətbiq edə biləcəyini dəqiq bilirik. Ancaq komanda fərqli yanaşmaya qərar verərsə və ya funksiya adlarının üst-üstə düşdüyü bir neçə kitabxanadan istifadə edərsə, biz çoxsaylı yalançı pozitivlərin o qədər də xoş olmayan mənzərəsini əldə edə bilərik.

  • İkinci seçim, kitabxananın açıq şəkildə idxal edildiyi faylları axtarmaqdır. Bu yanaşma ilə bizə lazım olan kitabxananın məhz bu faylda istifadə olunduğuna əmin ola bilərik.

  • Üçüncü variant isə yuxarıda göstərilən iki yanaşmadan birlikdə istifadə etməkdir.

Nümunə olaraq dar dairələrdə yaxşı tanınan bir kitabxanaya nəzər salaq hamar Scala proqramlaşdırma dili üçün, yəni funksionallıq Hərfi dəyərlərin birləşdirilməsi. Ümumiyyətlə, parametrləri SQL sorğusuna ötürmək üçün operatordan istifadə etməlisiniz $, məlumatları əvvəlcədən hazırlanmış SQL sorğusuna əvəz edir. Yəni əslində Java-da Hazırlanmış Bəyanatın birbaşa analoqudur. Lakin, SQL sorğusunu dinamik şəkildə qurmaq lazımdırsa, məsələn, cədvəl adlarını ötürmək lazımdırsa, operatordan istifadə edə bilərsiniz. #$, bu, məlumatları birbaşa sorğuya əvəz edəcək (demək olar ki, simli birləşmə kimi).

Nümunə kodu:

// В общем случае - значения, контролируемые пользователем
val table = "coffees"
sql"select * from #$table where name = $name".as[Coffee].headOption

Checkmarx hələ Splicing Literal Values ​​istifadəsini necə aşkar edəcəyini bilmir və operatorları atlayır #$, buna görə də potensial SQL inyeksiyalarını müəyyən etməyi və kodda düzgün yerləri vurğulamağı öyrətməyə çalışaq:

// Находим все импорты
CxList imports = All.FindByType(typeof(Import));

// Ищем по имени, есть ли в импортах slick
CxList slick = imports.FindByShortName("slick");

// Некоторый флаг, определяющий, что импорт библиотеки в коде присутствует
// Для более точного определения - можно применить подход с именем файла
bool not_empty_list = false;
foreach (CxList r in slick)
{
    // Если встретили импорт, считаем, что slick используется
	not_empty_list = true;
}

if (not_empty_list) {
    // Ищем вызовы, в которые передается SQL-строка
	CxList sql = All.FindByShortName("sql");
	sql.Add(All.FindByShortName("sqlu"));
	
	// Определяем данные, которые попадают в эти вызовы
	CxList data_sql = All.DataInfluencingOn(sql);
	
	// Так как синтакис не поддерживается, можно применить подход с регулярными выражениями
	// RegExp стоит использовать крайне осторожно и не применять его на большом количестве данных, так как это может сильно повлиять на производительность
	CxList find_possible_inj = data_sql.FindByRegex(@"#$", true, true, true);

    // Избавляемся от лишних срабатываний, если они есть и выводим в результат
	result = find_possible_inj.FindByType(typeof(BinaryExpr));
}

Vəzifə: Açıq Mənbəli kitabxanalarda istifadə olunan həssas funksiyaları axtarın

həll: Bir çox şirkətlər hazırlanmış proqramlarda kitabxanaların həssas versiyalarının istifadəsini aşkar etmək üçün Açıq Mənbəli monitorinq alətlərindən (OSA təcrübəsi) istifadə edirlər. Bəzən belə kitabxananı təhlükəsiz versiyaya yeniləmək mümkün olmur. Bəzi hallarda funksional məhdudiyyətlər var, digərlərində isə ümumiyyətlə təhlükəsiz versiya yoxdur. Bu halda, SAST və OSA təcrübələrinin kombinasiyası zəifliyin istismarına səbəb olan funksiyaların kodda istifadə edilmədiyini müəyyən etməyə kömək edəcək.

Ancaq bəzən, xüsusən də JavaScript-i nəzərdən keçirərkən, bu tamamilə əhəmiyyətsiz bir iş olmaya bilər. Aşağıda, bəlkə də ideal olmayan bir həll var, lakin buna baxmayaraq, komponentdəki zəifliklərdən istifadə edərək işləyir. lodash üsullarda template и *set.

JS faylında potensial həssas kodun test nümunələri:

/**
 * Template example
 */

'use strict';
var _ = require("./node_modules/lodash.js");


// Use the "interpolate" delimiter to create a compiled template.
var compiled = _.template('hello <%= js %>!');
console.log(compiled({ 'js': 'lodash' }));
// => 'hello lodash!'

// Use the internal `print` function in "evaluate" delimiters.

var compiled = _.template('<% print("hello " + js); %>!');
console.log(compiled({ 'js': 'lodash' }));
// => 'hello lodash!'

Və birbaşa html-də qoşulduqda:

<!DOCTYPE html>
<html>
<head>
    <title>Lodash Tutorial</title>
    <script src="./node_modules/lodash.js"></script>
    <script type="text/javascript">
  // Lodash chunking array
        nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];

        let c1 = _.template('<% print("hello " + js); %>!');
        console.log(c1);

        let c2 = _.template('<% print("hello " + js); %>!');
        console.log(c2);
    </script>
</head>
<body></body>
</html>

Biz zəifliklərdə sadalanan bütün həssas üsullarımızı axtarırıq:

// Ищем все строки: в которых встречается строка lodash (предполагаем, что это объявление импорта библиотеки
CxList lodash_strings = Find_String_Literal().FindByShortName("*lodash*");

// Ищем все данные: которые взаимодействуют с этими строками
CxList data_on_lodash = All.InfluencedBy(lodash_strings);


// Задаем список уязвимых методов
List<string> vulnerable_methods = new List<string> {"template", "*set"};

// Ищем все наши уязвимые методы, которые перечисленны в уязвимостях и отфильтровываем их только там, где они вызывались
CxList vulnerableMethods = All.FindByShortNames(vulnerable_methods).FindByType(typeof(MethodInvokeExpr));

//Находим все данные: которые взаимодействуют с данными методами
CxList vulnFlow = All.InfluencedBy(vulnerableMethods);

// Если есть пересечение по этим данным - кладем в результат
result = vulnFlow * data_on_lodash;

// Формируем список путей по которым мы уже прошли, чтобы фильтровать в дальнейшем дубли
List<string> lodash_result_path = new List<string> {};

foreach(CxList lodash_result in result)
{
    // Очередной раз получаем пути к файлам
	string file_name = lodash_result.GetFirstGraph().LinePragma.FileName;
	lodash_result_path.Add(file_name);
}

// Дальше идет часть относящаяся к html файлам, так как в них мы не можем проследить откуда именно идет вызов
// Формируем массив путей файлов, чтобы быть уверенными, что срабатывания уязвимых методов были именно в тех файлах, в которых объявлен lodash
List<string> lodash_path = new List<string> {};
foreach(CxList string_lodash in lodash_strings)
{
	string file_name = string_lodash.GetFirstGraph().LinePragma.FileName;
	lodash_path.Add(file_name);
}

// Перебираем все уязвимые методы и убеждаемся, что они вызваны в тех же файлах, что и объявление/включение lodash
foreach(CxList method in vulnerableMethods)
{
	string file_name_method = method.GetFirstGraph().LinePragma.FileName;
	if (lodash_path.Contains(file_name_method) == true && lodash_result_path.Contains(file_name_method) == false){
		result.Add(method);
	}
}

// Убираем все UknownReferences и оставляем самый "длинный" из путей, если такие встречаются
result = result.ReduceFlow(CxList.ReduceFlowType.ReduceSmallFlow) - result.FindByType(typeof(UnknownReference));

Vəzifə: Tətbiqə daxil edilmiş sertifikatlar axtarılır

həll: Tətbiqlərin, xüsusən də mobil proqramların müxtəlif serverlərə daxil olmaq və ya SSL-Pinning-i yoxlamaq üçün sertifikat və ya açarlardan istifadə etməsi qeyri-adi deyil. Təhlükəsizlik baxımından belə şeyləri kodda saxlamaq ən yaxşı təcrübə deyil. Anbarda oxşar faylları axtaracaq bir qayda yazmağa çalışaq:

// Найдем все сертификаты по маске файла
CxList find_certs = All.FindByShortNames(new List<string> {"*.der", "*.cer", "*.pem", "*.key"}, false);

// Проверим, где в приложении они используются
CxList data_used_certs = All.DataInfluencedBy(find_certs);

// И для мобильных приложений - можем поискать методы, где вызывается чтение сертификатов
// Для других платформ и приложений могут быть различные методы
CxList methods = All.FindByMemberAccess("*.getAssets");

// Пересечение множеств даст нам результат по использованию локальных сертификатов в приложении
result = methods * data_used_certs;

Vəzifə: Tətbiqdə pozulmuş nişanların tapılması

həll: Tez-tez pozulmuş tokenləri və ya kodda mövcud olan digər vacib məlumatları ləğv etmək lazımdır. Əlbəttə ki, onları mənbə kodunda saxlamaq yaxşı fikir deyil, lakin vəziyyətlər fərqlidir. CxQL sorğuları sayəsində bu kimi şeyləri tapmaq olduqca asandır:

// Получаем все строки, которые содержатся в коде
CxList strings = base.Find_Strings();

// Ищем среди всех строк нужное нам значение. В примере токен в виде строки "qwerty12345"
result = strings.FindByShortName("qwerty12345");

Nəticə

Ümid edirəm ki, bu məqalə Checkmarx aləti ilə tanışlığa başlayanlar üçün faydalı olacaq. Ola bilsin ki, uzun müddətdir öz qaydalarını yazanlar da bu təlimatda faydalı bir şey tapacaqlar.

Təəssüf ki, hazırda Checkmarx üçün qaydaların hazırlanması zamanı yeni ideyaların əldə oluna biləcəyi resurs yoxdur. Ona görə yaratdıq Github-da depo, CxQL-dən istifadə edən hər kəsin orada faydalı bir şey tapması, həmçinin işlərini cəmiyyətlə bölüşmək imkanı olması üçün işimizi burada dərc edəcəyik. Anbar məzmunun doldurulması və strukturlaşdırılması prosesindədir, ona görə də ianəçilər xoş gəlmisiniz!

Diqqətiniz üçün təşəkkür edirik!

Mənbə: www.habr.com

Добавить комментарий