こんにちは、Habr!
その作業において、当社はさまざまな静的コード分析ツール(SAST)を頻繁に扱っています。箱から出して、それらはすべて平均的に機能します。もちろん、それはすべて、プロジェクトとその中で使用されているテクノロジー、およびこれらのテクノロジーが分析ルールによってどの程度カバーされているかによって異なります。私の意見では、SASTツールを選択する際の最も重要な基準の1つは、アプリケーションの詳細に合わせてツールをカスタマイズする機能です。つまり、分析ルールを作成および変更するか、カスタムクエリと呼ばれることがよくあります。
私たちはほとんどの場合、非常に興味深く強力なコードアナライザーであるCheckmarxを使用します。この記事では、その分析ルールを作成した経験を共有します。
目次
, Checkmarx. 2019 : «Hello, Checkmarx!». Checkmarx SAST .
, CxQL (Checkmarx Query Language) .
, , - . “ ”, , Checkmarx. . , , , . , , “ Custom Queries ” - . , !
, , . , .
( ). . . .
CxAuditor. , Checkmarx. : .
Checkmarx , . , , . , , .
“Executable” “Non-Executable” ( ). , , . , “Executable” UI, “Non-Executable” ( - ).
/ . , , , “Override“. , . “Preset Manager” . , , , .
“” , . , , , . , , , .
:
-
(Team) - .
-
““
, , , .
- (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!
!