[実験] 静的コード解析ツールはどの程度バグや脆弱性を検出できるのか？ ～ SonarQube編

**静的コード解析ツールはバグや脆弱性をどの程度検出できるのでしょうか？**

[前回](http://qiita.com/tamura__246/items/da50983ca8ff94c6b6ac)、FindBugsで[バグだらけのWebアプリケーション](http://qiita.com/tamura__246/items/7275c7406706fb0057e8)を解析してみましたが、今回は**SonarQube**で解析してみました。

![mainsq.png](https://qiita-image-store.s3.amazonaws.com/0/43869/a6616d8f-6209-a3f6-c641-bb44d99b6a70.png)


## 検証内容

バグだらけのWebアプリケーション([EasyBuggy 1.3.3](https://github.com/k-tamura/easybuggy/releases/tag/1.3.3))が、現在実装済みのバグや脆弱性は以下の80種類です。

**障害**

 - デッドロック (Java)
 - デッドロック (SQL)
 - 完了しないプロセスの待機
 - 無限ループ
 - メモリリーク (Javaヒープ領域)
 - メモリリーク (Permanent領域)
 - メモリリーク (Cヒープ領域)
 - ネットワークソケットリーク
 - データベースコネクションリーク 
 - ファイルディスクリプタリーク 
 - スレッドリーク
 - 文字化け
 - 整数オーバーフロー
 - 丸め誤差
 - 打ち切り誤差
 - 情報落ち

**脆弱性**

 - XSS (クロスサイトスクリプティング)
 - SQLインジェクション
 - LDAPインジェクション
 - コードインジェクション
 - OSコマンドインジェクション
 - メールヘッダーインジェクション
 - Nullバイトインジェクション
 - サイズ制限の無いファイルアップロード
 - 拡張子制限の無いファイルアップロード
 - オープンリダイレクト可能なログイン画面
 - ブルートフォース攻撃可能なログイン画面
 - セッション固定攻撃可能なログイン画面
 - 親切過ぎる認証エラーメッセージ
 - 危険なファイルインクルード
 - パストラバーサル
 - 意図しないファイル公開
 - CSRF (クロスサイトリクエストフォージェリ)
 - クリックジャッキング
 - XEE (XMLエンティティ拡張)
 - XXE (XML外部エンティティ)
 - 正規表現解析による遅延
 - プラス演算子による文字列結合の遅延
 - 不必要なオブジェクト生成による遅延

**エラー**

 - AssertionError
 - ExceptionInInitializerError
 - FactoryConfigurationError
 - GenericSignatureFormatError
 - NoClassDefFoundError
 - OutOfMemoryError (Java heap space)
 - OutOfMemoryError (Requested array size exceeds VM limit)
 - OutOfMemoryError (unable to create new native thread)
 - OutOfMemoryError (GC overhead limit exceeded)
 - OutOfMemoryError (PermGen space)
 - OutOfMemoryError (Direct buffer memory)
 - StackOverflowError
 - TransformerFactoryConfigurationError
 - UnsatisfiedLinkError

**例外**

 - ArithmeticException
 - ArrayIndexOutOfBoundsException
 - ArrayStoreException
 - BufferOverflowException
 - BufferUnderflowException
 - CannotRedoException
 - CannotUndoException
 - ClassCastException
 - ConcurrentModificationException
 - EmptyStackException
 - IllegalArgumentException
 - IllegalMonitorStateException
 - IllegalPathStateException
 - IllegalStateException
 - IllegalThreadStateException
 - ImagingOpException
 - IndexOutOfBoundsException
 - InputMismatchException
 - MalformedParameterizedTypeException
 - MissingResourceException
 - NegativeArraySizeException
 - NoSuchElementException
 - NullPointerException
 - NumberFormatException
 - SecurityException
 - UnsupportedCharsetException
 - UnsupportedOperationException

SonarQube 6.3はどの程度の問題を検出できるのでしょうか？

## 結果

結果は以下のようになりました(SonarQubeでの検証結果とともに、同じソースコードをFindBugsで検証した結果も載せています)。

|バグ|SonarQube|FindBugs(分析力最大)|
--------|--------|--------
|デッドロック (Java)|×|×|
|デッドロック (SQL)|×|×|
|完了しないプロセスの待機|×|×|
|無限ループ|○|×|
|メモリリーク (Javaヒープ領域)|×|×|
|メモリリーク (Permanent領域)|×|×|
|メモリリーク (Cヒープ領域)|×|×|
|ネットワークソケットリーク|×|×|
|データベースコネクションリーク |○|○|
|ファイルディスクリプタリーク |○|○|
|スレッドリーク|×|×|
|文字化け|×|×|
|整数オーバーフロー|×|×|
|丸め誤差|×|×|
|打ち切り誤差|×|×|
|情報落ち|×|×|
|XSS (クロスサイトスクリプティング)|×|×|
|SQLインジェクション|○|○|
|LDAPインジェクション|×|×|
|コードインジェクション|×|×|
|OSコマンドインジェクション|×|×|
|メールヘッダーインジェクション|×|×|
|Nullバイトインジェクション|×|×|
|サイズ制限の無いファイルアップロード|×|×|
|拡張子制限の無いファイルアップロード|×|×|
|オープンリダイレクト可能なログイン画面|×|×|
|ブルートフォース攻撃可能なログイン画面|×|×|
|セッション固定攻撃可能なログイン画面|×|×|
|親切過ぎる認証エラーメッセージ|×|×|
|危険なファイルインクルード|×|×|
|パストラバーサル|×|×|
|意図しないファイル公開|×|×|
|CSRF (クロスサイトリクエストフォージェリ)|×|×|
|クリックジャッキング|×|×|
|XEE (XMLエンティティ拡張)|×|×|
|XXE (XML外部エンティティ)|×|×|
|正規表現解析による遅延|×|×|
|プラス演算子による文字列結合の遅延|○|○|
|不必要なオブジェクト生成による遅延|×|×|
|AssertionError|×|×|
|ExceptionInInitializerError / NoClassDefFoundError|×|×|
|FactoryConfigurationError|×|×|
|GenericSignatureFormatError|×|×|
|NoClassDefFoundError|×|×|
|OutOfMemoryError (Java heap space)|×|×|
|OutOfMemoryError (Requested array size exceeds VM limit)|×|×|
|OutOfMemoryError (unable to create new native thread)|×|×|
|OutOfMemoryError (GC overhead limit exceeded)|×|×|
|OutOfMemoryError (PermGen space)|×|×|
|OutOfMemoryError (Direct buffer memory)|×|×|
|StackOverflowError|×|×|
|TransformerFactoryConfigurationError|×|×|
|UnsatisfiedLinkError|×|×|
|ArithmeticException|○|×|
|ArrayIndexOutOfBoundsException|×|×|
|ArrayStoreException|×|×|
|BufferOverflowException|×|×|
|BufferUnderflowException|×|×|
|CannotRedoException|×|×|
|CannotUndoException|×|×|
|ClassCastException|×|×|
|ConcurrentModificationException|×|×|
|EmptyStackException|×|×|
|IllegalArgumentException|×|×|
|IllegalMonitorStateException|×|×|
|IllegalPathStateException|×|×|
|IllegalStateException|×|×|
|IllegalThreadStateException|×|×|
|ImagingOpException|×|×|
|IndexOutOfBoundsException|×|×|
|InputMismatchException|×|×|
|MalformedParameterizedTypeException|×|×|
|MissingResourceException|×|×|
|NegativeArraySizeException|×|×|
|NoSuchElementException|×|×|
|NullPointerException|×|○|
|NumberFormatException|×|×|
|SecurityException|×|×|
|UnsupportedCharsetException|×|×|
|UnsupportedOperationException|×|×|

結果は、80種類のバグに対して6種類しか検出できませんでした。見ての通り、若干の違いはありますが、検出能力はFindBugsと同程度という印象です。とはいえ、静的解析ツールを使うことで簡単なミスやコーディングのバッドパターンなどを把握できるので、とても有益なツールであることは確かです。ちなみにコードの行数約4,700行に対して、指摘の数は176件でした。

![sq.png](https://qiita-image-store.s3.amazonaws.com/0/43869/bcdb8695-a2dd-d79c-0b7d-f2c9d186587b.png)

*※ 注意：今回の検証で検出できたバグであっても、実装方法が異なれば検出できない可能性があります。逆に今回の検証で検出できなかったバグであっても、実装方法が異なれば検出できる可能性があります。100%の確率でNullPointerExceptionが発生するロジックでも、実装の仕方によってはNullPointerExceptionを検出できる場合も、できない場合もあります。*

## その他気付いたこと

SonarQubeを使っていて少し気になったのは、誤検知の多さです。

例えば、次のコードは未使用のメソッドがあることを指摘していますが、実際にこのメソッドは使用されており、削除すればコンパイルエラーになります。

![mis3.png](https://qiita-image-store.s3.amazonaws.com/0/43869/88c94afa-bf08-4234-5a11-db422411ff73.png)

次のコードはSQLインジェクションを指摘していますが、「`asc`」または「`desc`」以外の値はSQL文に付加されないので、問題はありません。

![mis2.png](https://qiita-image-store.s3.amazonaws.com/0/43869/33870195-79b2-21b0-dfb1-76c484b269d4.png)

次のコードはNPEの可能性を指摘していますが、`org.apache.commons.lang.StringUtils.isBlank(String)`でnullチェックしているため、変数`fileName`がnullとなって、NPEになることはありえません(「might be thrown」なので、まあ、いいのかな...)。

![mis1.png](https://qiita-image-store.s3.amazonaws.com/0/43869/4ad8ac83-4771-f982-0230-a365a5d49632.png)

## 備考

SonarQubeの使用方法などについては、簡単ですが、[ブログ](https://t246osslab.wordpress.com/2016/11/20/sonnarqube%e3%81%a7%e3%82%bd%e3%83%bc%e3%82%b9%e3%82%b3%e3%83%bc%e3%83%89%e3%81%ae%e5%93%81%e8%b3%aa%e3%82%92%e8%a7%a3%e6%9e%90%e3%81%99%e3%82%8b/)にまとめていますので、そちらを参照下さい。