Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gila

Hai Habr!

Dalam kerja kami, syarikat kami sering berurusan dengan pelbagai alat analisis kod statik (SAST). Di luar kotak mereka semua bekerja rata-rata. Sudah tentu, semuanya bergantung pada projek dan teknologi yang digunakan di dalamnya, serta seberapa baik teknologi ini dilindungi oleh peraturan analisis. Pada pendapat saya, salah satu kriteria yang paling penting apabila memilih alat SAST ialah keupayaan untuk menyesuaikannya mengikut spesifikasi aplikasi anda, iaitu, menulis dan menukar peraturan analisis atau, seperti yang lebih kerap dipanggil, Pertanyaan Tersuai.

Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gila

Kami paling kerap menggunakan Checkmarx - penganalisis kod yang sangat menarik dan berkuasa. Dalam artikel ini saya akan bercakap tentang pengalaman saya menulis peraturan analisis untuknya.

jadual kandungan

Entry

Sebagai permulaan, saya ingin mengesyorkan satu daripada beberapa artikel dalam bahasa Rusia tentang ciri menulis pertanyaan untuk Checkmarx. Ia diterbitkan di Habré pada akhir 2019 di bawah tajuk: "Hello, Checkmarx!" Cara menulis pertanyaan Checkmarx SAST dan mencari kelemahan yang hebat.

Ia meneliti secara terperinci cara menulis pertanyaan pertama dalam CxQL (Checkmarx Query Language) untuk beberapa aplikasi ujian dan menunjukkan prinsip asas bagaimana peraturan analisis berfungsi.

Saya tidak akan mengulangi apa yang diterangkan di dalamnya, walaupun beberapa persimpangan masih akan ada. Dalam artikel saya, saya akan cuba menyusun sejenis "koleksi resipi", senarai penyelesaian kepada masalah khusus yang saya hadapi semasa bekerja dengan Checkmarx. Saya terpaksa memerah otak saya tentang banyak masalah ini. Kadangkala tidak terdapat maklumat yang mencukupi dalam dokumentasi, malah kadangkala sukar untuk memahami cara melakukan apa yang diperlukan. Saya harap pengalaman saya dan malam tanpa tidur tidak akan sia-sia, dan "koleksi resipi Pertanyaan Tersuai" ini akan menjimatkan beberapa jam atau beberapa sel saraf. Jadi, mari kita mulakan!

Maklumat am mengenai peraturan

Mula-mula, mari kita lihat beberapa konsep asas dan proses bekerja dengan peraturan, untuk pemahaman yang lebih baik tentang perkara yang akan berlaku seterusnya. Dan juga kerana dokumentasi tidak mengatakan apa-apa tentang ini atau sangat tersebar dalam struktur, yang tidak begitu mudah.

  1. Peraturan digunakan semasa pengimbasan bergantung pada pratetap yang dipilih pada permulaan (satu set peraturan aktif). Anda boleh mencipta bilangan pratetap tanpa had, dan cara menyusunnya bergantung pada spesifik proses anda. Anda boleh mengumpulkannya mengikut bahasa atau memilih pratetap untuk setiap projek. Bilangan peraturan aktif mempengaruhi kelajuan dan ketepatan pengimbasan.

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaMenyediakan Pratetap dalam antara muka Checkmarx

  2. Peraturan disunting dalam alat khas yang dipanggil CxAuditor. Ini ialah aplikasi desktop yang bersambung ke pelayan yang menjalankan Checkmarx. Alat ini mempunyai dua mod operasi: peraturan mengedit dan menganalisis hasil imbasan yang telah dilakukan.

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaAntara muka CxAudit

  3. Peraturan dalam Checkmarx dibahagikan mengikut bahasa, iaitu setiap bahasa mempunyai set pertanyaannya sendiri. Terdapat juga beberapa peraturan am yang digunakan tanpa mengira bahasa, ini adalah apa yang dipanggil pertanyaan asas. Untuk sebahagian besar, pertanyaan asas melibatkan pencarian maklumat yang digunakan oleh peraturan lain.

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaMembahagikan peraturan mengikut bahasa

  4. Peraturan adalah "Boleh Laksana" dan "Tidak Boleh Laksana" (Dilaksanakan dan Tidak Dilaksanakan). Bukan nama yang betul, pada pendapat saya, tetapi itulah namanya. Intinya ialah hasil pelaksanaan peraturan "Boleh Laksana" akan dipaparkan dalam hasil imbasan dalam UI, dan peraturan "Tidak Boleh Laksana" hanya diperlukan untuk menggunakan keputusannya dalam permintaan lain (pada dasarnya, hanya fungsi).

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaMenentukan jenis peraturan semasa membuat

  5. Anda boleh membuat peraturan baharu atau menambah/menulis semula peraturan sedia ada. Untuk menulis semula peraturan, anda perlu mencarinya dalam pokok, klik kanan dan pilih "Timpa" daripada menu lungsur. Adalah penting untuk diingat di sini bahawa peraturan baharu pada mulanya tidak disertakan dalam pratetap dan tidak aktif. Untuk mula menggunakannya, anda perlu mengaktifkannya dalam menu "Pengurus Pratetap" dalam instrumen. Peraturan yang ditulis semula mengekalkan tetapannya, iaitu, jika peraturan itu aktif, ia akan kekal begitu dan akan digunakan serta-merta.

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaContoh peraturan baharu dalam antara muka Pengurus Pratetap

  6. Semasa pelaksanaan, "pokok" permintaan dibina, yang bergantung pada apa. Peraturan yang mengumpul maklumat dilaksanakan terlebih dahulu, dan mereka yang menggunakannya kedua. Hasil pelaksanaan dicache, jadi jika boleh menggunakan keputusan peraturan sedia ada, lebih baik berbuat demikian, ini akan mengurangkan masa pengimbasan.

  7. Peraturan boleh digunakan pada tahap yang berbeza:

  • Untuk keseluruhan sistem - akan digunakan untuk sebarang pengimbasan mana-mana projek

  • Di peringkat pasukan (Pasukan) - hanya akan digunakan untuk mengimbas projek dalam pasukan yang dipilih.

  • Di peringkat projek - Akan digunakan dalam projek tertentu

    Bagaimana untuk menulis peraturan untuk Checkmarx tanpa menjadi gilaMenentukan tahap di mana peraturan akan digunakan

"Kamus" untuk pemula

Dan saya akan mulakan dengan beberapa perkara yang menimbulkan persoalan kepada saya, dan saya juga akan menunjukkan beberapa teknik yang akan memudahkan kehidupan dengan ketara.

Operasi dengan senarai

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

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

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

Semua item ditemui

Dalam bahasa yang diimbas, anda boleh mendapatkan senarai semua elemen yang telah dikenal pasti oleh Checkmarx (rentetan, fungsi, kelas, kaedah, dll.). Ini adalah beberapa ruang objek yang boleh diakses melalui All. Iaitu, untuk mencari objek dengan nama tertentu searchMe, anda boleh mencari, contohnya, mengikut nama merentas semua objek yang ditemui:

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

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

Tetapi, jika anda perlu mencari dalam bahasa lain yang atas sebab tertentu tidak disertakan dalam imbasan (contohnya, groovy dalam projek Android), anda boleh mengembangkan ruang objek kami melalui pembolehubah:

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

Fungsi untuk analisis Aliran

Fungsi-fungsi ini digunakan dalam banyak peraturan dan berikut ialah helaian penipuan kecil tentang maksudnya:

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

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

Mendapatkan nama/laluan fail

Terdapat beberapa atribut yang boleh diperoleh daripada hasil pertanyaan (nama fail di mana entri ditemui, rentetan, dll.), tetapi dokumentasi tidak menyatakan cara mendapatkan dan menggunakannya. Jadi, untuk melakukan ini, anda perlu mengakses harta LinePragma dan objek yang kami perlukan akan ditempatkan di dalamnya:

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

Perlu diingat bahawa FileName sebenarnya mengandungi laluan ke fail, kerana kami menggunakan kaedah tersebut GetFirstGraph.

Hasil pelaksanaan

Terdapat pembolehubah khas di dalam CxQL result, yang mengembalikan hasil pelaksanaan peraturan bertulis anda. Ia dimulakan serta-merta dan anda boleh menulis hasil perantaraan ke dalamnya, mengubah dan memperhalusinya semasa anda bekerja. Tetapi, jika tiada penetapan kepada pembolehubah atau fungsi ini di dalam peraturan return— hasil pelaksanaan akan sentiasa sifar.

Pertanyaan berikut tidak akan mengembalikan apa-apa kepada kami hasil daripada pelaksanaan dan akan sentiasa kosong:

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

Tetapi, setelah memberikan hasil pelaksanaan kepada hasil pembolehubah ajaib, kami akan melihat apa yang dikembalikan oleh panggilan ini kepada kami:

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

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

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

Menggunakan keputusan peraturan lain

Peraturan dalam Checkmarx boleh dipanggil analog dengan fungsi dalam bahasa pengaturcaraan biasa. Semasa menulis peraturan, anda boleh menggunakan hasil pertanyaan lain. Sebagai contoh, tidak perlu mencari semua panggilan kaedah dalam kod setiap kali, cuma panggil peraturan yang dikehendaki:

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

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

Pendekatan ini membolehkan anda memendekkan kod dan mengurangkan masa pelaksanaan peraturan dengan ketara.

Penyelesaian masalah

Pembalakan

Apabila bekerja dengan alat, kadangkala tidak mungkin untuk menulis pertanyaan yang dikehendaki dengan segera dan anda perlu mencuba, mencuba pilihan yang berbeza. Untuk kes sedemikian, alat ini menyediakan pengelogan, yang dipanggil seperti berikut:

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

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

Tetapi perlu diingat bahawa kaedah ini hanya menerima sebagai input talian, jadi tidak mungkin untuk memaparkan senarai lengkap elemen yang ditemui hasil daripada operasi pertama. Pilihan kedua, yang digunakan untuk penyahpepijatan, adalah untuk menetapkan pembolehubah ajaib dari semasa ke semasa result hasil pertanyaan dan lihat apa yang berlaku. Pendekatan ini tidak begitu mudah; anda perlu memastikan bahawa tiada penggantian atau operasi dengan ini dalam kod selepas result atau komen sahaja kod di bawah. Atau anda boleh, seperti saya, lupa untuk mengalih keluar beberapa panggilan sedemikian daripada peraturan sedia ada dan tertanya-tanya mengapa tiada apa-apa yang berfungsi.

Cara yang lebih mudah ialah memanggil kaedah return dengan parameter yang diperlukan. Dalam kes ini, pelaksanaan peraturan akan berakhir dan kami akan dapat melihat apa yang berlaku akibat daripada apa yang kami tulis:

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

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

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

Masalah log masuk

Terdapat situasi apabila anda tidak boleh mengakses alat CxAudit (yang digunakan untuk menulis peraturan). Terdapat banyak sebab untuk ini, termasuk ranap sistem, kemas kini Windows mengejut, BSOD dan situasi tidak dijangka lain yang di luar kawalan kami. Dalam kes ini, kadangkala terdapat sesi yang belum selesai dalam pangkalan data, yang menghalang anda daripada log masuk semula. Untuk membetulkannya, anda perlu menjalankan beberapa pertanyaan:

Untuk Checkmarx sebelum 8.6:

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

Untuk Checkmarx selepas 8.6:

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

Peraturan penulisan

Sekarang kita sampai ke bahagian yang paling menarik. Apabila anda mula menulis peraturan dalam CxQL, apa yang anda sering kekurangan bukanlah dokumentasi seperti beberapa contoh hidup untuk menyelesaikan masalah tertentu dan menerangkan proses bagaimana pertanyaan berfungsi secara umum.

Saya akan cuba menjadikan hidup lebih mudah bagi mereka yang mula menyelami bahasa pertanyaan dan memberikan beberapa contoh menggunakan Pertanyaan Tersuai untuk menyelesaikan masalah tertentu. Sesetengah daripada mereka agak umum dan boleh digunakan dalam syarikat anda secara praktikal tanpa perubahan, yang lain lebih khusus, tetapi ia juga boleh digunakan dengan menukar kod untuk disesuaikan dengan spesifik aplikasi anda.

Jadi, berikut adalah masalah yang paling kerap kami hadapi:

Tugas: Terdapat beberapa Aliran dalam hasil pelaksanaan peraturan dan satu daripadanya adalah sarang yang lain, anda mesti meninggalkan salah satu daripadanya.

penyelesaian: Malah, kadangkala Checkmarx menunjukkan beberapa aliran data yang mungkin bertindih dan menjadi versi yang dipendekkan bagi yang lain. Terdapat kaedah khas untuk kes sedemikian ReduceFlow. Bergantung pada parameter, ia akan memilih Aliran terpendek atau terpanjang:

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

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

Tugas: Kembangkan senarai data sensitif yang alat itu bertindak balas

penyelesaian: Checkmarx mempunyai peraturan asas, yang hasilnya digunakan oleh banyak pertanyaan lain. Dengan menambah beberapa peraturan ini dengan data khusus untuk aplikasi anda, anda boleh menambah baik hasil imbasan anda dengan serta-merta. Di bawah ialah contoh peraturan untuk memulakan anda:

Senarai_pelanggaran_privasi_am

Mari tambah beberapa pembolehubah yang digunakan dalam aplikasi kami untuk menyimpan maklumat sensitif:

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

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

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

Tugas: Kembangkan senarai pembolehubah dengan kata laluan

penyelesaian: Saya akan mengesyorkan agar anda segera memberi perhatian kepada peraturan asas untuk menentukan kata laluan dalam kod dan menambah senarai nama pembolehubah yang biasa digunakan dalam syarikat anda.

Kata laluan_senarai_pelanggaran_privasi

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

Tugas: Tambahkan rangka kerja terpakai yang tidak disokong oleh Checkmarx

penyelesaian: Semua pertanyaan dalam Checkmarx dibahagikan mengikut bahasa, jadi anda perlu menambah peraturan untuk setiap bahasa. Di bawah adalah beberapa contoh peraturan tersebut.

Jika perpustakaan digunakan yang melengkapkan atau menggantikan fungsi standard, ia boleh ditambah dengan mudah kepada peraturan asas. Kemudian semua orang yang menggunakannya akan segera mengetahui tentang pengenalan baharu. Sebagai contoh, perpustakaan untuk log masuk Android ialah Timber dan Loggi. Dalam pakej asas, tiada peraturan untuk mengenal pasti panggilan bukan sistem, jadi jika kata laluan atau pengecam sesi masuk ke dalam log, kami tidak akan mengetahuinya. Mari cuba tambah definisi kaedah sedemikian pada peraturan Checkmarx.

Contoh kod ujian yang menggunakan perpustakaan Timber untuk pengelogan:

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

Dan berikut ialah contoh permintaan untuk Checkmarx, yang akan membolehkan anda menambah definisi memanggil kaedah Timber sebagai titik keluar untuk data daripada aplikasi:

CariAndroidOutputs

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

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

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

Dan anda juga boleh menambah peraturan jiran, tetapi yang ini berkaitan secara langsung dengan log masuk Android:

CariAndroidLog_Outputs

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

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

Juga, jika aplikasi Android menggunakan Pengurus Kerja untuk kerja tak segerak, adalah idea yang baik untuk memaklumkan Checkmarx tentang perkara ini dengan menambahkan kaedah untuk mendapatkan data daripada tugasan getInputData:

CariAndroidRead

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

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

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

Tugas: Mencari data sensitif dalam plist untuk projek iOS

penyelesaian: iOS sering menggunakan fail khas dengan sambungan .plist untuk menyimpan pelbagai pembolehubah dan nilai. Menyimpan kata laluan, token, kunci dan data sensitif lain dalam fail ini tidak disyorkan, kerana ia boleh diekstrak daripada peranti tanpa sebarang masalah.

Fail plist mempunyai ciri yang tidak jelas pada mata kasar, tetapi penting untuk Checkmarx. Mari tulis peraturan yang akan mencari data yang kami perlukan dan beritahu kami jika kata laluan atau token disebut di suatu tempat.

Contoh fail sedemikian, yang mengandungi token untuk komunikasi dengan perkhidmatan bahagian belakang:

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

Dan peraturan untuk Checkmarx, yang mempunyai beberapa nuansa yang harus diambil kira semasa menulis:

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

Tugas: Mencari Maklumat dalam XML

penyelesaian: Checkmarx mempunyai fungsi yang sangat mudah untuk bekerja dengan XML dan mencari nilai, teg, atribut dan banyak lagi. Tetapi, malangnya, terdapat ralat dalam dokumentasi kerana tidak ada satu contoh pun yang berfungsi. Walaupun fakta bahawa kecacatan ini telah dihapuskan dalam versi terkini dokumentasi, berhati-hati jika anda menggunakan versi dokumen yang lebih awal.

Berikut ialah contoh yang salah daripada dokumentasi:

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

Hasil daripada percubaan pelaksanaan, kami akan menerima ralat yang All tidak ada kaedah sedemikian... Dan ini benar, kerana terdapat ruang objek khas yang berasingan untuk menggunakan fungsi untuk bekerja dengan XML - cxXPath. Inilah rupa pertanyaan yang betul untuk mencari tetapan dalam Android yang membenarkan penggunaan trafik HTTP:

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

Mari kita lihat dengan lebih terperinci, kerana sintaks untuk semua fungsi adalah serupa, selepas anda mengetahuinya, maka anda hanya perlu memilih yang anda perlukan. Jadi, secara berurutan mengikut parameter:

  • "*.xml"— topeng fail untuk dicari

  • 8 — id bahasa yang peraturan itu digunakan

  • "cleartextTrafficPermitted"- nama atribut dalam xml

  • "true" — nilai atribut ini

  • false — penggunaan ungkapan biasa semasa mencari

  • true — bermakna carian akan dilakukan tanpa menghiraukan kes, iaitu, tidak sensitif huruf

Sebagai contoh, kami menggunakan peraturan yang mengenal pasti salah, dari sudut pandangan keselamatan, tetapan sambungan rangkaian dalam Android yang membenarkan komunikasi dengan pelayan melalui protokol HTTP. Contoh tetapan yang mengandungi atribut cleartextTrafficPermitted dengan makna 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>

Tugas: Hadkan hasil mengikut nama/laluan fail

penyelesaian: Dalam salah satu projek besar yang berkaitan dengan pembangunan aplikasi mudah alih untuk Android, kami menemui positif palsu peraturan yang menentukan tetapan kekeliruan. Hakikatnya ialah peraturan di luar kotak mencari dalam fail build.gradle tetapan yang bertanggungjawab untuk menggunakan peraturan kekeliruan untuk versi keluaran aplikasi.

Tetapi dalam projek besar kadang-kadang terdapat fail kanak-kanak build.gradle, yang merujuk kepada perpustakaan yang disertakan dalam projek. Keanehannya ialah walaupun fail ini tidak menunjukkan keperluan untuk mengelirukan, tetapan fail pemasangan induk akan digunakan semasa penyusunan.

Oleh itu, tugasnya adalah untuk memotong pencetus dalam fail kanak-kanak yang dimiliki oleh perpustakaan. Mereka boleh dikenal pasti dengan kehadiran garisan apply 'com.android.library'.

Contoh kod daripada fail build.gradle, yang menentukan keperluan untuk mengelirukan:

apply plugin: 'com.android.application'

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

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

dependencies {
  ...
}

Contoh fail build.gradle untuk perpustakaan yang disertakan dalam projek yang tidak mempunyai tetapan ini:

apply plugin: 'android-library'

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

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

Dan peraturan untuk 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);
		}
	}
}

Pendekatan ini boleh menjadi agak universal dan berguna bukan sahaja untuk aplikasi Android, tetapi juga untuk kes lain apabila anda perlu menentukan sama ada hasil adalah kepunyaan fail tertentu.

Tugas: Tambahkan sokongan untuk pustaka pihak ketiga jika sintaks tidak disokong sepenuhnya

penyelesaian: Bilangan pelbagai rangka kerja yang digunakan dalam proses menulis kod adalah di luar carta. Sudah tentu, Checkmarx tidak selalu tahu tentang kewujudan mereka, dan tugas kami adalah untuk mengajarnya untuk memahami bahawa kaedah tertentu tergolong khusus dalam rangka kerja ini. Kadang-kadang ini rumit oleh fakta bahawa rangka kerja menggunakan nama fungsi yang sangat biasa dan adalah mustahil untuk menentukan secara jelas hubungan panggilan tertentu ke perpustakaan tertentu.

Kesukarannya ialah sintaks perpustakaan tersebut tidak selalunya dikenali dengan betul dan anda perlu mencuba untuk mengelak daripada mendapat sejumlah besar positif palsu. Terdapat beberapa pilihan untuk meningkatkan ketepatan pengimbasan dan menyelesaikan masalah:

  • Pilihan pertama, kami tahu pasti bahawa perpustakaan digunakan dalam projek tertentu dan boleh menggunakan peraturan di peringkat pasukan. Tetapi jika pasukan memutuskan untuk mengambil pendekatan yang berbeza atau menggunakan beberapa perpustakaan di mana nama fungsi bertindih, kita boleh mendapatkan gambaran yang tidak begitu menyenangkan tentang banyak positif palsu

  • Pilihan kedua ialah mencari fail di mana perpustakaan diimport dengan jelas. Dengan pendekatan ini, kami boleh memastikan bahawa perpustakaan yang kami perlukan betul-betul digunakan dalam fail ini.

  • Dan pilihan ketiga ialah menggunakan kedua-dua pendekatan di atas bersama-sama.

Sebagai contoh, mari kita lihat perpustakaan yang terkenal dalam kalangan sempit licin untuk bahasa pengaturcaraan Scala, iaitu, kefungsian Penyatuan Nilai Tersurat. Secara umum, untuk menghantar parameter kepada pertanyaan SQL, anda mesti menggunakan operator $, yang menggantikan data ke dalam pertanyaan SQL yang telah dibentuk sebelumnya. Iaitu, sebenarnya, ia adalah analog langsung Pernyataan Disediakan di Jawa. Tetapi, jika anda perlu membina pertanyaan SQL secara dinamik, sebagai contoh, jika anda perlu menghantar nama jadual, anda boleh menggunakan operator #$, yang akan menggantikan data secara langsung ke dalam pertanyaan (hampir seperti penggabungan rentetan).

Contoh kod:

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

Checkmarx belum tahu bagaimana untuk mengesan penggunaan Splicing Literal Values ​​dan melangkau operator #$, jadi mari kita cuba mengajarnya untuk mengenal pasti suntikan SQL yang berpotensi dan menyerlahkan tempat yang betul dalam kod:

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

Tugas: Cari fungsi terdedah yang digunakan dalam perpustakaan Sumber Terbuka

penyelesaian: Banyak syarikat menggunakan alat pemantauan Sumber Terbuka (amalan OSA) untuk mengesan penggunaan versi perpustakaan yang terdedah dalam aplikasi yang dibangunkan. Kadangkala tidak mungkin untuk mengemas kini perpustakaan sedemikian kepada versi selamat. Dalam sesetengah kes terdapat batasan fungsi, dalam yang lain tiada versi selamat sama sekali. Dalam kes ini, gabungan amalan SAST dan OSA akan membantu menentukan bahawa fungsi yang membawa kepada eksploitasi kelemahan tidak digunakan dalam kod.

Tetapi kadangkala, terutamanya apabila mempertimbangkan JavaScript, ini mungkin bukan tugas yang remeh sepenuhnya. Di bawah ialah penyelesaian, mungkin tidak sesuai, tetapi tetap berfungsi, menggunakan contoh kelemahan dalam komponen lodash dalam kaedah template и *set.

Contoh ujian kod yang berpotensi terdedah dalam fail JS:

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

Dan apabila menyambung secara langsung dalam 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>

Kami sedang mencari semua kaedah terdedah kami, yang disenaraikan dalam kelemahan:

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

Tugas: Mencari sijil yang dibenamkan dalam aplikasi

penyelesaian: Ia bukan sesuatu yang luar biasa untuk aplikasi, terutamanya yang mudah alih, menggunakan sijil atau kunci untuk mengakses pelbagai pelayan atau mengesahkan SSL-Pinning. Dari perspektif keselamatan, menyimpan perkara sedemikian dalam kod bukanlah amalan terbaik. Mari cuba tulis peraturan yang akan mencari fail serupa dalam repositori:

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

Tugas: Mencari token yang terjejas dalam aplikasi

penyelesaian: Selalunya diperlukan untuk membatalkan token yang dikompromi atau maklumat penting lain yang terdapat dalam kod. Sudah tentu, menyimpannya di dalam kod sumber bukanlah idea yang baik, tetapi situasi berbeza-beza. Terima kasih kepada pertanyaan CxQL, mencari perkara seperti ini agak mudah:

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

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

Kesimpulan

Saya berharap artikel ini berguna kepada mereka yang mula mengenali alat Checkmarx. Mungkin mereka yang telah lama menulis peraturan mereka sendiri juga akan mendapati sesuatu yang berguna dalam panduan ini.

Malangnya, pada masa ini terdapat kekurangan sumber di mana idea baharu boleh diperolehi semasa pembangunan peraturan untuk Checkmarx. Itulah sebabnya kami mencipta repositori pada Github, di mana kami akan menyiarkan kerja kami supaya semua orang yang menggunakan CxQL dapat mencari sesuatu yang berguna di dalamnya, dan juga berpeluang untuk berkongsi kerja mereka dengan komuniti. Repositori sedang dalam proses pengisian dan penstrukturan kandungan, jadi penyumbang dialu-alukan!

Thank you!

Sumber: www.habr.com

Tambah komen