Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaður

Hæ Habr!

Í starfi okkar er fyrirtækið okkar mjög oft að fást við ýmis tól fyrir static code analysis (SAST). Upp úr kassanum vinna þeir allir að meðaltali. Það fer auðvitað allt eftir verkefninu og þeirri tækni sem notuð er í því, svo og hversu vel þessi tækni falli undir greiningarreglur. Að mínu mati er eitt mikilvægasta viðmiðið þegar þú velur SAST tól geta til að sérsníða það að sérstökum forritum þínum, nefnilega að skrifa og breyta greiningarreglum eða, eins og þær eru oftar kallaðar, sérsniðnar fyrirspurnir.

Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaður

Við notum oftast Checkmarx - mjög áhugaverðan og öflugan kóðagreiningartæki. Í þessari grein mun ég segja frá reynslu minni af því að skrifa greiningarreglur fyrir það.

efnisyfirlit

Færslu

Til að byrja með vil ég mæla með einni af fáum greinum á rússnesku um eiginleika þess að skrifa fyrirspurnir fyrir Checkmarx. Það var gefið út á Habré í lok árs 2019 undir heitinu: "Halló, Checkmarx!" Hvernig á að skrifa Checkmarx SAST fyrirspurn og finna flotta veikleika.

Það skoðar ítarlega hvernig á að skrifa fyrstu fyrirspurnirnar í CxQL (Checkmarx Query Language) fyrir einhverja prófunarforrit og sýnir grundvallarreglur um hvernig greiningarreglur virka.

Ég ætla ekki að endurtaka það sem þar er lýst, þó nokkur gatnamót verði enn til staðar. Í grein minni mun ég reyna að setja saman eins konar „safn af uppskriftum“, lista yfir lausnir á sérstökum vandamálum sem ég lenti í í starfi mínu með Checkmarx. Ég þurfti að rífast yfir mörgum af þessum vandamálum. Stundum voru ekki nægar upplýsingar í skjölunum og stundum var jafnvel erfitt að skilja hvernig ætti að gera það sem til þurfti. Ég vona að reynsla mín og svefnlausar nætur verði ekki til einskis og þetta „safn af sérsniðnum fyrirspurnum“ mun spara þér nokkrar klukkustundir eða nokkrar taugafrumur. Svo, við skulum byrja!

Almennar upplýsingar um reglurnar

Fyrst skulum við skoða nokkur grunnhugtök og ferlið við að vinna með reglurnar, til að fá betri skilning á því sem mun gerast næst. Og líka vegna þess að skjölin segja ekkert um þetta eða eru mjög dreifð í uppbyggingunni, sem er ekki mjög þægilegt.

  1. Reglurnar eru notaðar við skönnun, allt eftir forstillingunni sem var valin í upphafi (sett af virkum reglum). Þú getur búið til ótakmarkaðan fjölda forstillinga og nákvæmlega hvernig á að skipuleggja þær fer eftir sérstöðu ferlisins. Þú getur flokkað þau eftir tungumálum eða valið forstillingar fyrir hvert verkefni. Fjöldi virkra reglna hefur áhrif á hraða og nákvæmni skönnunar.

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurSetja upp forstillingu í Checkmarx viðmótinu

  2. Reglunum er breytt í sérstöku tóli sem kallast CxAuditor. Þetta er skrifborðsforrit sem tengist netþjóni sem keyrir Checkmarx. Þetta tól hefur tvær aðgerðir: að breyta reglum og greina niðurstöður skönnunar sem þegar hefur verið framkvæmd.

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurCxAudit tengi

  3. Reglum í Checkmarx er skipt eftir tungumálum, það er að segja að hvert tungumál hefur sitt eigið mengi fyrirspurna. Það eru líka nokkrar almennar reglur sem gilda óháð tungumáli, þetta eru svokallaðar grunnspurningar. Að mestu leyti fela grunnfyrirspurnir í sér að leita að upplýsingum sem aðrar reglur nota.

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurAð skipta reglum eftir tungumáli

  4. Reglur eru „Rekstrarhæfar“ og „Ekkiframkvæmanlegar“ (framkvæmt og ekki framkvæmt). Ekki alveg rétt nafn, að mínu mati, en það er það sem það er. Niðurstaðan er sú að niðurstaðan af því að keyra „Executable“ reglur mun birtast í skannaniðurstöðum í notendaviðmótinu og „Non-Executable“ reglur eru aðeins nauðsynlegar til að nota niðurstöður þeirra í öðrum beiðnum (í rauninni eru þær bara aðgerð ).

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurÁkvörðun reglugerðarinnar þegar búið er til

  5. Þú getur búið til nýjar reglur eða bætt við/endurskrifað þær sem fyrir eru. Til þess að endurskrifa reglu þarftu að finna hana í trénu, hægrismella og velja „Hanka“ í fellivalmyndinni. Það er mikilvægt að muna hér að nýju reglurnar eru upphaflega ekki með í forstillingunum og eru ekki virkar. Til að byrja að nota þau þarftu að virkja þau í „Preset Manager“ valmyndinni á tækinu. Endurskrifaðar reglur halda stillingum sínum, það er að segja ef reglan var virk verður hún áfram þannig og verður beitt strax.

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurDæmi um nýja reglu í viðmóti Forstillingarstjóra

  6. Við framkvæmd er „tré“ af beiðnum byggt, sem fer eftir hverju. Reglurnar sem safna upplýsingum eru framkvæmdar fyrst og þeir sem nota þær í öðru lagi. Framkvæmdarniðurstaðan er í skyndiminni, þannig að ef hægt er að nota niðurstöður núverandi reglu, þá er betra að gera það, þetta mun draga úr skönnunartímanum.

  7. Hægt er að beita reglum á mismunandi stigum:

  • Fyrir allt kerfið - verður notað til að skanna hvaða verkefni sem er

  • Á liðsstigi (teymi) - verður aðeins notað til að skanna verkefni í völdum teymi.

  • Á verkefnastigi - Verður beitt í tilteknu verkefni

    Hvernig á að skrifa reglur fyrir Checkmarx án þess að verða brjálaðurÁkvarða á hvaða stigi reglunni verður beitt

"Orðabók" fyrir byrjendur

Og ég mun byrja á nokkrum hlutum sem olli mér spurningum, og ég mun einnig sýna ýmsar aðferðir sem munu einfalda lífið verulega.

Aðgerðir með listum

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

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

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

Allir fundnir hlutir

Innan skannaða tungumálsins geturðu fengið lista yfir algerlega alla þætti sem Checkmarx hefur auðkennt (strengi, aðgerðir, flokka, aðferðir osfrv.). Þetta er rými hluta sem hægt er að nálgast í gegnum All. Það er að segja að leita að hlut með ákveðnu nafni searchMe, þú getur td leitað eftir nafni í öllum fundnum hlutum:

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

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

En ef þú þarft að leita á öðru tungumáli sem af einhverjum ástæðum var ekki innifalið í skönnuninni (til dæmis gróft í Android verkefni), geturðu stækkað hlutarýmið okkar með breytu:

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

Aðgerðir fyrir flæðisgreiningu

Þessar aðgerðir eru notaðar í mörgum reglum og hér er smá svindlblað um hvað þeir þýða:

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

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

Að sækja nafn/slóð skráar

Það eru nokkrir eiginleikar sem hægt er að fá úr niðurstöðum fyrirspurnar (heiti skráarinnar sem færslan fannst í, strengur o.s.frv.), en skjölin segja ekki til um hvernig eigi að afla þeirra og nota. Svo til að gera þetta þarftu að fá aðgang að LinePragma eigninni og hlutirnir sem við þurfum verða staðsettir inni í henni:

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

Það er rétt að hafa það í huga FileName inniheldur í raun slóðina að skránni, þar sem við notuðum aðferðina GetFirstGraph.

Niðurstaða framkvæmdar

Það er sérstök breyta inni í CxQL result, sem skilar niðurstöðunni af framkvæmd skriflegu reglunnar þinnar. Það er frumstillt strax og þú getur skrifað milliniðurstöður inn í það, breytt og betrumbætt þær þegar þú vinnur. En ef það er ekkert úthlutun á þessa breytu eða fall inni í reglunni return— framkvæmdarniðurstaðan verður alltaf núll.

Eftirfarandi fyrirspurn mun ekki skila neinu til okkar vegna framkvæmdar og verður alltaf tóm:

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

En eftir að hafa úthlutað framkvæmdarniðurstöðunni á töfrabreytu niðurstöðuna munum við sjá hverju þetta símtal skilar okkur:

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

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

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

Að nota niðurstöður annarra reglna

Reglur í Checkmarx má kalla hliðstæðar föllum í venjulegu forritunarmáli. Þegar þú skrifar reglu gætirðu vel notað niðurstöður annarra fyrirspurna. Til dæmis, það er engin þörf á að leita að öllum aðferðaköllum í kóðanum í hvert skipti, hringdu bara í þá reglu sem þú vilt:

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

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

Þessi aðferð gerir þér kleift að stytta kóðann og draga verulega úr framkvæmdartíma reglunnar.

Vandamál

Skógarhögg

Þegar þú vinnur með tólið er stundum ekki hægt að skrifa viðeigandi fyrirspurn strax og þú verður að gera tilraunir og prófa mismunandi valkosti. Í slíku tilviki veitir tólið skógarhögg, sem er kallað sem hér segir:

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

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

En það er þess virði að muna að þessi aðferð tekur aðeins við sem inntak strengur, þannig að það verður ekki hægt að birta heildarlista yfir fundna þætti sem afleiðing af fyrstu aðgerðinni. Annar valmöguleikinn, sem er notaður við villuleit, er að úthluta töfrabreytu af og til result niðurstöðu fyrirspurnarinnar og sjáðu hvað gerist. Þessi nálgun er ekki mjög þægileg; þú þarft að vera viss um að það séu engar hnekkingar eða aðgerðir með þessu í kóðanum eftir result eða einfaldlega skrifaðu athugasemd við kóðann hér að neðan. Eða þú getur, eins og ég, gleymt að fjarlægja nokkur slík símtöl úr tilbúinni reglu og velt því fyrir þér hvers vegna ekkert virkar.

Þægilegri leið er að kalla aðferðina return með nauðsynlegri færibreytu. Í þessu tilviki mun framkvæmd reglunnar ljúka og við munum geta séð hvað gerðist vegna þess sem við skrifuðum:

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

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

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

Vandamál við innskráningu

Það eru aðstæður þar sem þú getur ekki fengið aðgang að CxAudit tólinu (sem er notað til að skrifa reglur). Það geta verið margar ástæður fyrir þessu, þar á meðal hrun, skyndilegar Windows uppfærslur, BSOD og aðrar ófyrirséðar aðstæður sem eru óviðráðanlegar. Í þessu tilviki er stundum ólokið lota í gagnagrunninum sem kemur í veg fyrir að þú skráir þig inn aftur. Til að laga það þarftu að keyra nokkrar fyrirspurnir:

Fyrir Checkmarx fyrir 8.6:

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

Fyrir Checkmarx eftir 8.6:

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

Ritunarreglur

Nú komum við að áhugaverðasta hlutanum. Þegar þú byrjar að skrifa reglur í CxQL er það sem þig skortir oft ekki svo mikið skjöl heldur nokkur lifandi dæmi um að leysa ákveðin vandamál og lýsa ferlinu um hvernig fyrirspurnir virka almennt.

Ég mun reyna að gera lífið aðeins auðveldara fyrir þá sem eru að byrja að kafa ofan í fyrirspurnarmálið og gefa nokkur dæmi um að nota sérsniðnar fyrirspurnir til að leysa ákveðin vandamál. Sum þeirra eru frekar almenn og hægt að nota í fyrirtækinu þínu nánast án breytinga, önnur eru sértækari, en einnig er hægt að nota þau með því að breyta kóðanum til að henta sértækum forritum þínum.

Svo, hér eru vandamálin sem við lentum í oftast:

Verkefni: Það eru nokkur flæði í niðurstöðum framkvæmdar reglunnar og eitt þeirra er hreiður annars, þú verður að yfirgefa eitt þeirra.

lausn: Reyndar, stundum sýnir Checkmarx nokkur gagnaflæði sem geta skarast og verið stytt útgáfa af öðrum. Það er sérstök aðferð fyrir slík mál Minnka flæði. Það fer eftir breytu, það mun velja stysta eða lengsta flæðið:

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

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

Verkefni: Stækkaðu listann yfir viðkvæm gögn sem tólið bregst við

lausn: Checkmarx hefur grunnreglur, niðurstöður þeirra eru notaðar af mörgum öðrum fyrirspurnum. Með því að bæta við sumar þessara reglna með gögnum sem eru sértæk fyrir forritið þitt geturðu strax bætt skannaniðurstöður þínar. Hér að neðan er dæmi um reglu til að koma þér af stað:

Listi yfir almennan_persónuverndarbrot

Við skulum bæta við nokkrum breytum sem eru notaðar í forritinu okkar til að geyma viðkvæmar upplýsingar:

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

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

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

Verkefni: Stækkaðu listann yfir breytur með lykilorðum

lausn: Ég myndi mæla með því að fylgjast strax með grunnreglunni um að skilgreina lykilorð í kóða og bæta við það lista yfir breytuheiti sem eru almennt notuð í fyrirtækinu þínu.

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

Verkefni: Bættu við notuðum ramma sem eru ekki studdir af Checkmarx

lausn: Öllum fyrirspurnum í Checkmarx er skipt eftir tungumálum, þannig að þú þarft að bæta við reglum fyrir hvert tungumál. Hér að neðan eru nokkur dæmi um slíkar reglur.

Ef notuð eru bókasöfn sem bæta við eða koma í stað staðlaðrar virkni er auðvelt að bæta þeim við grunnregluna. Þá munu allir sem nota það strax kynnast nýju kynningunum. Sem dæmi eru bókasöfn fyrir innskráningu í Android Timber og Loggi. Í grunnpakkanum eru engar reglur til að bera kennsl á símtöl sem ekki eru kerfisbundin, þannig að ef lykilorð eða lotuauðkenni kemst inn í notendaskrána munum við ekki vita af því. Við skulum reyna að bæta skilgreiningum á slíkum aðferðum við Checkmarx reglurnar.

Dæmi um prófunarkóða sem notar Timber bókasafnið til að skrá:

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

Og hér er dæmi um beiðni um Checkmarx, sem gerir þér kleift að bæta við skilgreiningu á að kalla Timber-aðferðir sem útgöngustað fyrir gögn úr forritinu:

FindAndroidOutputs

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

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

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

Og þú getur líka bætt við nágrannaregluna, en þessi tengist beint innskráningu á Android:

FindAndroidLog_Outputs

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

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

Einnig, ef Android forrit nota Vinnustjóri fyrir ósamstillta vinnu er gott að upplýsa Checkmarx um þetta til viðbótar með því að bæta við aðferð til að fá gögn úr verkefninu getInputData:

FindAndroidRead

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

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

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

Verkefni: Leita að viðkvæmum gögnum í plist fyrir iOS verkefni

lausn: iOS notar oft sérstakar skrár með .plist viðbótinni til að geyma ýmsar breytur og gildi. Ekki er mælt með því að geyma lykilorð, tákn, lykla og önnur viðkvæm gögn í þessum skrám, þar sem hægt er að vinna þau úr tækinu án vandræða.

Plist skrár hafa eiginleika sem eru ekki augljósir með berum augum, en eru mikilvægir fyrir Checkmarx. Við skulum skrifa reglu sem mun leita að gögnum sem við þurfum og segja okkur hvort lykilorð eða tákn séu nefnd einhvers staðar.

Dæmi um slíka skrá, sem inniheldur tákn fyrir samskipti við bakendaþjónustuna:

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

Og regla fyrir Checkmarx, sem hefur nokkra blæbrigði sem ætti að hafa í huga þegar þú skrifar:

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

Verkefni: Að finna upplýsingar í XML

lausn: Checkmarx hefur mjög þægilegar aðgerðir til að vinna með XML og leita að gildum, merkjum, eiginleikum og fleiru. En því miður var villa í skjölunum vegna þess að ekkert eitt dæmi virkar. Þrátt fyrir þá staðreynd að þessum galla hafi verið eytt í nýjustu útgáfu skjala, vertu varkár ef þú notar fyrri útgáfur af skjölum.

Hér er rangt dæmi úr skjölunum:

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

Sem afleiðing af framkvæmd tilrauninni munum við fá villu sem All það er engin slík aðferð... Og þetta er satt, þar sem það er sérstakt, aðskilið hlutarými til að nota aðgerðir til að vinna með XML - cxXPath. Svona lítur rétta fyrirspurnin út til að finna stillingu í Android sem leyfir notkun HTTP umferðar:

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

Við skulum skoða það aðeins nánar, þar sem setningafræði fyrir allar aðgerðir er svipuð, eftir að þú hefur fundið út eina, þá þarftu bara að velja þá sem þú þarft. Svo, í röð í samræmi við breytur:

  • "*.xml"— gríma af skrám sem á að leita að

  • 8 — auðkenni tungumálsins sem reglunni er beitt fyrir

  • "cleartextTrafficPermitted"— eigindarheiti í xml

  • "true" — gildi þessa eiginleika

  • false — notkun reglulegrar tjáningar við leit

  • true — þýðir að leitin verður gerð með því að hunsa há- og hástafi, þ.e

Sem dæmi notuðum við reglu sem auðkennir rangar, frá öryggissjónarmiði, nettengingarstillingar í Android sem leyfa samskipti við netþjóninn í gegnum HTTP samskiptareglur. Dæmi um stillingu sem inniheldur eigind cleartextTrafficPermitted með merkingu 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>

Verkefni: Takmarkaðu niðurstöður með skráarheiti/slóð

lausn: Í einu af stóru verkefnunum sem tengjast þróun farsímaforrits fyrir Android, fundum við rangar jákvæðar hliðar reglunnar sem ákvarðar óskýrunarstillinguna. Staðreyndin er sú að reglan úr kassanum leitar í skránni build.gradle stilling sem ber ábyrgð á því að beita skyggingarreglum fyrir útgáfu útgáfu forritsins.

En í stórum verkefnum eru stundum barnaskrár build.gradle, sem vísa til þeirra bókasöfna sem verkefnið tekur til. Sérstaðan er sú að jafnvel þótt þessar skrár gefi ekki til kynna að þörf sé á þoku, þá verður stillingum yfirsamsetningarskráarinnar beitt við söfnun.

Þannig er verkefnið að skera af kveikjum í barnaskrám sem tilheyra bókasöfnum. Hægt er að bera kennsl á þá með tilvist línunnar apply 'com.android.library'.

Dæmi um kóða úr skrá build.gradle, sem ákvarðar þörfina fyrir þoku:

apply plugin: 'com.android.application'

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

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

dependencies {
  ...
}

Dæmi um skrá build.gradle fyrir bókasafn sem er innifalið í verkefninu sem hefur ekki þessa stillingu:

apply plugin: 'android-library'

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

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

Og reglan fyrir 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);
		}
	}
}

Þessi aðferð getur verið nokkuð alhliða og gagnleg, ekki aðeins fyrir Android forrit, heldur einnig fyrir önnur tilvik þegar þú þarft að ákvarða hvort niðurstaða tilheyri tiltekinni skrá.

Verkefni: Bættu við stuðningi við þriðja aðila bókasafn ef setningafræði er ekki að fullu studd

lausn: Fjöldi ýmissa ramma sem eru notaðir við að skrifa kóða er einfaldlega ekki á töflunni. Checkmarx veit auðvitað ekki alltaf um tilvist þeirra og verkefni okkar er að kenna honum að skilja að ákveðnar aðferðir tilheyra sérstaklega þessum ramma. Stundum er þetta flókið af því að rammar nota fallheiti sem eru mjög algeng og það er ómögulegt að ákvarða ótvírætt tengsl tiltekins símtals við tiltekið bókasafn.

Erfiðleikarnir eru þeir að setningafræði slíkra bókasöfna er ekki alltaf viðurkennd á réttan hátt og þú verður að gera tilraunir til að forðast að fá mikinn fjölda rangra jákvæða. Það eru nokkrir möguleikar til að bæta skönnunarnákvæmni og leysa vandamálið:

  • Fyrsti kosturinn, við vitum fyrir víst að bókasafnið er notað í tilteknu verkefni og getur beitt reglunni á teymisstigi. En ef teymið ákveður að taka aðra nálgun eða notar nokkur bókasöfn þar sem aðgerðaheiti skarast, getum við fengið ekki mjög skemmtilega mynd af fjölmörgum fölskum jákvæðum

  • Annar kosturinn er að leita að skrám þar sem bókasafnið er greinilega flutt inn. Með þessari nálgun getum við verið viss um að bókasafnið sem við þurfum sé nákvæmlega notað í þessari skrá.

  • Og þriðji kosturinn er að nota tvær ofangreindar aðferðir saman.

Sem dæmi skulum við líta á bókasafn sem er vel þekkt í þröngum hringjum klókur fyrir Scala forritunarmálið, nefnilega virknina Skera bókstafsgildi. Almennt, til að senda færibreytur í SQL fyrirspurn, verður þú að nota rekstraraðilann $, sem kemur í stað gagna í fyrirframgerða SQL fyrirspurn. Það er í raun og veru, það er bein hliðstæða við tilbúna yfirlýsingu á Java. En ef þú þarft að smíða SQL fyrirspurn á kraftmikinn hátt, til dæmis, ef þú þarft að senda töflunöfn, geturðu notað rekstraraðilann #$, sem kemur beint í staðinn fyrir gögnin í fyrirspurnina (næstum eins og strengjasamtenging).

Dæmi um kóða:

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

Checkmarx veit ekki enn hvernig á að greina notkun splicing Literal Values ​​​​og sleppir rekstraraðilum #$, svo við skulum reyna að kenna því að bera kennsl á hugsanlegar SQL innspýtingar og auðkenna rétta staði í kóðanum:

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

Verkefni: Leitaðu að notuðum viðkvæmum aðgerðum í Open-Source bókasöfnum

lausn: Mörg fyrirtæki nota Open-Source vöktunarverkfæri (OSA praxis) til að greina notkun á viðkvæmum útgáfum af bókasöfnum í þróuðum forritum. Stundum er ekki hægt að uppfæra slíkt bókasafn í örugga útgáfu. Í sumum tilfellum eru virkni takmarkanir, í öðrum er engin örugg útgáfa yfirleitt. Í þessu tilviki mun blanda af SAST og OSA starfsháttum hjálpa til við að ákvarða að aðgerðirnar sem leiða til hagnýtingar á varnarleysinu eru ekki notaðar í kóðanum.

En stundum, sérstaklega þegar JavaScript er íhugað, er þetta kannski ekki alveg léttvægt verkefni. Hér að neðan er lausn, kannski ekki tilvalin, en virkar engu að síður, með því að nota dæmi um veikleika í íhlutnum lodash í aðferðum template и *set.

Dæmi um að prófa mögulega viðkvæman kóða í JS skrá:

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

Og þegar þú tengir beint í html:

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

Við erum að leita að öllum viðkvæmu aðferðunum okkar, sem eru skráðar í varnarleysi:

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

Verkefni: Leitar að vottorðum sem eru felld inn í forritið

lausn: Það er ekki óalgengt að forrit, sérstaklega farsímar, noti vottorð eða lykla til að fá aðgang að ýmsum netþjónum eða staðfesta SSL-pinning. Frá öryggissjónarmiði er ekki besti aðferðin að geyma slíka hluti í kóða. Við skulum reyna að skrifa reglu sem mun leita að svipuðum skrám í geymslunni:

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

Verkefni: Að finna málamiðlanir í forritinu

lausn: Það er oft nauðsynlegt að afturkalla málamiðlunarmerki eða aðrar mikilvægar upplýsingar sem eru til staðar í kóðanum. Auðvitað er ekki góð hugmynd að geyma þau inni í frumkóðann, en aðstæður eru mismunandi. Þökk sé CxQL fyrirspurnum er frekar auðvelt að finna hluti eins og þetta:

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

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

Ályktun

Ég vona að þessi grein nýtist þeim sem eru að byrja að kynnast Checkmarx tólinu. Kannski munu þeir sem hafa skrifað sínar eigin reglur í langan tíma líka finna eitthvað gagnlegt í þessari handbók.

Því miður skortir nú úrræði þar sem hægt er að afla nýrra hugmynda við þróun reglna fyrir Checkmarx. Þess vegna sköpuðum við geymsla á Github, þar sem við munum birta verk okkar svo að allir sem nota CxQL geti fundið eitthvað gagnlegt í því, og einnig fengið tækifæri til að deila vinnu sinni með samfélaginu. Geymslan er að fylla og skipuleggja efni, svo þátttakendur eru velkomnir!

Svara með tilvísun!

Heimild: www.habr.com

Bæta við athugasemd