静的コード解析ツールはバグや脆弱性をどの程度検出できるのでしょうか?
前回、FindBugsでバグだらけのWebアプリケーションを解析してみましたが、今回はSonarQubeで解析してみました。
検証内容
バグだらけのWebアプリケーション(EasyBuggy 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件でした。
※ 注意:今回の検証で検出できたバグであっても、実装方法が異なれば検出できない可能性があります。逆に今回の検証で検出できなかったバグであっても、実装方法が異なれば検出できる可能性があります。100%の確率でNullPointerExceptionが発生するロジックでも、実装の仕方によってはNullPointerExceptionを検出できる場合も、できない場合もあります。
その他気付いたこと
SonarQubeを使っていて少し気になったのは、誤検知の多さです。
例えば、次のコードは未使用のメソッドがあることを指摘していますが、実際にこのメソッドは使用されており、削除すればコンパイルエラーになります。
次のコードはSQLインジェクションを指摘していますが、「asc」または「desc」以外の値はSQL文に付加されないので、問題はありません。
次のコードはNPEの可能性を指摘していますが、org.apache.commons.lang.StringUtils.isBlank(String)でnullチェックしているため、変数fileNameがnullとなって、NPEになることはありえません(「might be thrown」なので、まあ、いいのかな...)。
備考
SonarQubeの使用方法などについては、簡単ですが、ブログにまとめていますので、そちらを参照下さい。




