SV.PRIVILEGE.MISSING

呼び出されるメソッドは doPrivileged ブロック内にあってはなりません

ソフトウェアは、アクターの権限を適切に割り当てず、変更、追跡、またはチェックしないため、そのアクターに意図しない制御範囲が作成されます。

脆弱性とリスク

クラスのロードに関連するセキュリティチェックは、クラスローダーが実行します。このため、これらのクラスをロードするメソッドをどれか一つ呼び出すメソッドは、これらのメソッドが信頼できないコードに代わって動作できないことを保証する必要があります。

doPrivileged ブロック内でこれらのメソッドを使用すると、セキュリティマネージャーのチェックが実行スタックのさらに上位の呼び出し元に適用されなくなります。このため、以下のメソッドは doPrivileged ブロックで使用しないでください。
コピー
java.lang.Runtime.load
java.lang.Runtime.loadLibrary
java.lang.System.load
java.lang.System.loadLibrary
java.lang.reflect.Field.setAccessible()

脆弱コード例 1

以下の例では、特権の変更の証拠が見られます。

コピー
 public class NoReturnNoException {
      
     public void somemethod() {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             public Void run() {
                 // Privileged code goes here, for example: 
                 System.loadLibrary("awk");
                 return null; // nothing to return
             }
         });
     }
 }
コピー
  public class NoReturnNoException {
      
     class MyAction implements PrivilegedAction<Void> {
         public Void run() {
             // Privileged code goes here, for example: 
             System.loadLibrary("awt");
             return null; // nothing to return
         }
     }
      
     public void somemethod() {
             
         MyAction mya = new MyAction();
          
         // Become privileged: 
         AccessController.doPrivileged(mya);
     }
 }

このコードは、信頼できないコードに代わってライブラリをロードする可能性があるため、安全ではありません。信頼できないコードのクラスローダーは、直接ロードするための十分なパーミッションがない場合でも、このコードを使用してライブラリをロードできる可能性があります。ライブラリをロードした後、ネイティブメソッドにアクセス可能な場合、信頼できないコードはそうしたメソッドをライブラリから呼び出すことができます。これは、doPrivileged ブロックが、実行スタックのさらに上位の呼び出し元にセキュリティマネージャーのチェックが適用されないようにするからです。

ラムダ式を使用している例。

コピー
 import java.security.*;
  
 public class NoReturnNoException {
      
     public void somemethod() {
          
         // Lambda expression
         AccessController.doPrivileged((PrivilegedAction<Void>)
             () -> {
                 // Privileged code goes here, for example: 
                 System.loadLibrary("awt");
                 return null; // nothing to return
             }
         );
     }
 }

パーミッションの上作成を避けるために、loadLibrary() メソッドは doPrivileged ブロックで使用しないでください。

修正コード例 1

コピー
 import java.security.*;
  
 public class NoReturnNoException {
     public void somemethod() {        
            System.loadLibrary("awt");
     }
 }

この例では、loadLibrary() メソッドは doPrivileged ブロックで使用されていないため、Klocwork はもはや欠陥を報告していません。

脆弱コード例 2

コピー
 AccessController.doPrivileged(new PrivilegedAction() {
     @Override
     public Object run() {
         field.setAccessible(true);  // <----- SV.PRIVILEGE.MISSING should not be in doPrivileged block
         return null;
     }
 });

この例では、java.lang.reflect.Field.setAccessible() メソッドを使用して、Java 仮想マシン (JVM) に言語アクセスチェックをオーバーライドするように指示しています。このメソッドを AccessController.doPrivileged でラップすると、呼び出し元コードのパーミッションに関係なく、パーミッションが付与されます。これらの方法は、細心の注意を払って使用する必要があります。

ラムダ式を使用している例:

コピー
 AccessController.doPrivileged((PrivilegedAction) () -> {
     field.setAccessible(true);  // <----- SV.PRIVILEGE.MISSING should not be in doPrivileged block
     return null;
 });

修正コード例 2

コピー
 public static void replaceNull(Object obj)
 {
     Field[] fields = obj.getClass().getDeclaredFields();
     if (fields != null)
     {
         for (Field field : fields)
         {
             field.setAccessible(true);              
         }
     }
 }

この例では、field.setAccessible() メソッドは doPrivileged ブロックで使用されていないため、Klocwork は欠陥を報告しなくなりました。

関連チェッカー

セキュリティトレーニング

Secure Code Warrior が提供しているアプリケーションセキュリティトレーニング教材。