JSONルールでカスタマイズ可能なJavaバイトコードアナライザ。これはコマンドラインツールで、1つ以上のJarまたはWarファイルを含むパスを受け取り、提供されたルールを使用して解析し、結果のHTMLレポートを生成します。
usage: java -jar cba-cli.jar [OPTIONS] -a DIRECTORY_TO_ANALYZE
-a,--analyze <pathToAnalyze> 解析を実行するディレクトリのパス。
-c,--checks <checks...> 解析で実行されるカスタムチェックのスペース区切りリスト。
-f,--custom-file <customFile> カスタムルールを実行するためのJSON形式のファイルを指定。
詳細は https://github.com/fergarrui/custom-bytecode-analyzer を参照。
-h,--help このメッセージを表示。
-i,--items-report <maxItems> レポートあたりの最大アイテム数。この値を超える問題が見つかった場合、
レポートは複数のファイルに分割されます。レポートに多くの問題が予想される場合に便利です。デフォルト: 50。
-o,--output <outputDir> レポートを保存するディレクトリ。警告 - このディレクトリに既存のレポートがある場合、
上書きされます。デフォルトは "report"。
-v,--verbose-debug 詳細度をデバッグモードに増加。
-vv,--verbose-trace 詳細度をトレースモードに増加 - 処理が遅くなるため、必要な場合のみ使用。
ルールファイルは -f,--custom-file 引数で指定できます。ファイルはJSON形式で、以下の構造を持ちます。
final の場合のみサポートまた、net.nandgr.cba.custom.model.Rules.java をチェックすると、Javaコードでの構造を確認できます。
examples ディレクトリの下にすでにいくつかのルールがあります。以下に、各ルールの例を示します。
カスタムデシリアライゼーションを持つクラスを見つける必要がある場合、それは非常に簡単に行えます。クラスは private void readObject(ObjectInputStream in) を実装することでカスタムデシリアライゼーションを定義します。そのため、そのメソッドが定義されているすべてのクラスを見つければ十分です。ルールを次のように定義するだけで十分です。
{
"rules": [{
"name": "Custom deserialization",
"methods": [{
"name": "readObject",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectInputStream"
}]
}]
}]
}
これは、private 可視性、readObject という名前、および java.io.ObjectOutputStream 型のパラメータを持つメソッドを報告します。パラメータは配列であり、複数指定された場合、すべてが一致する必要があります。ルールは1つだけなので、custom-deserialization-0.html という名前のレポートが作成されます。
この場合、2つのメソッドを持つ1つのルールを定義する必要があります。デシリアライゼーションについては前の例と同じものを、そして private void writeObject(ObjectOutputStream out) に一致する新しいものを定義します。上記のJSON構造に示されているように、プロパティ rules.rule.methods はメソッドの配列であるため、次のようなルールを記述できます。
{
"rules": [{
"name": "Custom serialization and deserialization",
"methods": [{
"name": "readObject",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectInputStream"
}]
},{
"name": "writeObject",
"report": "false",
"visibility": "private",
"parameters" : [{
"type" : "java.io.ObjectOutputStream"
}]
}]
}]
}
report プロパティを false に設定することで、同じルールで2回報告されるのを防ぎます。2番目のメソッドは条件としてのみ使用し、readObject メソッドのみを報告することで、このルールの目的には十分です。
プロパティが定義されていない場合、常に true として一致します。例えば、このルールはすべてのメソッド定義を返します。
{
"rules": [{
"name": "Method definitions",
"methods": [{
}]
}]
}
メソッド呼び出しも見つけることができます。この場合のJSONは次のようになります。
{
"rules": [{
"name": "String equals",
"invocations": [{
"owner": "java.lang.String",
"method": {
"name": "equals"
}
}]
}]
}
owner プロパティは、メソッドを含むクラスを指定します。
前の例よりももう少し便利なメソッド呼び出しの別の例です。
{
"rules": [{
"name": "Method invocation by reflection",
"invocations": [{
"owner": "java.lang.reflect.Method",
"method": {
"name": "invoke"
}
}]
}]
}
これはメソッド呼び出しと同じですが、この場合のメソッド名は <init> である必要があります。
{
"rules": [{
"name" : "String instantiation",
"invocations" : [{
"owner" : "java.lang.String",
"method" : {
"name" : "<init>"
}
}]
}]
}
このルールは、次のようなコードを見つけます。
[...]
String s = new String("foo");
[...]
この例では、デシリアライゼーションの使用法(前の例のようにシリアライゼーション動作を定義するクラスではなく)を見つけたいとします。デシリアライゼーションは、ObjectInputStream.readObject() が呼び出されたときに発生します。例えば、次のコードスニペットです。
ObjectInputStream in = new ObjectInputStream(fileInputStream);
Object o = in.readObject();
そのため、ObjectInputStream からの readObject という名前のメソッド呼び出しを見つける必要があります。しかし、リサーチの文脈では多くの誤検出が見つかるでしょう。なぜなら、クラスがカスタムデシリアライゼーションを定義する場合、private void readObject(ObjectInputStream in) メソッド内でこのメソッドを呼び出すため、レポートが汚染されすぎてしまうからです。これらのケースを除外して、真のデシリアライゼーションのみを保持したい場合、notFrom プロパティを使用できます。
{
"rules": [{
"name": "Deserialization usage",
"invocations": [{
"owner": "java.io.ObjectInputStream",
"method": {
"name": "readObject"
},
"notFrom": {
"name": "readObject",
"visibility": "private"
}
}]
}]
}
このファイルは、呼び出しが private void readObject(ObjectInputStream in) メソッド内で行われていない場合に、java.io.ObjectInputStream.readObject() 呼び出しを見つけます。
以下のコードでコンパイルされたクラスは報告されません。
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Object o = in.readObject();
}
しかし、こちらは報告されます。
public Object deserializeObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
Object o = in.readObject();
return o;
}
from プロパティは、notFrom とまったく同じ方法で呼び出しに設定できますが、結果は逆になります。定義されたメソッドから呼び出しが行われた場合にのみ一致します。
この場合、superClass プロパティを使用できます。javax.servlet.http.HttpServlet を拡張するすべてのクラスを見つけたい場合、ルールは次のようになります。
{
"rules": [{
"name": "Java servlets",
"superClass" : "javax.servlet.http.HttpServlet"
}]
}
インターフェースの配列を実装するクラスを見つけるためのルールを書くことができます。ルールに複数のインターフェースが定義されている場合、クラスはそのすべてを実装している必要があります。javax.net.ssl.X509TrustManager を実装するクラスを見つけたい場合、ルールは次のようになります。
{
"rules": [{
"name": "X509TrustManager implementations",
"interfaces" : ["javax.net.ssl.X509TrustManager"]
}]
}
interfaces は 配列 であることに注意してください。文字列を角括弧で囲んで追加してください。例: ["interface1", "interface2", ...]。