SV.PRIVILEGE.MISSING
呼び出されるメソッドは 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 が提供しているアプリケーションセキュリティトレーニング教材。