วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้า

เฮ้ ฮับ!

ในงานของเรา บริษัทของเรามักจะเกี่ยวข้องกับเครื่องมือวิเคราะห์โค้ดแบบคงที่ (SAST) ต่างๆ บ่อยครั้ง นอกกรอบพวกเขาทั้งหมดทำงานโดยเฉลี่ย แน่นอนว่าทุกอย่างขึ้นอยู่กับโครงการและเทคโนโลยีที่ใช้ในโครงการ ตลอดจนกฎการวิเคราะห์ที่ครอบคลุมเทคโนโลยีเหล่านี้ได้ดีเพียงใด ในความคิดของฉัน หนึ่งในเกณฑ์ที่สำคัญที่สุดในการเลือกเครื่องมือ SAST คือความสามารถในการปรับแต่งให้เข้ากับลักษณะเฉพาะของแอปพลิเคชันของคุณ กล่าวคือ เขียนและเปลี่ยนแปลงกฎการวิเคราะห์ หรือที่มักเรียกว่า Custom Queries

วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้า

เรามักใช้ Checkmarx ซึ่งเป็นเครื่องมือวิเคราะห์โค้ดที่น่าสนใจและทรงพลังมาก ในบทความนี้ ผมจะพูดถึงประสบการณ์ของผมในการเขียนกฎการวิเคราะห์

สารบัญ

การเข้า

ขั้นแรก ฉันอยากจะแนะนำหนึ่งในไม่กี่บทความในภาษารัสเซียเกี่ยวกับคุณสมบัติของการเขียนข้อความค้นหาสำหรับ Checkmarx เผยแพร่บนHabréเมื่อปลายปี 2019 ภายใต้ชื่อ: “สวัสดีเช็คมาร์กซ์!” วิธีเขียนแบบสอบถาม Checkmarx SAST และค้นหาช่องโหว่เจ๋งๆ.

โดยจะตรวจสอบรายละเอียดวิธีเขียนแบบสอบถามแรกใน CxQL (Checkmarx Query Language) สำหรับแอปพลิเคชันทดสอบบางรายการ และแสดงหลักการพื้นฐานของวิธีการทำงานของกฎการวิเคราะห์

ฉันจะไม่ทำซ้ำสิ่งที่อธิบายไว้ในนั้นแม้ว่าทางแยกบางส่วนจะยังคงอยู่ก็ตาม ในบทความของฉัน ฉันจะพยายามรวบรวม "คอลเลกชันสูตรอาหาร" รายการวิธีแก้ไขปัญหาเฉพาะที่ฉันพบระหว่างทำงานกับ Checkmarx ฉันต้องระดมสมองกับปัญหามากมายเหล่านี้ บางครั้งมีข้อมูลไม่เพียงพอในเอกสาร และบางครั้งก็ยากที่จะเข้าใจว่าต้องทำอย่างไร ฉันหวังว่าประสบการณ์และการนอนไม่หลับของฉันจะไม่สูญเปล่า และ "คอลเลกชันสูตรการค้นหาที่กำหนดเอง" นี้จะช่วยคุณประหยัดเวลาได้สองสามชั่วโมงหรือสองสามเซลล์ เอาล่ะ มาเริ่มกันเลย!

ข้อมูลทั่วไปเกี่ยวกับกฎเกณฑ์

ขั้นแรก มาดูแนวคิดพื้นฐานบางประการและกระบวนการทำงานกับกฎ เพื่อความเข้าใจที่ดีขึ้นว่าจะเกิดอะไรขึ้นต่อไป และเนื่องจากเอกสารไม่ได้พูดอะไรเกี่ยวกับเรื่องนี้หรือมีโครงสร้างกระจายออกไปมากนักซึ่งไม่สะดวกนัก

  1. กฎจะถูกใช้ในระหว่างการสแกน ขึ้นอยู่กับการตั้งค่าล่วงหน้าที่เลือกเมื่อเริ่มต้น (ชุดของกฎที่ใช้งานอยู่) คุณสามารถสร้างค่าที่ตั้งไว้ล่วงหน้าได้ไม่จำกัดจำนวน และวิธีการจัดโครงสร้างค่าที่ตั้งล่วงหน้าจะขึ้นอยู่กับลักษณะเฉพาะของกระบวนการของคุณ คุณสามารถจัดกลุ่มตามภาษาหรือเลือกค่าที่ตั้งไว้ล่วงหน้าสำหรับแต่ละโปรเจ็กต์ จำนวนกฎที่ใช้งานอยู่จะส่งผลต่อความเร็วและความแม่นยำของการสแกน

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าการตั้งค่าล่วงหน้าในอินเทอร์เฟซ Checkmarx

  2. กฎได้รับการแก้ไขด้วยเครื่องมือพิเศษที่เรียกว่า CxAuditor นี่คือแอปพลิเคชันเดสก์ท็อปที่เชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้ Checkmarx เครื่องมือนี้มีโหมดการทำงานสองโหมด: การแก้ไขกฎและการวิเคราะห์ผลลัพธ์ของการสแกนที่ดำเนินการไปแล้ว

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าอินเทอร์เฟซ CxAudit

  3. กฎใน Checkmarx แบ่งตามภาษา กล่าวคือ แต่ละภาษาจะมีชุดคำถามของตัวเอง นอกจากนี้ยังมีกฎทั่วไปบางประการที่ใช้โดยไม่คำนึงถึงภาษา ซึ่งเรียกว่าข้อความค้นหาพื้นฐาน โดยส่วนใหญ่แล้ว ข้อความค้นหาพื้นฐานจะเกี่ยวข้องกับการค้นหาข้อมูลที่กฎอื่นใช้

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าการแบ่งกฎเกณฑ์ตามภาษา

  4. กฎคือ "ปฏิบัติการได้" และ "ไม่ปฏิบัติการได้" (ดำเนินการแล้วและไม่ดำเนินการ) ในความคิดของฉันไม่ใช่ชื่อที่ถูกต้องนัก แต่นั่นคือสิ่งที่เป็นอยู่ สิ่งที่สำคัญที่สุดคือผลลัพธ์ของการดำเนินการกฎ "ที่ปฏิบัติการได้" จะแสดงในผลลัพธ์การสแกนใน UI และกฎที่ "ไม่ปฏิบัติการได้" จำเป็นเพื่อใช้ผลลัพธ์ในคำขออื่น ๆ เท่านั้น (โดยพื้นฐานแล้วเป็นเพียงฟังก์ชัน)

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าการกำหนดประเภทกฎเมื่อสร้าง

  5. คุณสามารถสร้างกฎใหม่หรือเสริม/เขียนกฎที่มีอยู่ใหม่ได้ หากต้องการเขียนกฎใหม่ คุณต้องค้นหากฎนั้นในแผนผัง คลิกขวาและเลือก "แทนที่" จากเมนูแบบเลื่อนลง สิ่งสำคัญคือต้องจำไว้ว่ากฎใหม่ไม่ได้รวมอยู่ในค่าที่ตั้งล่วงหน้าในตอนแรกและไม่ได้ใช้งานอยู่ หากต้องการเริ่มใช้งาน คุณต้องเปิดใช้งานในเมนู "Preset Manager" ในเครื่องมือ กฎที่เขียนใหม่จะคงการตั้งค่าไว้ กล่าวคือ หากกฎนั้นทำงานอยู่ กฎนั้นก็จะยังคงอยู่และจะถูกนำไปใช้ทันที

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าตัวอย่างกฎใหม่ในอินเทอร์เฟซ Preset Manager

  6. ในระหว่างการดำเนินการ จะมีการสร้าง "แผนผัง" ของคำขอซึ่งขึ้นอยู่กับอะไร กฎที่รวบรวมข้อมูลจะถูกดำเนินการก่อนและผู้ที่ใช้ข้อมูลนั้นเป็นอันดับสอง ผลลัพธ์การดำเนินการจะถูกแคชไว้ ดังนั้น หากเป็นไปได้ที่จะใช้ผลลัพธ์ของกฎที่มีอยู่ ก็ควรทำเช่นนั้น ซึ่งจะทำให้เวลาในการสแกนลดลง

  7. สามารถใช้กฎเกณฑ์ได้ในระดับต่างๆ:

  • สำหรับทั้งระบบ - จะถูกใช้สำหรับการสแกนโปรเจ็กต์ใดๆ

  • ในระดับทีม (ทีม) - จะถูกใช้เพื่อสแกนโครงการในทีมที่เลือกเท่านั้น

  • ในระดับโครงการ - จะถูกนำไปใช้ในโครงการเฉพาะ

    วิธีเขียนกฎสำหรับ Checkmarx ไม่ให้บ้าการกำหนดระดับที่จะใช้กฎ

“พจนานุกรม” สำหรับผู้เริ่มต้น

ฉันจะเริ่มต้นด้วยบางสิ่งที่ทำให้เกิดคำถามในใจ และจะแสดงเทคนิคต่างๆ ที่จะทำให้ชีวิตง่ายขึ้นอย่างมาก

การดำเนินการกับรายการ

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

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

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

รายการที่พบทั้งหมด

ภายในภาษาที่สแกน คุณจะได้รับรายการองค์ประกอบทั้งหมดที่ Checkmarx ระบุไว้ (สตริง ฟังก์ชัน คลาส วิธีการ ฯลฯ) นี่คือพื้นที่บางส่วนของวัตถุที่สามารถเข้าถึงได้ All. นั่นคือเพื่อค้นหาวัตถุที่มีชื่อเฉพาะ searchMeคุณสามารถค้นหาตามชื่อในวัตถุที่พบทั้งหมดได้:

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

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

แต่ หากคุณต้องการค้นหาในภาษาอื่นที่ไม่รวมอยู่ในการสแกนด้วยเหตุผลบางประการ (เช่น Groovy ในโปรเจ็กต์ Android) คุณสามารถขยายพื้นที่อ็อบเจ็กต์ของเราผ่านตัวแปรได้:

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

ฟังก์ชั่นสำหรับการวิเคราะห์โฟลว์

ฟังก์ชันเหล่านี้ใช้ในกฎต่างๆ มากมาย และต่อไปนี้เป็นข้อมูลสรุปเล็กๆ น้อยๆ เกี่ยวกับความหมายของฟังก์ชันเหล่านี้:

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

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

รับชื่อไฟล์/เส้นทาง

มีคุณลักษณะหลายอย่างที่สามารถได้รับจากผลลัพธ์ของแบบสอบถาม (ชื่อของไฟล์ที่พบรายการ สตริง ฯลฯ) แต่เอกสารไม่ได้ระบุวิธีการรับและใช้งาน ดังนั้น ในการดำเนินการนี้ คุณต้องเข้าถึงคุณสมบัติ LinePragma และวัตถุที่เราต้องการจะอยู่ข้างใน:

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

มันคุ้มค่าที่จะจำไว้ว่า FileName มีเส้นทางไปยังไฟล์จริง ๆ เนื่องจากเราใช้วิธีนี้ GetFirstGraph.

ผลการดำเนินการ

มีตัวแปรพิเศษอยู่ภายใน CxQL resultซึ่งส่งคืนผลลัพธ์ของการดำเนินการกฎที่คุณเขียน โดยจะเริ่มต้นทันทีและคุณสามารถเขียนผลลัพธ์ระดับกลางลงไปได้ โดยเปลี่ยนแปลงและปรับปรุงผลลัพธ์ในขณะที่คุณทำงาน แต่หากไม่มีการกำหนดตัวแปรหรือฟังก์ชันนี้ภายในกฎ return— ผลการดำเนินการจะเป็นศูนย์เสมอ

ข้อความค้นหาต่อไปนี้จะไม่ส่งคืนสิ่งใดๆ ให้เราอันเป็นผลมาจากการดำเนินการ และจะว่างเปล่าเสมอ:

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

แต่เมื่อกำหนดผลการดำเนินการให้กับผลลัพธ์ของตัวแปรเวทย์มนตร์แล้ว เราจะเห็นว่าการเรียกนี้ส่งกลับหาเราอย่างไร:

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

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

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

การใช้ผลลัพธ์ของกฎอื่น ๆ

กฎใน Checkmarx สามารถเรียกได้ว่าคล้ายคลึงกับฟังก์ชันในภาษาการเขียนโปรแกรมทั่วไป เมื่อเขียนกฎ คุณอาจใช้ผลลัพธ์ของข้อความค้นหาอื่นๆ ได้ ตัวอย่างเช่น ไม่จำเป็นต้องค้นหาการเรียกใช้เมธอดทั้งหมดในโค้ดทุกครั้ง เพียงเรียกกฎที่ต้องการ:

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

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

วิธีการนี้ช่วยให้คุณย่อโค้ดให้สั้นลงและลดเวลาดำเนินการกฎได้อย่างมาก

การแก้ปัญหา

การบันทึก

เมื่อทำงานกับเครื่องมือ บางครั้งไม่สามารถเขียนข้อความค้นหาที่ต้องการได้ทันทีและคุณต้องทดลองลองใช้ตัวเลือกอื่น ในกรณีดังกล่าว เครื่องมือจัดให้มีการบันทึก ซึ่งมีชื่อดังต่อไปนี้:

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

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

แต่ควรจำไว้ว่าวิธีนี้ยอมรับเป็นอินพุตเท่านั้น สตริงดังนั้นจึงไม่สามารถแสดงรายการองค์ประกอบที่พบทั้งหมดอันเป็นผลมาจากการดำเนินการครั้งแรกได้ ตัวเลือกที่สองซึ่งใช้สำหรับการดีบักคือการกำหนดให้กับตัวแปรเวทย์มนตร์เป็นครั้งคราว result ผลลัพธ์ของการสืบค้นและดูว่าเกิดอะไรขึ้น วิธีนี้ไม่สะดวกนัก คุณต้องแน่ใจว่าจะไม่มีการแทนที่หรือการดำเนินการกับสิ่งนี้ในโค้ดหลังจากนั้น result หรือเพียงแสดงความคิดเห็นรหัสด้านล่าง หรือคุณสามารถลืมลบการโทรดังกล่าวออกจากกฎสำเร็จรูปเช่นเดียวกับฉัน และสงสัยว่าทำไมไม่มีอะไรทำงาน

วิธีที่สะดวกกว่าคือการเรียกวิธีการ return ด้วยพารามิเตอร์ที่ต้องการ ในกรณีนี้ การดำเนินการตามกฎจะสิ้นสุดและเราจะสามารถเห็นสิ่งที่เกิดขึ้นจากสิ่งที่เราเขียน:

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

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

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

ปัญหาการเข้าสู่ระบบ

มีสถานการณ์ที่คุณไม่สามารถเข้าถึงเครื่องมือ CxAudit (ซึ่งใช้ในการเขียนกฎ) อาจมีสาเหตุหลายประการ รวมถึงการล่ม การอัปเดต Windows อย่างกะทันหัน BSOD และสถานการณ์ที่ไม่คาดฝันอื่น ๆ ที่อยู่นอกเหนือการควบคุมของเรา ในกรณีนี้ บางครั้งมีเซสชันที่ยังไม่เสร็จสิ้นในฐานข้อมูล ซึ่งทำให้คุณไม่สามารถเข้าสู่ระบบอีกครั้งได้ หากต้องการแก้ไข คุณต้องเรียกใช้แบบสอบถามหลายรายการ:

สำหรับ Checkmarx ก่อน 8.6:

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

สำหรับ Checkmarx หลัง 8.6:

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

กฎการเขียน

ตอนนี้เรามาถึงส่วนที่น่าสนใจที่สุดแล้ว เมื่อคุณเริ่มเขียนกฎใน CxQL สิ่งที่คุณมักขาดไม่ใช่เอกสารที่มากเท่ากับตัวอย่างที่มีชีวิตของการแก้ปัญหาบางอย่างและอธิบายกระบวนการทำงานของคิวรีโดยทั่วไป

ฉันจะพยายามทำให้ชีวิตง่ายขึ้นเล็กน้อยสำหรับผู้ที่เริ่มเรียนรู้ภาษาของคิวรี และยกตัวอย่างการใช้ Custom Query เพื่อแก้ไขปัญหาบางอย่าง บางส่วนค่อนข้างกว้างและสามารถนำมาใช้ในบริษัทของคุณได้จริงโดยไม่มีการเปลี่ยนแปลง บางส่วนมีความเฉพาะเจาะจงมากกว่า แต่ก็สามารถนำมาใช้โดยการเปลี่ยนโค้ดเพื่อให้เหมาะกับการใช้งานเฉพาะของคุณ

ดังนั้นนี่คือปัญหาที่เราพบบ่อยที่สุด:

งาน: มีโฟลว์หลายอย่างในผลลัพธ์ของการดำเนินการกฎ และหนึ่งในนั้นคือการซ้อนของอีกโฟลว์ คุณต้องปล่อยหนึ่งในนั้น

การแก้ปัญหา: แท้จริงแล้ว บางครั้ง Checkmarx จะแสดงกระแสข้อมูลหลายอย่างที่อาจทับซ้อนกันและเป็นเวอร์ชันที่สั้นลงของกระแสข้อมูลอื่นๆ มีวิธีการพิเศษสำหรับกรณีดังกล่าว ลดการไหล ขึ้นอยู่กับพารามิเตอร์ มันจะเลือกการไหลที่สั้นที่สุดหรือยาวที่สุด:

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

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

งาน: ขยายรายการข้อมูลที่ละเอียดอ่อนที่เครื่องมือตอบสนอง

การแก้ปัญหา: Checkmarx มีกฎพื้นฐาน ซึ่งผลลัพธ์จะถูกใช้โดยข้อความค้นหาอื่นๆ มากมาย ด้วยการเสริมกฎบางข้อเหล่านี้ด้วยข้อมูลเฉพาะสำหรับแอปพลิเคชันของคุณ คุณสามารถปรับปรุงผลการสแกนได้ทันที ด้านล่างนี้เป็นตัวอย่างกฎสำหรับการเริ่มต้น:

General_privacy_violation_list

มาเพิ่มตัวแปรหลายตัวที่ใช้ในแอปพลิเคชันของเราเพื่อจัดเก็บข้อมูลที่ละเอียดอ่อน:

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

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

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

งาน: ขยายรายการตัวแปรด้วยรหัสผ่าน

การแก้ปัญหา: ฉันขอแนะนำให้ใส่ใจกับกฎพื้นฐานในการกำหนดรหัสผ่านในโค้ดทันที และเพิ่มรายการชื่อตัวแปรที่ใช้กันทั่วไปในบริษัทของคุณ

รหัสผ่าน_ความเป็นส่วนตัว_การละเมิด_รายการ

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

งาน: เพิ่มเฟรมเวิร์กที่ใช้ซึ่ง Checkmarx ไม่รองรับ

การแก้ปัญหา: ข้อความค้นหาทั้งหมดใน Checkmarx จะถูกแบ่งตามภาษา ดังนั้นคุณจึงต้องเพิ่มกฎสำหรับแต่ละภาษา ด้านล่างนี้เป็นตัวอย่างบางส่วนของกฎดังกล่าว

หากมีการใช้ไลบรารีเพื่อเสริมหรือแทนที่ฟังก์ชันมาตรฐาน ไลบรารีเหล่านั้นก็สามารถเพิ่มลงในกฎพื้นฐานได้อย่างง่ายดาย จากนั้นทุกคนที่ใช้จะได้เรียนรู้เกี่ยวกับการแนะนำตัวใหม่ทันที ตามตัวอย่าง ไลบรารีสำหรับการเข้าสู่ระบบใน Android คือ Timber และ Loggi ในแพ็คเกจพื้นฐาน ไม่มีกฎเกณฑ์ในการระบุการโทรที่ไม่ใช่ระบบ ดังนั้นหากรหัสผ่านหรือตัวระบุเซสชันเข้าไปในบันทึก เราจะไม่ทราบเรื่องนี้ ลองเพิ่มคำจำกัดความของวิธีการดังกล่าวลงในกฎ Checkmarx

ตัวอย่างโค้ดทดสอบที่ใช้ไลบรารี Timber สำหรับการบันทึก:

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

และนี่คือตัวอย่างคำขอ Checkmarx ซึ่งจะช่วยให้คุณเพิ่มคำจำกัดความของการเรียกเมธอด Timber เป็นจุดออกสำหรับข้อมูลจากแอปพลิเคชัน:

ค้นหา AndroidOutputs

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

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

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

และคุณยังสามารถเพิ่มกฎใกล้เคียงได้ แต่กฎนี้เกี่ยวข้องโดยตรงกับการเข้าสู่ระบบใน Android:

ค้นหา AndroidLog_Outputs

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

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

นอกจากนี้หากใช้งานแอพพลิเคชั่น Android ผู้จัดการงาน สำหรับงานอะซิงโครนัส เป็นความคิดที่ดีที่จะแจ้ง Checkmarx เพิ่มเติมเกี่ยวกับเรื่องนี้โดยเพิ่มวิธีการรับข้อมูลจากงาน getInputData:

ค้นหา AndroidRead

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

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

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

งาน: ค้นหาข้อมูลที่ละเอียดอ่อนใน plist สำหรับโปรเจ็กต์ iOS

การแก้ปัญหา: iOS มักใช้ไฟล์พิเศษที่มีนามสกุล .plist เพื่อจัดเก็บตัวแปรและค่าต่างๆ ไม่แนะนำให้จัดเก็บรหัสผ่าน โทเค็น คีย์ และข้อมูลที่ละเอียดอ่อนอื่นๆ ในไฟล์เหล่านี้ เนื่องจากสามารถแยกออกจากอุปกรณ์ได้โดยไม่มีปัญหาใดๆ

ไฟล์ Plist มีคุณสมบัติที่ไม่ชัดเจนด้วยตาเปล่า แต่มีความสำคัญสำหรับ Checkmarx มาเขียนกฎที่จะค้นหาข้อมูลที่เราต้องการและแจ้งให้เราทราบหากมีการกล่าวถึงรหัสผ่านหรือโทเค็นอยู่ที่ไหนสักแห่ง

ตัวอย่างของไฟล์ดังกล่าวซึ่งมีโทเค็นสำหรับการสื่อสารกับบริการแบ็กเอนด์:

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

และกฎสำหรับ Checkmarx ซึ่งมีความแตกต่างหลายประการที่ควรคำนึงถึงเมื่อเขียน:

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

งาน: การค้นหาข้อมูลในรูปแบบ XML

การแก้ปัญหา: Checkmarx มีฟังก์ชันที่สะดวกมากสำหรับการทำงานกับ XML และการค้นหาค่า แท็ก คุณลักษณะ และอื่นๆ แต่น่าเสียดายที่มีข้อผิดพลาดในเอกสารประกอบเนื่องจากไม่มีตัวอย่างเดียวที่ใช้งานได้ แม้ว่าข้อบกพร่องนี้จะได้รับการแก้ไขแล้วในเอกสารเวอร์ชันล่าสุด โปรดใช้ความระมัดระวังหากคุณใช้เอกสารเวอร์ชันก่อนหน้า

นี่เป็นตัวอย่างที่ไม่ถูกต้องจากเอกสารประกอบ:

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

อันเป็นผลมาจากความพยายามในการดำเนินการเราจะได้รับข้อผิดพลาดดังกล่าว All ไม่มีวิธีการดังกล่าว... และนี่ก็เป็นจริงเนื่องจากมีพื้นที่อ็อบเจ็กต์พิเศษแยกต่างหากสำหรับการใช้ฟังก์ชันสำหรับการทำงานกับ XML - cxXPath. นี่คือลักษณะการค้นหาที่ถูกต้องเพื่อค้นหาการตั้งค่าใน Android ที่อนุญาตให้ใช้การรับส่งข้อมูล HTTP:

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

มาดูรายละเอียดกันอีกหน่อย เนื่องจากไวยากรณ์สำหรับฟังก์ชันทั้งหมดคล้ายกัน หลังจากที่คุณหาได้แล้ว คุณเพียงแค่ต้องเลือกฟังก์ชันที่คุณต้องการ ดังนั้นตามลำดับตามพารามิเตอร์:

  • "*.xml"— มาสก์ของไฟล์ที่จะค้นหา

  • 8 — รหัสของภาษาที่ใช้กฎ

  • "cleartextTrafficPermitted"— ชื่อแอตทริบิวต์ใน xml

  • "true" — ค่าของคุณลักษณะนี้

  • false — การใช้นิพจน์ทั่วไปในการค้นหา

  • true — หมายความว่าการค้นหาจะดำเนินการโดยไม่สนใจตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ นั่นคือ ไม่คำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่

ตามตัวอย่าง เราใช้กฎที่ระบุไม่ถูกต้องจากมุมมองด้านความปลอดภัย การตั้งค่าการเชื่อมต่อเครือข่ายใน Android ที่อนุญาตการสื่อสารกับเซิร์ฟเวอร์ผ่านโปรโตคอล HTTP ตัวอย่างการตั้งค่าที่มีแอตทริบิวต์ cleartextTrafficPermitted ด้วยความหมาย 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>

งาน: จำกัดผลลัพธ์ตามชื่อไฟล์/พาธ

การแก้ปัญหา: ในโปรเจ็กต์ขนาดใหญ่แห่งหนึ่งที่เกี่ยวข้องกับการพัฒนาแอปพลิเคชันมือถือสำหรับ Android เราพบผลบวกที่ผิดพลาดของกฎที่กำหนดการตั้งค่าการทำให้สับสน ความจริงก็คือกฎนอกกรอบจะค้นหาในไฟล์ build.gradle การตั้งค่าที่รับผิดชอบในการใช้กฎการทำให้สับสนสำหรับเวอร์ชันที่เผยแพร่ของแอปพลิเคชัน

แต่ในโปรเจ็กต์ขนาดใหญ่บางครั้งอาจมีไฟล์ย่อย build.gradleซึ่งหมายถึงไลบรารีที่รวมอยู่ในโปรเจ็กต์ ลักษณะเฉพาะคือแม้ว่าไฟล์เหล่านี้ไม่ได้ระบุถึงความจำเป็นในการสร้างความสับสน แต่การตั้งค่าของไฟล์แอสเซมบลีพาเรนต์จะถูกนำไปใช้ในระหว่างการคอมไพล์

ดังนั้นงานคือตัดทริกเกอร์ในไฟล์ลูกที่เป็นของไลบรารี พวกเขาสามารถระบุได้โดยการมีอยู่ของเส้น apply 'com.android.library'.

ตัวอย่างโค้ดจากไฟล์ build.gradleซึ่งกำหนดความจำเป็นในการทำให้สับสน:

apply plugin: 'com.android.application'

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

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

dependencies {
  ...
}

ตัวอย่างไฟล์ build.gradle สำหรับไลบรารีที่รวมอยู่ในโปรเจ็กต์ที่ไม่มีการตั้งค่านี้:

apply plugin: 'android-library'

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

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

และกฎสำหรับ Checkmarx:

ProGuard ObfuscationNotInUse

// Поиск метода 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);
		}
	}
}

วิธีการนี้ค่อนข้างเป็นสากลและมีประโยชน์ไม่เพียง แต่สำหรับแอปพลิเคชัน Android เท่านั้น แต่ยังรวมถึงกรณีอื่น ๆ เมื่อคุณต้องการพิจารณาว่าผลลัพธ์เป็นของไฟล์ใดไฟล์หนึ่งหรือไม่

งาน: เพิ่มการสนับสนุนสำหรับไลบรารีบุคคลที่สามหากไวยากรณ์ไม่รองรับอย่างสมบูรณ์

การแก้ปัญหา: จำนวนกรอบงานต่างๆ ที่ใช้ในกระบวนการเขียนโค้ดนั้นอยู่นอกแผนภูมิ แน่นอนว่า Checkmarx ไม่ได้รู้เกี่ยวกับการมีอยู่ของมันเสมอไป และงานของเราคือสอนให้เข้าใจว่าวิธีการบางอย่างเป็นของกรอบการทำงานนี้โดยเฉพาะ บางครั้งสิ่งนี้อาจซับซ้อนเนื่องจากข้อเท็จจริงที่ว่าเฟรมเวิร์กใช้ชื่อฟังก์ชันที่ธรรมดามากและเป็นไปไม่ได้ที่จะระบุความสัมพันธ์ของการเรียกเฉพาะไปยังไลบรารีเฉพาะอย่างไม่คลุมเครือ

ปัญหาคือไวยากรณ์ของไลบรารีดังกล่าวไม่ได้รับการจดจำอย่างถูกต้องเสมอไป และคุณต้องทดลองเพื่อหลีกเลี่ยงไม่ให้ได้รับผลบวกลวงจำนวนมาก มีหลายตัวเลือกในการปรับปรุงความแม่นยำในการสแกนและแก้ไขปัญหา:

  • ตัวเลือกแรก เรารู้แน่ว่าไลบรารีนั้นถูกใช้ในโปรเจ็กต์เฉพาะและสามารถใช้กฎในระดับทีมได้ แต่ถ้าทีมตัดสินใจที่จะใช้แนวทางที่แตกต่างออกไปหรือใช้หลายไลบรารีที่ชื่อฟังก์ชันทับซ้อนกัน เราจะได้ภาพที่ไม่น่าพึงพอใจของผลบวกลวงจำนวนมาก

  • ตัวเลือกที่สองคือการค้นหาไฟล์ที่มีการนำเข้าไลบรารีอย่างชัดเจน ด้วยวิธีนี้ เราจึงมั่นใจได้ว่าไลบรารีที่เราต้องการจะถูกใช้ในไฟล์นี้ทุกประการ

  • และทางเลือกที่สามคือการใช้สองวิธีข้างต้นร่วมกัน

ตัวอย่างเช่น ลองดูห้องสมุดที่มีชื่อเสียงในวงแคบๆ เนียน สำหรับภาษาโปรแกรม Scala ได้แก่ ฟังก์ชันการทำงาน ประกบค่าตัวอักษร. โดยทั่วไป หากต้องการส่งพารามิเตอร์ไปยังแบบสอบถาม SQL คุณต้องใช้ตัวดำเนินการ $ซึ่งแทนที่ข้อมูลลงในแบบสอบถาม SQL ที่จัดรูปแบบไว้ล่วงหน้า นั่นคือ ในความเป็นจริง มันเป็นอะนาล็อกโดยตรงของคำสั่งที่เตรียมไว้ในภาษา Java แต่ถ้าคุณต้องการสร้างแบบสอบถาม SQL แบบไดนามิก เช่น หากคุณต้องการส่งชื่อตาราง คุณสามารถใช้ตัวดำเนินการ #$ซึ่งจะแทนที่ข้อมูลลงในแบบสอบถามโดยตรง (เกือบจะเหมือนกับการต่อสตริง)

รหัสตัวอย่าง:

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

Checkmarx ยังไม่ทราบวิธีการตรวจสอบการใช้ Splicing Literal Values ​​​​และข้ามตัวดำเนินการ #$ดังนั้นเรามาลองสอนให้ระบุการแทรก SQL ที่เป็นไปได้และเน้นตำแหน่งที่ถูกต้องในโค้ด:

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

งาน: ค้นหาฟังก์ชันที่มีช่องโหว่ที่ใช้ในไลบรารีโอเพ่นซอร์ส

การแก้ปัญหา: บริษัทหลายแห่งใช้เครื่องมือตรวจสอบโอเพ่นซอร์ส (แนวปฏิบัติ OSA) เพื่อตรวจจับการใช้ไลบรารีเวอร์ชันที่มีช่องโหว่ในแอปพลิเคชันที่พัฒนาแล้ว บางครั้งไม่สามารถอัปเดตไลบรารีดังกล่าวเป็นเวอร์ชันที่ปลอดภัยได้ ในบางกรณีก็มีข้อจำกัดด้านการทำงาน ในบางกรณีก็ไม่มีเวอร์ชันที่ปลอดภัยเลย ในกรณีนี้ การผสมผสานระหว่างแนวทางปฏิบัติ SAST และ OSA จะช่วยในการพิจารณาว่าฟังก์ชันที่นำไปสู่การแสวงหาประโยชน์จากช่องโหว่นั้นไม่ได้ถูกใช้ในโค้ด

แต่บางครั้ง โดยเฉพาะอย่างยิ่งเมื่อพิจารณาถึง JavaScript นี่อาจไม่ใช่งานที่ไม่สำคัญเลย ด้านล่างนี้เป็นวิธีแก้ปัญหา อาจไม่เหมาะนัก แต่ก็ใช้งานได้ โดยใช้ตัวอย่างของช่องโหว่ในส่วนประกอบ lodash ในวิธีการ template и *set.

ตัวอย่างโค้ดทดสอบที่อาจมีช่องโหว่ในไฟล์ 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!'

และเมื่อเชื่อมต่อโดยตรงใน 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>

เรากำลังมองหาวิธีการที่มีช่องโหว่ทั้งหมดซึ่งมีรายการอยู่ในช่องโหว่:

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

งาน: ค้นหาใบรับรองที่ฝังอยู่ในแอปพลิเคชัน

การแก้ปัญหา: ไม่ใช่เรื่องแปลกที่แอปพลิเคชัน โดยเฉพาะอุปกรณ์พกพา จะใช้ใบรับรองหรือคีย์เพื่อเข้าถึงเซิร์ฟเวอร์ต่างๆ หรือตรวจสอบ SSL-Pinning จากมุมมองด้านความปลอดภัย การจัดเก็บสิ่งเหล่านี้ในโค้ดไม่ใช่แนวทางปฏิบัติที่ดีที่สุด ลองเขียนกฎที่จะค้นหาไฟล์ที่คล้ายกันในที่เก็บ:

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

งาน: ค้นหาโทเค็นที่ถูกบุกรุกในแอปพลิเคชัน

การแก้ปัญหา: มักจำเป็นต้องเพิกถอนโทเค็นที่ถูกบุกรุกหรือข้อมูลสำคัญอื่น ๆ ที่มีอยู่ในโค้ด แน่นอนว่าการเก็บไว้ในซอร์สโค้ดไม่ใช่ความคิดที่ดี แต่สถานการณ์อาจแตกต่างกันไป ต้องขอบคุณคำสั่ง CxQL การค้นหาสิ่งนี้จึงค่อนข้างง่าย:

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

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

ข้อสรุป

ฉันหวังว่าบทความนี้จะเป็นประโยชน์สำหรับผู้ที่เริ่มคุ้นเคยกับเครื่องมือ Checkmarx บางทีผู้ที่เขียนกฎของตนเองมาเป็นเวลานานอาจพบสิ่งที่มีประโยชน์ในคู่มือนี้เช่นกัน

น่าเสียดายที่ขณะนี้ยังขาดทรัพยากรที่สามารถรวบรวมแนวคิดใหม่ๆ ได้ในระหว่างการพัฒนากฎสำหรับ Checkmarx นั่นเป็นเหตุผลที่เราสร้างขึ้น พื้นที่เก็บข้อมูลบน Githubซึ่งเราจะโพสต์ผลงานของเราเพื่อให้ทุกคนที่ใช้ CxQL สามารถค้นพบสิ่งที่มีประโยชน์ในนั้น และยังมีโอกาสแบ่งปันผลงานกับชุมชนอีกด้วย พื้นที่เก็บข้อมูลอยู่ระหว่างการเติมและจัดโครงสร้างเนื้อหา ยินดีต้อนรับผู้ร่วมให้ข้อมูล!

ขอบคุณ!

ที่มา: will.com

เพิ่มความคิดเห็น