JPCERT コーディネーションセンター

ERR09-J. 信頼できないコードにJVMを終了させない

System.exit() 呼出しはJava仮想マシン(JVM)を終了させる。つまり、実行中のすべてのプログラムやスレッドを終了させる。結果としてサービス運用妨害(DoS)を引き起こされる可能性がある。たとえば、Java Server Page(JSP)に組込まれたSystem.exit()を呼び出すことで、ウェブサーバを終了させ、プログラムがそれ以上サービスを提供できないようにすることが可能である。したがってプログラムは、突然の悪意ある System.exit() 呼出しを阻止しなくてはならない。さらに(Windows のタスクマネージャやPOSIXのkillコマンドの使用により)プログラムが強制的に終了させられる場合、必要なクリーンアップ処理を行わなくてはならない。

違反コード

以下の違反コード例では、System.exit()を使用してJVMを強制的にシャットダウンし、実行中のプロセスを強制終了している。このプログラムはセキュリティマネージャーを実装していないため、呼出し側がSystem.exit()を呼び出してよいかどうかをチェックすることができない。

public class InterceptExit {
  public static void main(String[] args) {
    // ...
    System.exit(1);  // 突然の exit 呼出し
    System.out.println("This never executes");
  }
}
適合コード

以下の適合コードでは、SecurityManager クラスで定義されている checkExit() メソッドをオーバーライドする独自のセキュリティマネージャ PasswordSecurityManager を実装している。exitを許可する前にクリーンアップコードの呼出しを行うには、このようにオーバーライドする必要がある。SecurityManagerクラスに定義されているデフォルトのcheckExit()メソッドにはこの機能が存在しない。

class PasswordSecurityManager extends SecurityManager {
  private boolean isExitAllowedFlag; 
  
  public PasswordSecurityManager(){
    super();
    isExitAllowedFlag = false;  
  }
 
  public boolean isExitAllowed(){
    return isExitAllowedFlag;	 
  }
 
  @Override 
  public void checkExit(int status) {
    if (!isExitAllowed()) {
      throw new SecurityException();
    }
    super.checkExit(status);
  }
 
  public void setExitAllowed(boolean f) {
    isExitAllowedFlag = f; 	 
  }
}

public class InterceptExit {
  public static void main(String[] args) {
    PasswordSecurityManager secManager =
        new PasswordSecurityManager();
    System.setSecurityManager(secManager);
    try {
      // ...
      System.exit(1);  // 突然の exit 呼出し
    } catch (Throwable x) {
      if (x instanceof SecurityException) {
        System.out.println("Intercepted System.exit()");
        // 例外をログに記録する
      } else {
        // 例外ハンドラに処理を渡す
      }
    }

    // ...
    secManager.setExitAllowed(true);  // exit を許可する
    // System.exit() が実行される
    // ...
  }
}

このプログラムでは、フラグを使ってexitが許可されているかどうかを確認している。setExitAllowed()メソッドはこのフラグを設定するが、フラグが設定されていない場合(つまりfalseの場合)、checkExit()メソッドはSecurityExceptionをスローする。このフラグは初期化時はfalseであるため、try 節では、最初のSystem.exit()を実行せずにSecurityException をスローする。プログラムはSecurityExceptionをキャッチし、例外をログに記録するなどのクリーンアップ処理を行う。クリーンアップ処理が完了して初めて System.exit() メソッドの実行が許可される。

例外

ERR09-EX0: コマンドラインプログラムにおいて、たとえば呼び出しに必要な引数が与えられていない場合などに System.exit() を呼び出すことは許される[Bloch 2008][ESA 2005]。

リスク評価

Sytem.exit()の不正な呼出しを許すと、サービス運用妨害(DoS)につながる恐れがある。

ルール 深刻度 可能性 修正コスト 優先度 レベル
ERR09-J P2 L3
関連ガイドライン
MITRE CWE CWE-382. J2EE bad practices: Use of System.exit()
参考文献
[API 2006] Method checkExit(), class Runtime, method addShutdownHook
[Austin 2000] Writing a Security Manager
[Darwin 2004] 9.5, The Finalize Method
[ESA 2005] Rule 78. Restrict the use of the System.exit method
[Goetz 2006] 7.4, JVM Shutdown
[Kalinovsky 2004] Chapter 16, Intercepting a Call to System.exit
翻訳元

これは以下のページを翻訳したものです。

ERR09-J. Do not allow untrusted code to terminate the JVM (revision 70)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter