Wie man Regeln für Checkmarx schreibt und nicht verrückt wird

Hallo Habr!

In seiner Arbeit beschäftigt sich unser Unternehmen sehr häufig mit verschiedenen statischen Code-Analyse-Tools (SAST). Nach dem Auspacken arbeiten alle durchschnittlich. Natürlich hängt alles vom Projekt und den darin verwendeten Technologien ab sowie davon, wie gut diese Technologien von den Analyseregeln abgedeckt werden. Meiner Meinung nach ist eines der wichtigsten Kriterien bei der Auswahl eines SAST-Tools die Möglichkeit, es an die Besonderheiten Ihrer Anwendungen anzupassen, nämlich Analyseregeln zu schreiben und zu ändern oder, wie sie oft genannt werden, benutzerdefinierte Abfragen.

Wir verwenden am häufigsten Checkmarx - einen sehr interessanten und leistungsstarken Code-Analysator. In diesem Artikel werde ich meine Erfahrungen mit dem Schreiben von Analyseregeln dafür teilen.

Inhaltsverzeichnis

, Checkmarx. 2019 : «Hello, Checkmarx!». Checkmarx SAST .

, CxQL (Checkmarx Query Language) .

, , - . “ ”, , Checkmarx. . , , , . , , “ Custom Queries ” - . , !

, , . , .

  1. ( ). . . .

    Voreinstellung in der Checkmarx-Oberfläche
    Preset Checkmarx
  2. CxAuditor. , Checkmarx. : .

    CxAudit-Schnittstelle
    CxAudit
  3. Checkmarx , . , , . , , .

    Trennung der Regeln nach Sprache
  4. “Executable” “Non-Executable” ( ). , , . , “Executable” UI, “Non-Executable” ( - ).

    Definieren des Regeltyps beim Erstellen
  5. / . , , , “Override“. , . “Preset Manager” . , , , .

    Ein Beispiel für eine neue Regel in der Preset Manager-Oberfläche
    Preset Manager
  6. “” , . , , , . , , , .

  7. :

  • -

  • (Team) - .

  • -

    Festlegen der Ebene, auf der die Regel angewendet wird
    ,

““

, , , .

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

Flow

, :

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

, result - , :

//   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 Queries . , , , .

, :

: Flow , .

: , Checkmarx Flow , . ReduceFlow. Flow:

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

:

: , .

Password_privacy_violation_list

CxList allStrings = All.FindByType("String"); 
allStrings.Add(All.FindByType(typeof(StringLiteral))); 
allStrings.Add(Find_UnknownReference());
allStrings.Add(All.FindByType(typeof (Declarator)));
allStrings.Add(All.FindByType(typeof (MemberAccess)));
allStrings.Add(All.FindByType(typeof(EnumMemberDecl))); 
allStrings.Add(Find_Methods().FindByShortName("get*"));

//    
List < string > pswdIncludeList = new List<string>{"*password*", "*psw", "psw*", "pwd*", "*pwd", "*authKey*", "pass*", "cipher*", "*cipher", "pass", "adgangskode", "benutzerkennwort", "chiffre", "clave", "codewort", "contrasena", "contrasenya", "geheimcode", "geslo", "heslo", "jelszo", "kennwort", "losenord", "losung", "losungswort", "lozinka", "modpas", "motdepasse", "parol", "parola", "parole", "pasahitza", "pasfhocal", "passe", "passord", "passwort", "pasvorto", "paswoord", "salasana", "schluessel", "schluesselwort", "senha", "sifre", "wachtwoord", "wagwoord", "watchword", "zugangswort", "PAROLACHIAVE", "PAROLA CHIAVE", "PAROLECHIAVI", "PAROLE CHIAVI", "paroladordine", "verschluesselt", "sisma",
                "pincode",
								"pin"};
								
List < string > pswdExcludeList = new List<string>{"*pass", "*passable*", "*passage*", "*passenger*", "*passer*", "*passing*", "*passion*", "*passive*", "*passover*", "*passport*", "*passed*", "*compass*", "*bypass*", "pass-through", "passthru", "passthrough", "passbytes", "passcount", "passratio"};

CxList tempResult = allStrings.FindByShortNames(pswdIncludeList, false);
CxList toRemove = tempResult.FindByShortNames(pswdExcludeList, false);
tempResult -= toRemove;
tempResult.Add(allStrings.FindByShortName("pass", false));

foreach (CxList r in tempResult)
{
	CSharpGraph g = r.data.GetByIndex(0) as CSharpGraph;
	if(g != null && g.ShortName != null && g.ShortName.Length < 50)
	{
		result.Add(r);
	}
}

: , 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, :

FindAndroidOutputs

//     
result = base.Find_Android_Outputs();

//  ,     Timber
CxList timber = All.FindByExactMemberAccess("Timber.*") +
    All.FindByShortName("Timber").GetMembersOfTarget();

//    
result.Add(timber);

, Android:

FindAndroidLog_Outputs

//     
result = base.Find_Android_Log_Outputs();

//  ,     Timber
result.Add(
  All.FindByExactMemberAccess("Timber.*") +
  All.FindByShortName("Timber").GetMembersOfTarget()
);

, Android- WorkManager , Checkmarx, getInputData:

FindAndroidRead

//     
result = base.Find_Android_Read();

//    getInputData,    WorkManager
CxList getInputData = All.FindByShortName("getInputData");

//    
result.Add(getInputData.GetMembersOfTarget());

: plist iOS

: iOS .plist. , , , .

plist , , Checkmarx. , , - .

, backend:

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

  • "cleartextTrafficPermitted"- xml

  • "true" -

  • false -

  • true - , , case-insensitive

, , , 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:

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

Android , , .


: ,

: , . , Checkmarx , . , , .

, , . , :

  • , , . , ,

  • , , . ,

  • , .

slick Scala, , Splicing Literal Values. , SQL- $, SQL-. , Prepared Statement 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));
}

: Open-Source

: Open-Source ( 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, - , . , contributors are welcome!

!




All Articles