1. 背景
ソースコード静的解析ツール(SAST)は、ソフトウェアのセキュリティを保証する重要なツールとして、さまざまな分野で広く活用されています。オープンソースの SAST ツールが広く使用され、ツールの種類が増加しているため、ユーザーはツールの長所と短所、およびエンタープライズ アプリケーションのシナリオに適しているかどうかを判断することが困難になっています。誰もが静的解析ツールを選択するための基礎を提供するために、この記事では、現在の静的コード解析ツールに存在する技術的問題と、ツールの評価の基本的な基準を分析します。
2. 概要
一般に、偽陽性率と偽陰性率は SAST の最も重要な技術評価指標ですが、一般的な意味でのテストセットがないため、静的解析ツールの検出精度や分析の感度が完全に反映されます。したがって、テストの難しさを単純化するために、Java セキュリティ検出機能におけるコード分析ツールの強みを反映するために、この評価には Java 言語と比較的安全な国際一般テスト セット OWASP ベンチマークを選択しました。
OWASP ベンチマークは、11 のカテゴリからの数千の脆弱性を含むサンプル アプリケーションです。ベンチマークには、間接呼び出し、到達不能なブランチ、マップ、構成ファイルに依存する値など、静的分析では処理が困難なコード フラグメントが含まれています。
ユースケースのダウンロード アドレス: github.com/OWASP/Bench…。コード分析ツールの検出機能をある程度反映できます。
1. テストの根拠
次の表は、あるツールの OWASP 検出結果を示しています。図に示すように、左の列はすべてのカテゴリを示し、P/N は陽性/陰性サンプル (badcase/goodcase) の数、TP/FP は数を示します真/偽陽性の数 (悪いケースの報告数/偽陽性の数)、TN/FN は真/偽陰性の数 (良好なケースの報告数/見逃した陰性の数)、TPR と FPR は正解率と偽陽性率、Y はYouden インデックス、Youden Index (Youden's indx、YI) は正しいインデックスであり、このインデックス値の範囲は 0 から 1 のみです。Youden インデックスが大きいほど、その信頼性が高くなります。TPR、FPR、Yの計算式は以下のとおりです。
TPR=TP/P
FPR=FP/N
Y=[TP/(TP+FN)+TN/(FP+TN)]-1
カテゴリー |
P |
N |
TP |
FP |
テネシー州 |
FN |
TPR |
FPR |
Y |
コマンドインジェクション(cmdi) |
126 |
125 |
126 |
45 |
80 |
0 |
1.0 |
0.36 |
0.64 |
弱い暗号 (暗号) |
130 |
116 |
130 |
0 |
116 |
0 |
1.0 |
0.0 |
1.0 |
弱いランダム性 (ハッシュ) |
129 |
107 |
129 |
0 |
107 |
0 |
1.0 |
0.0 |
1.0 |
LDAP インジェクション (ldapi) |
27 |
32 |
27 |
13 |
19 |
0 |
1.0 |
0.41 |
0.59 |
パストラバーサル (パストラバー) |
133 |
135 |
133 |
36 |
99 |
0 |
1.0 |
0.27 |
0.73 |
セキュア Cookie フラグ securecookie) |
36 |
31 |
36 |
0 |
31 |
0 |
1.0 |
0.0 |
1.0 |
SQLインジェクション(sqli) |
272 |
232 |
272 |
87 |
145 |
0 |
1.0 |
0.375 |
0.63 |
信頼境界違反 (trustbound) |
83 |
43 |
83 |
24 |
19 |
0 |
1.0 |
0.56 |
0.44 |
弱いランダム化 (weakrand) |
218 |
275 |
218 |
0 |
275 |
0 |
1.0 |
0.0 |
1.0 |
XPATH インジェクション (xpathi) |
15 |
20 |
15 |
7 |
13 |
0 |
1.0 |
0.35 |
0.65 |
クロスサイトスクリプティング (xss) |
246 |
209 |
246 |
48 |
161 |
0 |
1.0 |
0.23 |
0.77 |
すべての平均 |
1415 |
1325 |
1415 |
290 |
1035 |
0 |
1.0 |
0.23 |
0.77 |
2. 試験結果
选取市场上主流的SAST工具进行测试,本次选取的测试工具涵盖较广,包含国外商业工具、开源工具以及国内自研工具。如SonarQube[1]代码自动审查工具,该工具是开源工具中使用最多的工具,因为开源免费尤其受很多金融企业喜爱;以色列的Checkmarx CxSAST[2],Micro Focus Fortify[3],目前在电力、金融等行业推广较多,是中国市场Java应用最多的工具之一;还有在互联网领域应用的比较广泛的新思科技的Coverity[4]、IBM Appscan[5]。军工领域应用比较广泛的Parasoft的JTest[6]、VeraCode[7]等。下图是10款静态分析工具的OWASP基准测试结果。商业SAST工具01-06包括:Checkmarx CxSAST、Micro Focus Fortify、IBM AppScan Source、Coverity Code Advisor、Parasoft Jtest、SourceMeter[9]和Veracode工具。
分析工具 |
OWASP版本 |
TPR |
FPR |
Y |
FBwfindSecBugs[10] |
1.2 |
0.97 |
0.58 |
0.39 |
SonarQube |
1.2 |
0.5 |
0.17 |
0.33 |
1.2 |
1.0 |
0.12 |
0.88 |
|
SAST-04 |
1.1 |
0.61 |
0.29 |
0.33 |
SAST-06 |
1.1 |
0.85 |
0.52 |
0.33 |
SAST-02 |
1.1 |
0.56 |
0.26 |
0.31 |
SAST-03 |
1.1 |
0.46 |
0.214 |
0.25 |
SAST-05 |
1.1 |
0.48 |
0.29 |
0.19 |
SAST-01 |
1.1 |
0.29 |
0.12 |
0.17 |
PMD |
1.2 |
0.00 |
0.00 |
0.00 |
从上图可知,覆盖率指数最大为1(即100%覆盖,不存在漏报);而误报率最低的指数为0.12,最高为0.58,尚无。
三、技术分析
静态代码分析基本原理:首先将源代码解析为抽象语法树;采用控制流分析、多态分析、指向分析、函数调用分析等多种分析算法对基本分析模型;考虑路径敏感等多种情况,建立符号执行、抽象解释、图可达性等程序模型;根据缺陷模式在程序模型的基础上生成一阶逻辑表达式并采用SMT进行可满足性约束求解,生成最终结果。目前很多工具只做基本分析层面,尤其是开源工具,针对全模式的敏感分析很多工具并不支持,或支持的不好,因此可能产生大量的误漏报,下面分析了几种典型的问题:
基于以上要点,分析误报原因,了解工具的局限性。通过分析,误报基本由以下几种情况导致。
1. 集合覆盖问题
在集合中,部分集合数据存在污染数据,当检索集合中未污染部分时,导致整个集合覆盖污染,误报产生。如:以下代码中,map中填充带有一个污点(param)和一个未污点的值(a_value),并且从映射中检索参数赋值给bar。如果一个集合的一部分被污染了,假设整个collection都被污染,那么在本例中,当我们检索集合的未污染部分时,导致误报。
private class Test {
public String doSomething(String param) throws ServletException, IOException {
String bar = "safe!";
java.util.HashMap map831 = new java.util.HashMap();
map831.put("keyA-831", "a_Value"); // put some stuff in the collection
map831.put("keyB-831", param); // put it in a collection
map831.put("keyC", "another_Value"); // put some stuff in the collection
bar = (String)map831.get("keyB-831"); // get it back out
bar = (String)map831.get("keyA-831"); // get safe value back out
return bar;
}
} // end innerclass Test
2. 集合过度污染问题
在一个集合中,部分集合数据存在污染数据,当对集成做一些操作后,工具无法识别出受污染的数据,导致其他正常数据收到影响,产生误报。如:在以下代码中,存在一个未受污染的值(safe),一个受污染的值(param) 和另一个未受污染的值(moresafe) 被添加到列表中。 当第一个值“safe”被删除后,从列表的开头,检索索引为 1 的列表元素,即读取未受污染的值“moresafe”。同样导致误报。
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
String param = "";
boolean flag = true;
java.util.Enumeration names = request.getParameterNames();
while (names.hasMoreElements() && flag) {
String name = (String) names.nextElement();
String[] values = request.getParameterValues(name);
if (values != null) {
for(int i=0;i<values.length && flag; i++){
String value = values[i];
if (value.equals("vector")) {
param = name;
flag = false;
}
}
}
}
String bar = "alsosafe";
if (param != null) {
java.util.List valuesList = new java.util.ArrayList( );
valuesList.add("safe");
valuesList.add( param );
valuesList.add( "moresafe" );
valuesList.remove(0); // remove the 1st safe value
bar = valuesList.get(1); // get the last 'safe' value
}
String cmd = org.owasp.benchmark.helpers.Utils.getInsecureOSCommandString(this.getClass().getClassLoader());
String[] args = {cmd};
String[] argsEnv = { bar };
Runtime r = Runtime.getRuntime();
try {
Process p = r.exec(args, argsEnv, new java.io.File(System.getProperty("user.dir")));
org.owasp.benchmark.helpers.Utils.printOSCommandResults(p, response);
} catch (IOException e) {
System.out.println("Problem executing cmdi - TestCase");
throw new ServletException(e);
}
}
3. 分支问题
在条件分支中,由于条件设置问题,导致某些分支可能永远无法执行,若工具无法判定某些无法执行的分支,可能导致误报的产生。如:在以下代码中,因为num为常量106,(7*18)+num的值永远大于200,导致bar的值始终都为常量字符串,“This_should_always_happen”。另外一个包含污染数据的分支“param”永远无法执行。导致工具产生误报。
private class Test {
public String doSomething(String param) throws ServletException, IOException {
String bar;// Simple ? condition that assigns constant to bar on true condition
int num = 106;
bar = (7*18) + num > 200 ? "This_should_always_happen" : param;
return bar;
}
}
四、结论
全面、高效地静态识别漏洞,减少工具的误报是静态分析中至关重要的技术,目前在该领域中,仍然有很大的进步空间。针对本次OWASP的基准测试,在选取的工具中,目前结果最好的工具覆盖率可以达到100%,且同时误报率为12%,也说明了工具正不断趋于成熟,但该结果仅针对OWASP测试用例。在后续的静态代码分析技术中,需要不断对静态数据流跟踪器进行持续优化,以此提高检测精度。
为了更好地对代码分析工具进行评价,笔者提出了几个评价维度,并给出评价等级:
评价指标 |
描述 |
Level 1 |
Level 2 |
Level 3 |
约登指数 |
查全率-误报 |
0.9-1.0 |
0.7-0.9 |
0.7- |
吞吐量 |
最大检测代码规模 |
1000W+ |
100W+ |
10W+ |
检测效率 |
每小时代码检测代码行数 |
100W+ |
50W+ |
10W+ |
片段代码检测能力 |
能否在编译不通过情况下检测 |
支持所有语言 |
C/C++,Java |
不支持 |
并发检测能力 |
支持单CPU的多并发测试 |
硬件允许的最大值 |
单进程 |
单进程 |
跨语言及框架分析能力 |
支持最新的框架及兼容语言间调用 |
支持70种以上框架 |
支持10种以下 |
不支持 |
支持语言 |
支持检测的语言种类 |
20种+ |
10种+ |
3种+ |
与Devops集成能力 |
是否与DevOps主要工具集成 |
支持持续集成工具、版本管理及测试工具,三个方面 |
仅支持版本管理 |
不支持 |
CWE模式覆盖数 |
覆盖的缺陷模式个数 |
200+ |
100+ |
50+ |