Nola idatzi Checkmarx-erako arauak erotu gabe

Aupa Habr!

Gure lanean, gure enpresak sarritan kode estatikoko analisirako tresna ezberdinak (SAST) lantzen ditu. Kutxatik kanpo guztiak batez beste lan egiten dute. Jakina, dena proiektuaren eta bertan erabiltzen diren teknologien araberakoa da, baita teknologia horiek analisi-arauek zenbateraino betetzen dituzten ere. Nire ustez, SAST tresna bat aukeratzerakoan irizpide garrantzitsuenetako bat zure aplikazioen berezitasunetara pertsonalizatzeko gaitasuna da, hau da, analisi-arauak idatzi eta aldatzea edo, maizago deitzen zaien bezala, Kontsulta pertsonalizatuak.

Nola idatzi Checkmarx-erako arauak erotu gabe

Gehienetan Checkmarx erabiltzen dugu - kode analizatzaile oso interesgarria eta indartsua. Artikulu honetan analisi-arauak idazteko esperientziari buruz hitz egingo dut.

Edukien taula

Sarrera

Hasteko, Checkmarx-en kontsultak idazteko ezaugarriei buruzko errusierazko artikulu bakanetako bat gomendatu nahiko nuke. Habré-n argitaratu zen 2019aren amaieran izenburupean: "Kaixo, Checkmarx!" Nola idatzi Checkmarx SAST kontsulta bat eta aurkitu ahultasun politak.

Xehetasunez aztertzen du nola idatzi lehen kontsultak CxQL-n (Checkmarx Query Language) proba-aplikazio batzuetarako eta analisi-arauek nola funtzionatzen duten oinarrizko printzipioak erakusten ditu.

Ez dut bertan azaltzen dena errepikatuko, nahiz eta bidegurutze batzuk egongo diren oraindik. Nire artikuluan "errezeta bilduma" moduko bat osatzen saiatuko naiz, Checkmarx-ekin lanean aurkitu ditudan arazo zehatzetarako irtenbideen zerrenda. Arazo horietako askoren aurrean buru-belarri sartu behar izan nuen. Batzuetan ez zegoen dokumentazioan informazio nahikorik, eta, batzuetan, eskatzen zena nola egin ulertzea ere zaila zen. Nire esperientzia eta lorik gabeko gauak alferrikakoak ez izatea espero dut, eta "Personalizatutako Kontsulten errezeta bilduma" honek ordu batzuk edo nerbio-zelula pare bat aurreztuko ditu. Beraz, has gaitezen!

Arauei buruzko informazio orokorra

Lehenik eta behin, ikus ditzagun oinarrizko kontzeptu batzuk eta arauak lantzeko prozesua, ondoren gertatuko dena hobeto ulertzeko. Eta gainera dokumentazioak ez duelako ezer esaten edo egituran oso hedatuta dagoelako, ez baita oso erosoa.

  1. Arauak eskaneatzean aplikatzen dira hasieran hautatutako aurrez ezarritakoaren arabera (arau aktiboen multzoa). Aurrez ezarritako kopuru mugagabea sor dezakezu, eta nola egituratu zehatz-mehatz zure prozesuaren zehaztasunen araberakoa da. Hizkuntzaren arabera taldeka ditzakezu edo proiektu bakoitzerako aurrezarpenak hauta ditzakezu. Arau aktiboen kopuruak eragina du eskanearen abiadura eta zehaztasuna.

    Nola idatzi Checkmarx-erako arauak erotu gabePreset konfiguratzea Checkmarx interfazean

  2. Arauak CxAuditor izeneko tresna berezi batean editatzen dira. Hau Checkmarx exekutatzen duen zerbitzari batera konektatzen den mahaigaineko aplikazio bat da. Tresna honek bi funtzionamendu modu ditu: arauak editatzea eta dagoeneko egindako eskaneaketa baten emaitzak aztertzea.

    Nola idatzi Checkmarx-erako arauak erotu gabeCxAudit interfazea

  3. Checkmarx-en arauak hizkuntzaren arabera banatzen dira, hau da, hizkuntza bakoitzak bere kontsulta multzoa du. Hizkuntza edozein dela ere aplikatzen diren arau orokor batzuk ere badaude, oinarrizko kontsultak deiturikoak dira. Gehienetan, oinarrizko kontsultak beste arau batzuek erabiltzen duten informazioa bilatzea dakar.

    Nola idatzi Checkmarx-erako arauak erotu gabeArauak hizkuntzaren arabera banatzea

  4. Arauak "Exekutatugarriak" eta "Ez exekutagarriak" dira (Exekutatuta eta Exekutatu gabe). Ez da guztiz izen zuzena, nire ustez, baina hori da. Beheko lerroa da "Exekutagarriak" arauak exekutatzeko emaitza eskaneatu emaitzetan bistaratuko dela UI-n, eta "Ez exekutagarriak" arauak behar dira haien emaitzak beste eskaera batzuetan erabiltzeko (funtsean, funtzio bat besterik ez).

    Nola idatzi Checkmarx-erako arauak erotu gabeArau mota zehaztea sortzerakoan

  5. Arau berriak sor ditzakezu edo lehendik daudenak osatu/idatzi ditzakezu. Arau bat berridazteko, zuhaitzean aurkitu behar duzu, egin klik eskuineko botoiarekin eta hautatu "Gainarazi" goitibeherako menuan. Garrantzitsua da hemen gogoratzea arau berriak ez direla hasiera batean aurrezarpenetan sartzen eta ez daudela aktibo. Erabiltzen hasteko, tresnako "Preset Manager" menuan aktibatu behar dituzu. Berridatzitako arauek beren ezarpenak mantentzen dituzte, hau da, araua aktibo bazegoen, horrela mantenduko da eta berehala aplikatuko da.

    Nola idatzi Checkmarx-erako arauak erotu gabeAurrez ezarritako kudeatzailearen interfazeko arau berri baten adibidea

  6. Exekuzioan, eskaeren "zuhaitza" eraikitzen da, zeinaren araberakoa dena. Informazioa biltzen duten arauak exekutatzen dira lehenengo, eta erabiltzen dutenak bigarren. Exekuzioaren emaitza cachean gordetzen da, beraz, lehendik dagoen arau baten emaitzak erabiltzea posible bada, hobe da hori egitea, honek eskaneatzeko denbora murriztuko du.

  7. Arauak maila ezberdinetan aplika daitezke:

  • Sistema osorako - edozein proiektu eskaneatzeko erabiliko da

  • Talde mailan (Taldea) - hautatutako taldean proiektuak eskaneatzeko soilik erabiliko da.

  • Proiektu mailan - Proiektu zehatz batean aplikatuko da

    Nola idatzi Checkmarx-erako arauak erotu gabeAraua zein mailatan aplikatuko den zehaztea

Hasiberrientzako “Hiztegia”.

Eta galderak eragin zizkidaten zenbait gauzarekin hasiko naiz, eta bizitza nabarmen erraztuko duten hainbat teknika ere erakutsiko ditut.

Zerrendekin eragiketak

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

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

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

Aurkitutako elementu guztiak

Eskaneatutako hizkuntzaren barruan, Checkmarx-ek identifikatu dituen elementu guztien zerrenda lor dezakezu (kateak, funtzioak, klaseak, metodoak, etab.). Hau objektuen espazio bat da, bidez sar daitekeena All. Hau da, izen zehatza duen objektu bat bilatzeko searchMe, adibidez, aurkitutako objektu guztietan izenaren arabera bilatu dezakezu:

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

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

Baina, arrazoiren batengatik eskanean sartu ez den beste hizkuntza batean bilatu behar baduzu (adibidez, groovy Android proiektu batean), aldagai baten bidez zabaldu dezakezu gure objektu-espazioa:

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

Fluxuaren analisirako funtzioak

Funtzio hauek arau askotan erabiltzen dira eta hona hemen zer esan nahi duten iruzur orri txiki bat:

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

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

Fitxategiaren izena/bidea eskuratzen

Kontsulta baten emaitzetatik lor daitezkeen hainbat atributu (sarrera aurkitu den fitxategiaren izena, katea, etab.), baina dokumentazioak ez du esaten nola lortu eta nola erabili. Beraz, horretarako LinePragma propietatea sartu behar duzu eta behar ditugun objektuak barruan kokatuko dira:

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

Kontuan izatea merezi du FileName fitxategirako bidea dauka, metodoa erabili dugunez GetFirstGraph.

Exekuzioaren emaitza

CxQL barruan aldagai berezi bat dago result, zure idatzizko araua exekutatzeko emaitza itzultzen duena. Berehala hasten da eta tarteko emaitzak idatz ditzakezu bertan, lan egiten duzun bitartean aldatuz eta hobetuz. Baina, arauaren barruan aldagai edo funtzio honi esleipenik ez badago return— exekuzioaren emaitza beti izango da zero.

Ondorengo kontsultak ez digu ezer itzuliko exekuzioaren ondorioz eta beti egongo da hutsik:

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

Baina, exekuzioaren emaitza aldagai magikoaren emaitzari esleitu ondoren, dei honek zer itzultzen digun ikusiko dugu:

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

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

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

Beste arau batzuen emaitzak erabiltzea

Checkmarx-en arauak ohiko programazio-lengoaia bateko funtzioen antzekoak dei daitezke. Arau bat idaztean, baliteke beste kontsulta batzuen emaitzak erabiltzea. Adibidez, ez dago aldi bakoitzean metodo-dei guztiak kodean bilatu beharrik, nahi duzun araura deitu besterik ez dago:

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

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

Ikuspegi honek kodea laburtu eta arauen exekuzio denbora nabarmen murrizten du.

Arazoen konponbidea

Erregistratzea

Tresnarekin lan egitean, batzuetan ezin da nahi duzun kontsulta berehala idatzi eta esperimentatu egin behar duzu, aukera desberdinak probatuz. Horrelako kasuetarako, tresnak erregistroa eskaintzen du, honela deitzen dena:

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

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

Baina merezi du gogoratzea metodo honek sarrera gisa soilik onartzen duela katea, beraz, ezin izango da lehenengo eragiketaren ondorioz aurkitutako elementuen zerrenda osoa bistaratu. Bigarren aukera, arazketarako erabiltzen dena, noizean behin aldagai magiko bati esleitzea da result kontsultaren emaitza eta ikusi zer gertatzen den. Ikuspegi hau ez da oso erosoa; ziurtatu behar duzu kodean ez dagoela baliogabetze edo eragiketarik ondoren. result edo, besterik gabe, komentatu beheko kodea. Edo, ni bezala, ahaztu egin dezakezu horrelako hainbat dei prest egindako arau batetik kentzea eta zergatik ezer ez dabilen galdetzea.

Modu erosoagoa metodoari deitzea da return eskatutako parametroarekin. Kasu honetan, arauaren exekuzioa amaituko da eta guk idatzitakoaren ondorioz gertatutakoa ikusi ahal izango dugu:

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

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

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

Saioa hasteko arazoa

Badaude CxAudit tresnara sartu ezin duzun egoerak (arauak idazteko erabiltzen dena). Arrazoi asko egon daitezke, besteak beste, hutsegiteek, bat-bateko Windows eguneratzeak, BSOD eta gure kontroletik kanpo dauden ustekabeko beste egoera batzuk. Kasu honetan, batzuetan datu-basean amaitu gabeko saio bat dago, eta horrek berriro saioa hastea galarazten dizu. Konpontzeko, hainbat kontsulta egin behar dituzu:

Checkmarx 8.6 baino lehen:

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

Checkmarx-erako 8.6 ondoren:

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

Idazteko arauak

Orain zatirik interesgarrienera iritsiko gara. CxQL-en arauak idazten hasten zarenean, askotan falta zaizuna ez da dokumentazioa, arazo batzuk konpontzeko eta kontsultak oro har nola funtzionatzen duen prozesua deskribatzeko adibide bizi batzuk baizik.

Kontsulten hizkuntzan murgiltzen hasi direnei bizitza apur bat errazten saiatuko naiz eta arazo jakin batzuk konpontzeko Kontsulta pertsonalizatuak erabiltzearen hainbat adibide emango ditut. Horietako batzuk nahiko orokorrak dira eta zure enpresan ia aldaketarik gabe erabil daitezke, beste batzuk zehatzagoak dira, baina kodea aldatuz ere erabil daitezke zure aplikazioen berezitasunetara egokitzeko.

Beraz, hona hemen gehien topatu ditugun arazoak:

Helburua: Araua exekutatzeko emaitzetan hainbat Fluxu daude eta horietako bat beste baten habia da, horietako bat utzi behar duzu.

irtenbidea: Izan ere, batzuetan Checkmarx-ek hainbat datu-fluxu erakusten ditu gainjarri daitezkeen eta besteen bertsio laburtu bat izan daitezkeenak. Horrelako kasuetarako metodo berezi bat dago MurriztuFlow. Parametroaren arabera, Fluxurik laburrena edo luzeena hautatuko du:

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

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

Helburua: Zabaldu tresnak erreakzionatzen duen datu sentikorren zerrenda

irtenbidea: Checkmarx-ek oinarrizko arauak ditu, eta horien emaitzak beste hainbat kontsultak erabiltzen dituzte. Arau horietako batzuk zure aplikazioari dagozkion datuekin osatuz gero, berehala hobetu ditzakezu eskaneatu emaitzak. Jarraian arau adibide bat duzu hasteko:

Pribatutasun_urraketa_zerrenda orokorra

Gehi ditzagun gure aplikazioan informazio sentikorra gordetzeko erabiltzen diren hainbat aldagai:

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

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

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

Helburua: Zabaldu pasahitzekin aldagaien zerrenda

irtenbidea: Kodean pasahitzak definitzeko oinarrizko arauari arreta jartzea gomendatuko nuke berehala eta zure enpresan erabili ohi diren aldagaien izenen zerrenda gehitzea.

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

Helburua: Gehitu Checkmarx-ek onartzen ez dituen erabilitako markoak

irtenbidea: Checkmarx-en kontsulta guztiak hizkuntzaren arabera banatzen dira, beraz, hizkuntza bakoitzerako arauak gehitu behar dituzu. Jarraian, arau horien adibide batzuk daude.

Funtzionalitate estandarra osatzen edo ordezkatzen duten liburutegiak erabiltzen badira, erraz gehi daitezke oinarrizko araura. Orduan erabiltzen duten guztiek berehala ezagutuko dute aurkezpen berrien berri. Adibide gisa, Android-en saioa hasteko liburutegiak Timber eta Loggi dira. Oinarrizko paketean, sistemakoak ez diren deiak identifikatzeko araurik ez dago, beraz, pasahitza edo saio-identifikatzailea erregistroan sartzen bada, ez dugu horren berri izango. Saia gaitezen Checkmarx arauei halako metodoen definizioak gehitzen.

Timber liburutegia erregistratzeko erabiltzen duen proba-kodearen adibidea:

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

Eta hona hemen Checkmarx-en eskaeraren adibide bat, Timber metodoak deitzeko definizio bat gehitzeko aukera emango dizuna aplikazioko datuetarako irteera puntu gisa:

AurkituAndroidOutputs

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

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

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

Eta aldameneko araura ere gehi dezakezu, baina hau Android-en saioa hastearekin lotuta dago zuzenean:

AurkituAndroidLog_Outputs

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

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

Gainera, Android aplikazioak erabiltzen badira Laneko kudeatzailea lan asinkronorako, komeni da Checkmarx-i horri buruz jakinaraztea, zereginaren datuak lortzeko metodo bat gehituz. getInputData:

AurkituAndroidIrakurri

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

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

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

Helburua: Datu sentikorren bila plist-en iOS proiektuetarako

irtenbidea: iOS-ek askotan .plist luzapena duten fitxategi bereziak erabiltzen ditu hainbat aldagai eta balio gordetzeko. Ez da gomendagarria fitxategi hauetan pasahitzak, tokenak, giltzak eta bestelako datu sentikorrak gordetzea, gailutik arazorik gabe atera baitaitezke.

Plist fitxategiek begi hutsez begi bistakoak ez diren ezaugarriak dituzte, baina Checkmarx-entzat garrantzitsuak dira. Idatz dezagun arau bat, behar ditugun datuak bilatuko dituen eta pasahitzak edo tokenak nonbait aipatzen diren esango digu.

Fitxategi horren adibide bat, backend zerbitzuarekin komunikatzeko token bat daukana:

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

Eta Checkmarx-en arau bat, idazteko orduan kontuan hartu beharreko hainbat ñabardura dituena:

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

Helburua: XML-n informazioa bilatzea

irtenbidea: Checkmarx-ek funtzio oso erosoak ditu XMLrekin lan egiteko eta balioak, etiketak, atributuak eta abar bilatzeko. Baina, tamalez, akats bat egon zen dokumentazioan, eta horren ondorioz adibide bakar batek ere ez du funtzionatzen. Dokumentazioaren azken bertsioan akats hori ezabatu den arren, kontuz ibili dokumentuen aurreko bertsioak erabiltzen badituzu.

Hona hemen dokumentazioko adibide oker bat:

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

Exekuzio saiakeraren ondorioz, akats bat jasoko dugu All ez dago horrelako metodorik... Eta hori egia da, XMLrekin lan egiteko funtzioak erabiltzeko objektu-espazio berezi eta bereizi bat dagoenez - cxXPath. Hau da Android-en HTTP trafikoa erabiltzeko aukera ematen duen ezarpen bat aurkitzeko kontsulta zuzenak:

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

Ikus dezagun xehetasun apur bat gehiago, funtzio guztien sintaxia antzekoa denez, bat asmatu ondoren, behar duzuna hautatu besterik ez duzu egin behar. Beraz, sekuentzialki parametroen arabera:

  • "*.xml"— Bilatu beharreko fitxategien maskara

  • 8 — Araua aplikatzen den hizkuntzaren id

  • "cleartextTrafficPermitted"— atributuaren izena xml-n

  • "true" — Atributu honen balioa

  • false — Bilatzerakoan adierazpen erregularra erabiltzea

  • true — esan nahi du bilaketa maiuskulak eta minuskulak alde batera utzita egingo dela, hau da, maiuskulak eta minuskulak bereiziz

Adibide gisa, zerbitzariarekin HTTP protokoloaren bidez komunikazioa ahalbidetzen duten Android-en sare-konexioaren ezarpen okerrak identifikatzen dituen arau bat erabili dugu, segurtasunaren ikuspuntutik. Atributu bat duen ezarpen baten adibidea cleartextTrafficPermitted esanahiarekin 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>

Helburua: Mugatu emaitzak fitxategi-izenaren/bidearen arabera

irtenbidea: Android-erako mugikorrentzako aplikazio baten garapenarekin lotutako proiektu handietako batean, ofuskapen ezarpena zehazten duen arauaren positibo faltsuak topatu genituen. Kontua da koadrotik kanpoko arauak fitxategian bilatzen duela build.gradle aplikazioaren bertsiorako ofuskazio-arauak aplikatzeaz arduratzen den ezarpena.

Baina proiektu handietan batzuetan haur fitxategiak daude build.gradle, proiektuan sartutako liburutegiei erreferentzia egiten zaie. Berezitasuna da fitxategi hauek ezkutatzeko beharra adierazten ez badute ere, muntaketa-fitxategi nagusiaren ezarpenak konpilatzean aplikatuko direla.

Horrela, liburutegiei dagozkien haur fitxategietan abiarazleak moztea da zeregina. Lerroaren presentziaren arabera identifikatu daitezke apply 'com.android.library'.

Fitxategiko kodearen adibidea build.gradle, lausotzearen beharra zehazten duena:

apply plugin: 'com.android.application'

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

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

dependencies {
  ...
}

Fitxategiaren adibidea build.gradle ezarpen hau ez duen proiektuan sartutako liburutegi baterako:

apply plugin: 'android-library'

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

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

Eta Checkmarx-en araua:

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

Ikuspegi hau nahiko unibertsala eta erabilgarria izan daiteke Android aplikazioetarako ez ezik, emaitza bat fitxategi jakin bati dagokion ala ez zehaztu behar duzun beste kasu batzuetan ere.

Helburua: Gehitu hirugarrenen liburutegi baterako laguntza, sintaxia guztiz onartzen ez bada

irtenbidea: Kodea idazteko prozesuan erabiltzen diren hainbat esparru-kopurua zerrendetatik kanpo geratzen da. Jakina, Checkmarx-ek ez daki beti haien existentziaz, eta gure zeregina metodo batzuk berariaz esparru horri dagozkiola ulertzen irakastea da. Batzuetan, hori zaildu egiten da esparruek oso ohikoak diren funtzio-izenak erabiltzen dituztelako eta ezinezkoa da anbiguotasunik gabe zehaztea dei jakin batek liburutegi zehatz batekin duen erlazioa.

Zailtasuna da horrelako liburutegien sintaxia ez dela beti behar bezala ezagutzen eta esperimentatu egin behar duzula positibo faltsu ugari ez lortzeko. Eskaneatzeko zehaztasuna hobetzeko eta arazoa konpontzeko hainbat aukera daude:

  • Lehenengo aukera, ziur badakigu liburutegia proiektu zehatz batean erabiltzen dela eta araua talde mailan aplika dezakeela. Baina taldeak beste ikuspegi bat hartzea erabakitzen badu edo funtzioen izenak gainjartzen diren hainbat liburutegi erabiltzen baditu, positibo faltsu askoren argazki ez oso atsegina lor dezakegu.

  • Bigarren aukera liburutegia argi eta garbi inportatuta dagoen fitxategiak bilatzea da. Planteamendu honekin, ziur egon gaitezke behar dugun liburutegia fitxategi honetan zehazki erabiltzen dela.

  • Eta hirugarren aukera goiko bi ikuspegiak batera erabiltzea da.

Adibide gisa, ikus dezagun zirkulu estuetan ezaguna den liburutegi bat beltza Scala programazio lengoaiarako, hots, funtzionaltasuna Balio literalak elkartzea. Oro har, SQL kontsulta bati parametroak pasatzeko, operadorea erabili behar duzu $, datuak aurrez prestatutako SQL kontsulta batean ordezkatzen dituena. Hau da, hain zuzen ere, Prepared Statement-en analogo zuzena da Javan. Baina, SQL kontsulta bat dinamikoki eraiki behar baduzu, adibidez, taulen izenak pasa behar badituzu, operadorea erabil dezakezu #$, eta horrek zuzenean ordezkatuko ditu datuak kontsultan (ia kateen kateamendua bezala).

Adibidea kodea:

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

Checkmarx-ek oraindik ez daki nola detektatu Splicing Literal Values ​​eta operadoreak saltatzen dituen #$, beraz, saiatu gaitezen balizko SQL injekzioak identifikatzen eta kodean leku egokiak nabarmentzen irakasten:

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

Helburua: Bilatu erabilitako funtzio zaurgarriak Iturburu Irekiko liburutegietan

irtenbidea: Enpresa askok iturburu irekiko monitorizazio tresnak (OSA praktika) erabiltzen dituzte garatutako aplikazioetan liburutegien bertsio zaurgarrien erabilera detektatzeko. Batzuetan, ezin da horrelako liburutegi bat bertsio seguru batera eguneratu. Kasu batzuetan muga funtzionalak daude, beste batzuetan ez dago bertsio segururik. Kasu honetan, SAST eta OSA praktiken konbinazioak lagunduko du ahultasuna ustiatzen duten funtzioak kodean erabiltzen ez direla zehazten.

Baina batzuetan, batez ere JavaScript kontuan hartuta, baliteke hori ez izatea zeregin guztiz hutsala. Jarraian irtenbide bat dago, agian ez da ideala, baina hala ere funtzionatzen duena, osagaiko ahultasunen adibidea erabiliz lodash metodoetan template и *set.

JS fitxategi batean zaurgarria izan daitekeen kode probaren adibideak:

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

Eta zuzenean html-n konektatzean:

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

Gure metodo zaurgarri guztiak bilatzen ari gara, ahultasunetan zerrendatuta daudenak:

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

Helburua: Aplikazioan txertatutako ziurtagiriak bilatzea

irtenbidea: Ez da arraroa aplikazioek, batez ere mugikorrak, ziurtagiriak edo gakoak erabiltzea hainbat zerbitzarietara sartzeko edo SSL-Pinning egiaztatzeko. Segurtasun ikuspegitik, horrelako gauzak kodean gordetzea ez da praktikarik onena. Saia gaitezen biltegian antzeko fitxategiak bilatuko dituen arau bat idazten:

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

Helburua: Aplikazioan arriskuan dauden tokenak aurkitzea

irtenbidea: Askotan beharrezkoa da konprometitutako tokenak edo kodean dagoen beste informazio garrantzitsua baliogabetzea. Noski, iturri-kodearen barruan gordetzea ez da ideia ona, baina egoerak aldatu egiten dira. CxQL kontsultei esker, horrelako gauzak aurkitzea nahiko erraza da:

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

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

Ondorioa

Espero dut artikulu hau Checkmarx tresna ezagutzen hasten direnentzat erabilgarria izatea. Beharbada, denbora luzez beren arauak idazten ari direnek ere zerbait erabilgarria aurkituko dute gida honetan.

Zoritxarrez, gaur egun Checkmarx-en arauen garapenean ideia berriak atera daitezkeen baliabiderik falta da. Horregatik sortu dugu Github-en biltegia, non gure lana argitaratuko dugu, CxQL erabiltzen duten guztiek bertan zerbait erabilgarria aurki dezaten, eta, gainera, bere lana komunitatearekin partekatzeko aukera izan dezan. Biltegia edukia betetzeko eta egituratzeko prozesuan dago, beraz, laguntzaileak ongi etorriak dira!

Eskerrik asko zure arreta!

Iturria: www.habr.com

Gehitu iruzkin berria