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 块会阻止将任何安全管理器检查应用到调用程序,从而阻止应用到执行堆栈。

此示例使用 lambda 表达式。

复制
 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
             }
         );
     }
 }

不得在 doPrivileged 块中使用 loadLibrary() 方法,以免权限覆盖。

修正代码示例 1

复制
 import java.security.*;
  
 public class NoReturnNoException {
     public void somemethod() {        
            System.loadLibrary("awt");
     }
 }

在此示例中,Klocwork 不再报告缺陷,因为 doPrivileged 块中未使用 loadLibrary() 方法。

漏洞代码示例 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 中可完成权限授予,无论调用程序代码的权限如何。因此,应极其谨慎地使用这些方法。

此示例使用 lambda 表达式:

复制
 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);              
         }
     }
 }

在此示例中,Klocwork 不再报告缺陷,因为 doPrivileged 块中未使用 field.setAccessible( ) 方法。

相关检查器

安全培训

应用程序安全培训材料由 Secure Code Warrior 提供。