Hoe om reëls vir Checkmarx te skryf sonder om mal te word

Haai Habr!

In ons werk handel ons maatskappy baie dikwels met verskeie statiese kode-analise-instrumente (SAST). Uit die boks werk hulle almal gemiddeld. Dit hang natuurlik alles af van die projek en die tegnologieë wat daarin gebruik word, asook hoe goed hierdie tegnologieë deur die reëls van analise gedek word. Na my mening is een van die belangrikste kriteria by die keuse van 'n SAST-instrument die vermoë om dit aan te pas by die besonderhede van jou toepassings, naamlik om analisereëls te skryf en te verander of, soos dit meer dikwels genoem word, Custom Queries.

Hoe om reëls vir Checkmarx te skryf sonder om mal te word

Ons gebruik meestal Checkmarx - 'n baie interessante en kragtige kode-ontleder. In hierdie artikel sal ek praat oor my ervaring van die skryf van ontledingsreëls daarvoor.

Inhoudsopgawe

Entry

Om mee te begin, wil ek graag een van die min artikels in Russies aanbeveel oor die kenmerke van die skryf van navrae vir Checkmarx. Dit is aan die einde van 2019 op Habré gepubliseer onder die titel: "Hallo, Checkmarx!" Hoe om 'n Checkmarx SAST-navraag te skryf en koel kwesbaarhede te vind.

Dit ondersoek in detail hoe om die eerste navrae in CxQL (Checkmarx Query Language) te skryf vir een of ander toetstoepassing en toon die basiese beginsels van hoe analisereëls werk.

Ek sal nie herhaal wat daarin beskryf word nie, hoewel sommige kruisings steeds teenwoordig sal wees. In my artikel gaan ek probeer om 'n soort "versameling resepte" saam te stel, 'n lys van oplossings vir spesifieke probleme wat ek tydens my werk met Checkmarx teëgekom het. Ek moes my brein oor baie van hierdie probleme. Soms was daar nie genoeg inligting in die dokumentasie nie, en soms was dit selfs moeilik om te verstaan ​​hoe om te doen wat vereis word. Ek hoop dat my ervaring en slapelose nagte nie tevergeefs sal wees nie, en hierdie "versameling van Custom Queries resepte" sal jou 'n paar uur of 'n paar senuweeselle spaar. So, kom ons begin!

Algemene inligting oor die reëls

Kom ons kyk eers na 'n paar basiese konsepte en die proses om met die reëls te werk, vir 'n beter begrip van wat volgende gaan gebeur. En ook omdat die dokumentasie niks hieroor sê nie of baie versprei is in die struktuur, wat nie baie gerieflik is nie.

  1. Die reëls word tydens skandering toegepas, afhangende van die voorafinstelling wat aan die begin gekies is ('n stel aktiewe reëls). U kan 'n onbeperkte aantal voorafinstellings skep, en presies hoe om dit te struktureer hang af van die besonderhede van u proses. Jy kan hulle volgens taal groepeer of voorafinstellings vir elke projek kies. Die aantal aktiewe reëls beïnvloed die spoed en akkuraatheid van skandering.

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordStel voorafinstelling in die Checkmarx-koppelvlak op

  2. Die reëls word geredigeer in 'n spesiale instrument genaamd CxAuditor. Dit is 'n lessenaartoepassing wat koppel aan 'n bediener wat Checkmarx gebruik. Hierdie instrument het twee werkswyses: redigeerreëls en ontleding van die resultate van 'n reeds uitgevoer skandering.

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordCxAudit-koppelvlak

  3. Reëls in Checkmarx word volgens taal verdeel, dit wil sê, elke taal het sy eie stel navrae. Daar is ook 'n paar algemene reëls wat geld ongeag taal, dit is die sogenaamde basiese navrae. Vir die grootste deel behels basiese navrae die soeke na inligting wat ander reëls gebruik.

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordVerdeel reëls volgens taal

  4. Reëls is "Uitvoerbaar" en "Nie-uitvoerbaar" (Uitgevoer en nie uitgevoer nie). Nie heeltemal die korrekte naam nie, na my mening, maar dit is wat dit is. Die slotsom is dat die resultaat van die uitvoering van "Uitvoerbare" reëls in die skanderingsresultate in die UI vertoon sal word, en "Nie-uitvoerbare" reëls is slegs nodig om hul resultate in ander versoeke te gebruik (in wese net 'n funksie).

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordBepaling van die reëltipe tydens skep

  5. Jy kan nuwe reëls skep of bestaandes aanvul/herskryf. Om 'n reël te herskryf, moet jy dit in die boom vind, regskliek en kies "Oorskryf" uit die aftreklys. Dit is belangrik om hier te onthou dat die nuwe reëls nie aanvanklik by die voorafinstellings ingesluit is nie en nie aktief is nie. Om dit te begin gebruik, moet jy dit aktiveer in die "Preset Manager"-kieslys in die instrument. Hergeskrewe reëls behou hul instellings, dit wil sê, as die reël aktief was, sal dit so bly en sal onmiddellik toegepas word.

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordVoorbeeld van 'n nuwe reël in die Preset Manager-koppelvlak

  6. Tydens uitvoering word 'n "boom" van versoeke gebou, wat afhang van wat. Die reëls wat inligting insamel, word eerste uitgevoer, en diegene wat dit gebruik tweede. Die uitvoeringsresultaat is in die kas, so as dit moontlik is om die resultate van 'n bestaande reël te gebruik, is dit beter om dit te doen, dit sal die skanderingstyd verminder.

  7. Reëls kan op verskillende vlakke toegepas word:

  • Vir die hele stelsel - sal gebruik word vir enige skandering van enige projek

  • Op spanvlak (Span) - sal slegs gebruik word om projekte in die gekose span te skandeer.

  • Op projekvlak - Sal toegepas word in 'n spesifieke projek

    Hoe om reëls vir Checkmarx te skryf sonder om mal te wordBepaling van die vlak waarop die reël toegepas sal word

"Woordeboek" vir beginners

En ek sal begin met 'n paar dinge wat my vrae veroorsaak het, en ek sal ook 'n aantal tegnieke wys wat die lewe aansienlik sal vereenvoudig.

Bewerkings met lyste

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

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

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

Alle items gevind

Binne die geskandeerde taal kan u 'n lys kry van absoluut alle elemente wat Checkmarx geïdentifiseer het (stringe, funksies, klasse, metodes, ens.). Dit is 'n ruimte van voorwerpe wat deur toegang verkry kan word All. Dit wil sê om te soek na 'n voorwerp met 'n spesifieke naam searchMe, kan jy byvoorbeeld op naam soek oor alle voorwerpe wat gevind is:

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

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

Maar as jy in 'n ander taal moet soek wat om een ​​of ander rede nie by die skandering ingesluit is nie (byvoorbeeld groovy in 'n Android-projek), kan jy ons voorwerpspasie uitbrei deur 'n veranderlike:

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

Funksies vir vloeianalise

Hierdie funksies word in baie reëls gebruik en hier is 'n klein cheat sheet van wat dit beteken:

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

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

Kry lêernaam/pad

Daar is verskeie eienskappe wat uit die resultate van 'n navraag verkry kan word (die naam van die lêer waarin die inskrywing gevind is, string, ens.), maar die dokumentasie sê nie hoe om dit te verkry en te gebruik nie. Dus, om dit te kan doen, moet u toegang tot die LinePragma-eiendom verkry en die voorwerpe wat ons benodig sal daarin geleë wees:

// Для примера найдем все методы
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);

Dit is die moeite werd om dit in gedagte te hou FileName bevat eintlik die pad na die lêer, aangesien ons die metode gebruik het GetFirstGraph.

Uitvoering resultaat

Daar is 'n spesiale veranderlike binne CxQL result, wat die resultaat van die uitvoering van jou geskrewe reël gee. Dit word onmiddellik geïnisialiseer en jy kan tussenresultate daarin skryf, dit verander en verfyn terwyl jy werk. Maar as daar geen toewysing aan hierdie veranderlike of funksie binne die reël is nie return— die uitvoeringsresultaat sal altyd nul wees.

Die volgende navraag sal niks aan ons terugstuur as gevolg van uitvoering nie en sal altyd leeg wees:

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

Maar, nadat ons die uitvoeringsresultaat aan die magiese veranderlike resultaat toegewys het, sal ons sien wat hierdie oproep aan ons terugstuur:

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

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

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

Gebruik die resultate van ander reëls

Reëls in Checkmarx kan analoog genoem word aan funksies in 'n gewone programmeertaal. Wanneer u 'n reël skryf, kan u die resultate van ander navrae gebruik. Byvoorbeeld, dit is nie nodig om elke keer vir alle metode-oproepe in die kode te soek nie, bel net die verlangde reël:

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

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

Hierdie benadering laat jou toe om die kode te verkort en die reëluitvoeringstyd aansienlik te verminder.

Oplossing van probleme

Tekening

As u met die instrument werk, is dit soms nie moontlik om die gewenste navraag onmiddellik te skryf nie en u moet eksperimenteer en verskillende opsies probeer. Vir so 'n geval bied die instrument aanteken, wat soos volg genoem word:

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

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

Maar dit is die moeite werd om te onthou dat hierdie metode slegs as insette aanvaar word tou, dus sal dit nie moontlik wees om 'n volledige lys van gevonde elemente te vertoon as gevolg van die eerste bewerking nie. Die tweede opsie, wat vir ontfouting gebruik word, is om van tyd tot tyd aan 'n towerveranderlike toe te wys result die resultaat van die navraag en kyk wat gebeur. Hierdie benadering is nie baie gerieflik nie; jy moet seker wees dat daar geen ignorering of bewerkings met hierdie in die kode na result of maak eenvoudig kommentaar op die kode hieronder. Of jy kan, soos ek, vergeet om verskeie sulke oproepe van 'n klaargemaakte reël te verwyder en wonder hoekom niks werk nie.

'n Geriefliker manier is om die metode te noem return met die vereiste parameter. In hierdie geval sal die uitvoering van die reël eindig en ons sal kan sien wat gebeur het as gevolg van wat ons geskryf het:

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

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

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

Aanmelding probleem

Daar is situasies wanneer jy nie toegang tot die CxAudit-instrument kan kry nie (wat gebruik word om reëls te skryf). Daar kan baie redes hiervoor wees, insluitend ineenstortings, skielike Windows-opdaterings, BSOD en ander onvoorsiene situasies wat buite ons beheer is. In hierdie geval is daar soms 'n onvoltooide sessie in die databasis, wat jou verhoed om weer aan te meld. Om dit reg te stel, moet jy verskeie navrae uitvoer:

Vir Checkmarx voor 8.6:

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

Vir Checkmarx na 8.6:

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

Skryfreëls

Nou kom ons by die interessantste deel. Wanneer jy reëls in CxQL begin skryf, is dit wat jy dikwels kort nie soseer dokumentasie nie, maar 'n paar lewende voorbeelde van die oplossing van sekere probleme en die beskrywing van die proses van navraagbewerking in die algemeen.

Ek sal probeer om die lewe 'n bietjie makliker te maak vir diegene wat in die navraagtaal begin duik en verskeie voorbeelde gee van die gebruik van Custom Queries om sekere probleme op te los. Sommige van hulle is redelik algemeen en kan feitlik sonder veranderinge in jou onderneming gebruik word, ander is meer spesifiek, maar hulle kan ook gebruik word deur die kode te verander om by die besonderhede van jou toepassings te pas.

So, hier is die probleme wat ons die meeste teëgekom het:

'N Taak: Daar is verskeie vloei in die resultate van die uitvoering van die reël en een van hulle is 'n nes van 'n ander, moet jy een van hulle verlaat.

oplossing: Inderdaad, soms wys Checkmarx verskeie datavloei wat kan oorvleuel en 'n verkorte weergawe van ander kan wees. Daar is 'n spesiale metode vir sulke gevalle Verminder vloei. Afhangende van die parameter, sal dit die kortste of langste vloei kies:

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

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

'N Taak: Brei die lys sensitiewe data uit waarop die instrument reageer

oplossing: Checkmarx het basiese reëls, waarvan die resultate deur baie ander navrae gebruik word. Deur sommige van hierdie reëls aan te vul met data spesifiek vir jou toepassing, kan jy jou skanderingsresultate onmiddellik verbeter. Hieronder is 'n voorbeeldreël om aan die gang te kom:

General_privacy_violation_list

Kom ons voeg verskeie veranderlikes by wat in ons toepassing gebruik word om sensitiewe inligting te stoor:

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

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

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

'N Taak: Brei die lys veranderlikes uit met wagwoorde

oplossing: Ek sal aanbeveel dat u dadelik aandag gee aan die basiese reël vir die definisie van wagwoorde in kode en 'n lys veranderlike name wat algemeen in u onderneming gebruik word, daarby voeg.

Password_privacy_violation_list

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);
	}
}

'N Taak: Voeg gebruikte raamwerke by wat nie deur Checkmarx ondersteun word nie

oplossing: Alle navrae in Checkmarx word volgens taal gedeel, so jy moet reëls vir elke taal byvoeg. Hieronder is 'n paar voorbeelde van sulke reëls.

As biblioteke gebruik word wat standaardfunksionaliteit aanvul of vervang, kan hulle maklik by die basiese reël gevoeg word. Dan sal almal wat dit gebruik dadelik van die nuwe bekendstellings leer. As 'n voorbeeld, biblioteke vir aanteken in Android is Timber en Loggi. In die basiese pakket is daar geen reëls vir die identifisering van nie-stelseloproepe nie, so as 'n wagwoord of sessie-identifiseerder in die logboek kom, sal ons nie daarvan weet nie. Kom ons probeer om definisies van sulke metodes by die Checkmarx-reëls te voeg.

Toetskode-voorbeeld wat die Timber-biblioteek vir aanteken gebruik:

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");
    }
}

En hier is 'n voorbeeld van 'n versoek vir Checkmarx, wat jou sal toelaat om 'n definisie van die oproep van Timber-metodes as 'n uitgangpunt vir data van die toepassing by te voeg:

Vind Android-uitsette

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

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

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

En jy kan ook by die naburige reël voeg, maar hierdie een hou direk verband met die aanmelding van Android:

FindAndroidLog_Outputs

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

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

Ook, as Android-toepassings gebruik Werksbestuurder vir asinchroniese werk is dit 'n goeie idee om Checkmarx ook hieroor in te lig deur 'n metode by te voeg om data van die taak af te kry getInputData:

FindAndroidRead

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

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

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

'N Taak: Soek na sensitiewe data in plist vir iOS-projekte

oplossing: iOS gebruik dikwels spesiale lêers met die .plist-uitbreiding om verskeie veranderlikes en waardes te stoor. Dit word nie aanbeveel om wagwoorde, tekens, sleutels en ander sensitiewe data in hierdie lêers te stoor nie, aangesien dit sonder enige probleme uit die toestel onttrek kan word.

Plist-lêers het kenmerke wat nie met die blote oog duidelik is nie, maar is belangrik vir Checkmarx. Kom ons skryf 'n reël wat sal soek vir die data wat ons benodig en vir ons sê of wagwoorde of tekens iewers genoem word.

'n Voorbeeld van so 'n lêer, wat 'n teken bevat vir kommunikasie met die backend-diens:

<?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>

En 'n reël vir Checkmarx, wat verskeie nuanses het wat in ag geneem moet word wanneer jy skryf:

// Используем результат выполнения правила по поиску файлов 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);

'N Taak: Vind inligting in XML

oplossing: Checkmarx het baie gerieflike funksies om met XML te werk en na waardes, etikette, eienskappe en meer te soek. Maar ongelukkig was daar 'n fout in die dokumentasie wat nie 'n enkele voorbeeld werk nie. Ten spyte van die feit dat hierdie gebrek in die jongste weergawe van die dokumentasie uitgeskakel is, wees versigtig as jy vroeëre weergawes van dokumente gebruik.

Hier is 'n verkeerde voorbeeld uit die dokumentasie:

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

As gevolg van die uitvoeringspoging sal ons 'n fout ontvang wat All daar is nie so 'n metode nie... En dit is waar, aangesien daar 'n spesiale, aparte voorwerpspasie is vir die gebruik van funksies om met XML te werk - cxXPath. Dit is hoe die korrekte navraag lyk om 'n instelling in Android te vind wat die gebruik van HTTP-verkeer toelaat:

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

Kom ons kyk na dit in 'n bietjie meer detail, aangesien die sintaksis vir alle funksies soortgelyk is, nadat jy een uitgepluis het, dan hoef jy net die een te kies wat jy nodig het. Dus, opeenvolgend volgens die parameters:

  • "*.xml"- masker van lêers wat deursoek moet word

  • 8 — id van die taal waarvoor die reël toegepas word

  • "cleartextTrafficPermitted"- kenmerk naam in xml

  • "true" — die waarde van hierdie eienskap

  • false - gebruik van gereelde uitdrukking wanneer jy soek

  • true — beteken dat die soektog uitgevoer sal word met die ignorering van geval, dit wil sê, hoofletter-onsensitief

As voorbeeld het ons 'n reël gebruik wat verkeerde, uit 'n sekuriteitsoogpunt, netwerkverbindinginstellings in Android identifiseer wat kommunikasie met die bediener via die HTTP-protokol toelaat. Voorbeeld van 'n instelling wat 'n kenmerk bevat cleartextTrafficPermitted met betekenis 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>

'N Taak: Beperk resultate volgens lêernaam/pad

oplossing: In een van die groot projekte wat verband hou met die ontwikkeling van 'n mobiele toepassing vir Android, het ons vals positiewe teëgekom van die reël wat die verduistering-instelling bepaal. Die feit is dat die reël buite die boks soek in die lêer build.gradle 'n instelling wat verantwoordelik is vir die toepassing van verduisteringreëls vir die vrystellingweergawe van die toepassing.

Maar in groot projekte is daar soms kinderlêers build.gradle, wat verwys na die biblioteke wat by die projek ingesluit is. Die eienaardigheid is dat selfs as hierdie lêers nie die behoefte aan verduistering aandui nie, sal die instellings van die ouersamestellinglêer tydens samestelling toegepas word.

Die taak is dus om snellers af te sny in kinderlêers wat aan biblioteke behoort. Hulle kan uitgeken word aan die teenwoordigheid van die lyn apply 'com.android.library'.

Voorbeeld kode uit lêer build.gradle, wat die behoefte aan verduistering bepaal:

apply plugin: 'com.android.application'

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

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

dependencies {
  ...
}

Voorbeeld lêer build.gradle vir 'n biblioteek wat by die projek ingesluit is wat nie hierdie instelling het nie:

apply plugin: 'android-library'

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

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

En die reël vir Checkmarx:

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);
		}
	}
}

Hierdie benadering kan redelik universeel en nuttig wees, nie net vir Android-toepassings nie, maar ook vir ander gevalle wanneer u moet bepaal of 'n resultaat aan 'n spesifieke lêer behoort.

'N Taak: Voeg ondersteuning by vir 'n derdeparty-biblioteek as die sintaksis nie ten volle ondersteun word nie

oplossing: Die aantal verskillende raamwerke wat gebruik word in die proses om kode te skryf, is eenvoudig buite die kaarte. Checkmarx weet natuurlik nie altyd van hul bestaan ​​nie, en ons taak is om dit te leer verstaan ​​dat sekere metodes spesifiek tot hierdie raamwerk behoort. Soms word dit bemoeilik deur die feit dat raamwerke funksiename gebruik wat baie algemeen voorkom en dit is onmoontlik om die verwantskap van 'n bepaalde oproep tot 'n spesifieke biblioteek ondubbelsinnig te bepaal.

Die moeilikheid is dat die sintaksis van sulke biblioteke nie altyd korrek herken word nie en jy moet eksperimenteer om te verhoed dat jy 'n groot aantal vals positiewes kry. Daar is verskeie opsies om skandering akkuraatheid te verbeter en die probleem op te los:

  • Die eerste opsie, ons weet verseker dat die biblioteek in 'n spesifieke projek gebruik word en kan die reël op spanvlak toepas. Maar as die span besluit om 'n ander benadering te volg of verskeie biblioteke gebruik waarin funksiename oorvleuel, kan ons 'n nie baie aangename prentjie kry van talle vals positiewes

  • Die tweede opsie is om te soek vir lêers waarin die biblioteek duidelik ingevoer is. Met hierdie benadering kan ons seker wees dat die biblioteek wat ons benodig presies in hierdie lêer gebruik word.

  • En die derde opsie is om die twee bogenoemde benaderings saam te gebruik.

As voorbeeld, kom ons kyk na 'n biblioteek wat in noue kringe bekend is gladde vir die Scala-programmeertaal, naamlik die funksionaliteit Splitsing van letterlike waardes. Oor die algemeen, om parameters na 'n SQL-navraag deur te gee, moet jy die operateur gebruik $, wat data in 'n vooraf gevormde SQL-navraag vervang. Dit wil sê, dit is in werklikheid 'n direkte analoog van Voorbereide Verklaring in Java. Maar as jy 'n SQL-navraag dinamies moet bou, byvoorbeeld, as jy tabelname moet deurgee, kan jy die operateur gebruik #$, wat die data direk in die navraag sal vervang (amper soos string aaneenskakeling).

Kode voorbeeld:

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

Checkmarx weet nog nie hoe om die gebruik van Splicing Literal Values ​​​​op te spoor nie en slaan operateurs oor #$, so kom ons probeer dit leer om potensiële SQL-inspuitings te identifiseer en die regte plekke in die kode uit te lig:

// Находим все импорты
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));
}

'N Taak: Soek vir gebruikte kwesbare funksies in oopbronbiblioteke

oplossing: Baie maatskappye gebruik Oopbron-moniteringnutsmiddels (OSA-praktyk) om die gebruik van kwesbare weergawes van biblioteke in ontwikkelde toepassings op te spoor. Soms is dit nie moontlik om so 'n biblioteek op te dateer na 'n veilige weergawe nie. In sommige gevalle is daar funksionele beperkings, in ander is daar glad nie 'n veilige weergawe nie. In hierdie geval sal 'n kombinasie van SAST- en OSA-praktyke help om te bepaal dat die funksies wat lei tot die uitbuiting van die kwesbaarheid nie in die kode gebruik word nie.

Maar soms, veral as jy JavaScript oorweeg, is dit dalk nie 'n heeltemal onbenullige taak nie. Hieronder is 'n oplossing, miskien nie ideaal nie, maar werk nietemin, deur die voorbeeld van kwesbaarhede in die komponent te gebruik lodash in metodes template и *set.

Voorbeelde van toets potensieel kwesbare kode in 'n JS-lêer:

/**
 * 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!'

En wanneer jy direk in html koppel:

<!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>

Ons is op soek na al ons kwesbare metodes, wat in kwesbaarhede gelys word:

// Ищем все строки: в которых встречается строка 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));

'N Taak: Soek vir sertifikate wat in die aansoek ingebed is

oplossing: Dit is nie ongewoon dat toepassings, veral mobiele toepassings, sertifikate of sleutels gebruik om toegang tot verskeie bedieners te verkry of SSL-vasspeld te verifieer nie. Vanuit 'n sekuriteitsperspektief is dit nie die beste praktyk om sulke dinge in kode te stoor nie. Kom ons probeer om 'n reël te skryf wat vir soortgelyke lêers in die bewaarplek sal soek:

// Найдем все сертификаты по маске файла
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;

'N Taak: Vind gekompromitteerde tekens in die toepassing

oplossing: Dit is dikwels nodig om gekompromitteerde tekens of ander belangrike inligting wat in die kode voorkom, te herroep. Dit is natuurlik nie 'n goeie idee om dit binne die bronkode te stoor nie, maar situasies verskil. Danksy CxQL-navrae is dit redelik maklik om dinge soos hierdie te vind:

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

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

Gevolgtrekking

Ek hoop dat hierdie artikel nuttig sal wees vir diegene wat hul kennismaking met die Checkmarx-instrument begin. Miskien sal diegene wat al lank hul eie reëls skryf ook iets nuttigs in hierdie gids vind.

Ongelukkig is daar tans 'n gebrek aan 'n hulpbron waar nuwe idees ingesamel kan word tydens die ontwikkeling van reëls vir Checkmarx. Dis hoekom ons geskep het bewaarplek op Github, waar ons ons werk sal plaas sodat almal wat CxQL gebruik iets nuttigs daarin kan vind, en ook die geleentheid kry om hul werk met die gemeenskap te deel. Die bewaarplek is besig om inhoud in te vul en te struktureer, so bydraers is welkom!

Skep 'n nuwe weergawe!

Bron: will.com

Voeg 'n opmerking