例 2: ソースからシンクへの変更
例 2 は、例 1 のコードを変更したものです。検証ルーチンの getVulnerableSource
と、writeToVulnerableSink
で呼び出されるエンコード・ルーチンを追加することで、例 1 を改善しています。
import java.io.*;
public class TestCase_IOT_Instance_Val_Encode {
public static void main(String[] args) {
try {
TestCase_IOT_Instance_Val_Encode testCase = new
TestCase_IOT_Instance_Val_Encode();
String file = args[0];
String source = testCase.getVulnerableSource(file);
source = testCase.validate(source);
String encodedStr = testCase.encode(source);
testCase.writeToVulnerableSink(file, encodedStr);
} catch (Exception e) {
}
}
public String getVulnerableSource(String file) throws Exception {
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[100];
fis.read(buf);
fis.close();
String ret = new String(buf);
return ret;
}
public void writeToVulnerableSink(String file, String str)
throws FileNotFoundException {
FileOutputStream fos = new FileOutputStream(file);
PrintWriter writer = new PrintWriter(fos);
writer.write(str);
}
private String validate(String source) throws Exception {
if (source.length() > 100) {
throw new Exception("Length too long: " + source.length());
}
return source;
}
private String encode(String source) {
return source.trim();
}
}
最初のスキャンで、例 1 と同様のスタック・トレースが生成されます。
Knowledgebase を拡張して検証ルーチンとエンコード・ルーチンを組み込むことにより、検出結果内の不要な情報を削除し、すべての呼び出しグラフについて検証ルーチンとエンコード・ルーチンが呼び出されているかどうかを確認することができます。例えば、例 1 で java.io.FileInputStream.read(byte[]):int
に対するすべての呼び出しからのデータを指定した場合、スキャンは read
からのすべての呼び出しを除去します。これは、read もこの検証ルーチンを呼び出すためです。また、カスタム検証メソッドを呼び出さなかった read
からの呼び出しの状況は、「確定」セキュリティー検出結果に引き上げられます。これは、コード内の既知の検証メソッドを呼び出さなかった場合、悪質な攻撃を受ける可能性があるためです。
検証ルーチンは、FileInputStream
の read
メソッドの他のバリエーションを検証することもできます。これらは追加のソースとして指定することもできます。加えて、特定のシンク (つまり、特定のプロパティーを持つシンク) のみをこのメソッドで検証されるように指定することもできます。例えば、このルーチンを、Technology.IO
プロパティーを持つシンク (このサンプル・データを取り込むのに使用される PrintWriter.write
シンクなど) に制限できます。