เฮ้ ฮับ!
ในงานของเรา บริษัทของเรามักจะเกี่ยวข้องกับเครื่องมือวิเคราะห์โค้ดแบบคงที่ (SAST) ต่างๆ บ่อยครั้ง นอกกรอบพวกเขาทั้งหมดทำงานโดยเฉลี่ย แน่นอนว่าทุกอย่างขึ้นอยู่กับโครงการและเทคโนโลยีที่ใช้ในโครงการ ตลอดจนกฎการวิเคราะห์ที่ครอบคลุมเทคโนโลยีเหล่านี้ได้ดีเพียงใด ในความคิดของฉัน หนึ่งในเกณฑ์ที่สำคัญที่สุดในการเลือกเครื่องมือ SAST คือความสามารถในการปรับแต่งให้เข้ากับลักษณะเฉพาะของแอปพลิเคชันของคุณ กล่าวคือ เขียนและเปลี่ยนแปลงกฎการวิเคราะห์ หรือที่มักเรียกว่า Custom Queries
เรามักใช้ Checkmarx ซึ่งเป็นเครื่องมือวิเคราะห์โค้ดที่น่าสนใจและทรงพลังมาก ในบทความนี้ ผมจะพูดถึงประสบการณ์ของผมในการเขียนกฎการวิเคราะห์
สารบัญ
การเข้า
ขั้นแรก ฉันอยากจะแนะนำหนึ่งในไม่กี่บทความในภาษารัสเซียเกี่ยวกับคุณสมบัติของการเขียนข้อความค้นหาสำหรับ Checkmarx เผยแพร่บนHabréเมื่อปลายปี 2019 ภายใต้ชื่อ:
โดยจะตรวจสอบรายละเอียดวิธีเขียนแบบสอบถามแรกใน CxQL (Checkmarx Query Language) สำหรับแอปพลิเคชันทดสอบบางรายการ และแสดงหลักการพื้นฐานของวิธีการทำงานของกฎการวิเคราะห์
ฉันจะไม่ทำซ้ำสิ่งที่อธิบายไว้ในนั้นแม้ว่าทางแยกบางส่วนจะยังคงอยู่ก็ตาม ในบทความของฉัน ฉันจะพยายามรวบรวม "คอลเลกชันสูตรอาหาร" รายการวิธีแก้ไขปัญหาเฉพาะที่ฉันพบระหว่างทำงานกับ Checkmarx ฉันต้องระดมสมองกับปัญหามากมายเหล่านี้ บางครั้งมีข้อมูลไม่เพียงพอในเอกสาร และบางครั้งก็ยากที่จะเข้าใจว่าต้องทำอย่างไร ฉันหวังว่าประสบการณ์และการนอนไม่หลับของฉันจะไม่สูญเปล่า และ "คอลเลกชันสูตรการค้นหาที่กำหนดเอง" นี้จะช่วยคุณประหยัดเวลาได้สองสามชั่วโมงหรือสองสามเซลล์ เอาล่ะ มาเริ่มกันเลย!
ข้อมูลทั่วไปเกี่ยวกับกฎเกณฑ์
ขั้นแรก มาดูแนวคิดพื้นฐานบางประการและกระบวนการทำงานกับกฎ เพื่อความเข้าใจที่ดีขึ้นว่าจะเกิดอะไรขึ้นต่อไป และเนื่องจากเอกสารไม่ได้พูดอะไรเกี่ยวกับเรื่องนี้หรือมีโครงสร้างกระจายออกไปมากนักซึ่งไม่สะดวกนัก
-
กฎจะถูกใช้ในระหว่างการสแกน ขึ้นอยู่กับการตั้งค่าล่วงหน้าที่เลือกเมื่อเริ่มต้น (ชุดของกฎที่ใช้งานอยู่) คุณสามารถสร้างค่าที่ตั้งไว้ล่วงหน้าได้ไม่จำกัดจำนวน และวิธีการจัดโครงสร้างค่าที่ตั้งล่วงหน้าจะขึ้นอยู่กับลักษณะเฉพาะของกระบวนการของคุณ คุณสามารถจัดกลุ่มตามภาษาหรือเลือกค่าที่ตั้งไว้ล่วงหน้าสำหรับแต่ละโปรเจ็กต์ จำนวนกฎที่ใช้งานอยู่จะส่งผลต่อความเร็วและความแม่นยำของการสแกน
การตั้งค่าล่วงหน้าในอินเทอร์เฟซ Checkmarx
-
กฎได้รับการแก้ไขด้วยเครื่องมือพิเศษที่เรียกว่า CxAuditor นี่คือแอปพลิเคชันเดสก์ท็อปที่เชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้ Checkmarx เครื่องมือนี้มีโหมดการทำงานสองโหมด: การแก้ไขกฎและการวิเคราะห์ผลลัพธ์ของการสแกนที่ดำเนินการไปแล้ว
อินเทอร์เฟซ CxAudit
-
กฎใน Checkmarx แบ่งตามภาษา กล่าวคือ แต่ละภาษาจะมีชุดคำถามของตัวเอง นอกจากนี้ยังมีกฎทั่วไปบางประการที่ใช้โดยไม่คำนึงถึงภาษา ซึ่งเรียกว่าข้อความค้นหาพื้นฐาน โดยส่วนใหญ่แล้ว ข้อความค้นหาพื้นฐานจะเกี่ยวข้องกับการค้นหาข้อมูลที่กฎอื่นใช้
การแบ่งกฎเกณฑ์ตามภาษา
-
กฎคือ "ปฏิบัติการได้" และ "ไม่ปฏิบัติการได้" (ดำเนินการแล้วและไม่ดำเนินการ) ในความคิดของฉันไม่ใช่ชื่อที่ถูกต้องนัก แต่นั่นคือสิ่งที่เป็นอยู่ สิ่งที่สำคัญที่สุดคือผลลัพธ์ของการดำเนินการกฎ "ที่ปฏิบัติการได้" จะแสดงในผลลัพธ์การสแกนใน UI และกฎที่ "ไม่ปฏิบัติการได้" จำเป็นเพื่อใช้ผลลัพธ์ในคำขออื่น ๆ เท่านั้น (โดยพื้นฐานแล้วเป็นเพียงฟังก์ชัน)
การกำหนดประเภทกฎเมื่อสร้าง
-
คุณสามารถสร้างกฎใหม่หรือเสริม/เขียนกฎที่มีอยู่ใหม่ได้ หากต้องการเขียนกฎใหม่ คุณต้องค้นหากฎนั้นในแผนผัง คลิกขวาและเลือก "แทนที่" จากเมนูแบบเลื่อนลง สิ่งสำคัญคือต้องจำไว้ว่ากฎใหม่ไม่ได้รวมอยู่ในค่าที่ตั้งล่วงหน้าในตอนแรกและไม่ได้ใช้งานอยู่ หากต้องการเริ่มใช้งาน คุณต้องเปิดใช้งานในเมนู "Preset Manager" ในเครื่องมือ กฎที่เขียนใหม่จะคงการตั้งค่าไว้ กล่าวคือ หากกฎนั้นทำงานอยู่ กฎนั้นก็จะยังคงอยู่และจะถูกนำไปใช้ทันที
ตัวอย่างกฎใหม่ในอินเทอร์เฟซ Preset Manager
-
ในระหว่างการดำเนินการ จะมีการสร้าง "แผนผัง" ของคำขอซึ่งขึ้นอยู่กับอะไร กฎที่รวบรวมข้อมูลจะถูกดำเนินการก่อนและผู้ที่ใช้ข้อมูลนั้นเป็นอันดับสอง ผลลัพธ์การดำเนินการจะถูกแคชไว้ ดังนั้น หากเป็นไปได้ที่จะใช้ผลลัพธ์ของกฎที่มีอยู่ ก็ควรทำเช่นนั้น ซึ่งจะทำให้เวลาในการสแกนลดลง
-
สามารถใช้กฎเกณฑ์ได้ในระดับต่างๆ:
-
สำหรับทั้งระบบ - จะถูกใช้สำหรับการสแกนโปรเจ็กต์ใดๆ
-
ในระดับทีม (ทีม) - จะถูกใช้เพื่อสแกนโครงการในทีมที่เลือกเท่านั้น
-
ในระดับโครงการ - จะถูกนำไปใช้ในโครงการเฉพาะ
การกำหนดระดับที่จะใช้กฎ
“พจนานุกรม” สำหรับผู้เริ่มต้น
ฉันจะเริ่มต้นด้วยบางสิ่งที่ทำให้เกิดคำถามในใจ และจะแสดงเทคนิคต่างๆ ที่จะทำให้ชีวิตง่ายขึ้นอย่างมาก
การดำเนินการกับรายการ
- вычитание одного из другого (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 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 ไม่ได้รู้เกี่ยวกับการมีอยู่ของมันเสมอไป และงานของเราคือสอนให้เข้าใจว่าวิธีการบางอย่างเป็นของกรอบการทำงานนี้โดยเฉพาะ บางครั้งสิ่งนี้อาจซับซ้อนเนื่องจากข้อเท็จจริงที่ว่าเฟรมเวิร์กใช้ชื่อฟังก์ชันที่ธรรมดามากและเป็นไปไม่ได้ที่จะระบุความสัมพันธ์ของการเรียกเฉพาะไปยังไลบรารีเฉพาะอย่างไม่คลุมเครือ
ปัญหาคือไวยากรณ์ของไลบรารีดังกล่าวไม่ได้รับการจดจำอย่างถูกต้องเสมอไป และคุณต้องทดลองเพื่อหลีกเลี่ยงไม่ให้ได้รับผลบวกลวงจำนวนมาก มีหลายตัวเลือกในการปรับปรุงความแม่นยำในการสแกนและแก้ไขปัญหา:
-
ตัวเลือกแรก เรารู้แน่ว่าไลบรารีนั้นถูกใช้ในโปรเจ็กต์เฉพาะและสามารถใช้กฎในระดับทีมได้ แต่ถ้าทีมตัดสินใจที่จะใช้แนวทางที่แตกต่างออกไปหรือใช้หลายไลบรารีที่ชื่อฟังก์ชันทับซ้อนกัน เราจะได้ภาพที่ไม่น่าพึงพอใจของผลบวกลวงจำนวนมาก
-
ตัวเลือกที่สองคือการค้นหาไฟล์ที่มีการนำเข้าไลบรารีอย่างชัดเจน ด้วยวิธีนี้ เราจึงมั่นใจได้ว่าไลบรารีที่เราต้องการจะถูกใช้ในไฟล์นี้ทุกประการ
-
และทางเลือกที่สามคือการใช้สองวิธีข้างต้นร่วมกัน
ตัวอย่างเช่น ลองดูห้องสมุดที่มีชื่อเสียงในวงแคบๆ $
ซึ่งแทนที่ข้อมูลลงในแบบสอบถาม 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 นั่นเป็นเหตุผลที่เราสร้างขึ้น
ขอบคุณ!
ที่มา: will.com