《Java编码指南:编写安全可靠程序的75条建议》—— 指南19:对细粒度的安全定义自定义安全权限...

本节书摘来异步社区《Java编码指南:编写安全可靠程序的75条建议》一书中的第1章,第1.19节,作者:【美】Fred Long(弗雷德•朗), Dhruv Mohindra(德鲁•莫欣达), Robert C.Seacord(罗伯特 C.西科德), Dean F.Sutherland(迪恩 F.萨瑟兰), David Svoboda(大卫•斯沃博达),更多章节内容可以访问云栖社区“异步社区”公众号查看。

指南19:对细粒度的安全定义自定义安全权限

默认的SecurityManager会检查给定方法的调用者是否具有足够的继续执行动作的权限。动作定义在Java安全架构的访问级别,需要特定的权限才能执行。例如,java.io.FilePermission类的动作是读、写、执行和删除[API 2013]。“权限描述和风险”指南(Permission Descriptions and Risks guide)[Oracle 2011d]列举了默认的权限和为Java代码授予这些权限有关的风险。

有时候,我们需要的限制比默认安全管理器所能提供的还要强。当不存在对应的默认权限且未能提供自定义的权限时,可能会导致特权升级漏洞,从而允许不可信的调用者执行限制操作或动作。

本指南讨论了过多权限的问题,有关解决这个问题的另外一个办法,参见指南16。

违规代码示例

下面的违规代码示例包含一个特权代码块,用来执行两个敏感操作:加载一个库;设置默认异常处理程序。

class LoadLibrary {
 private void loadLibrary() {
  AccessController.doPrivileged(
   new PrivilegedAction() {
    public Object run() {
     // Privileged code
     System.loadLibrary("myLib.so");
     // Perform some sensitive operation like
     // setting the default exception handler
     MyExceptionReporter.setExceptionReporter(reporter);
     return null;
    }
  });
 }
}```
使用时,默认的安全管理器会禁止库的加载,除非RuntimePermission loadLibrary.myLib在策略文件中已被授权。然而,安全管理器不会自动防护调用者的第二个敏感操作的执行,即设置默认异常处理程序,因为该操作的权限不是默认的,因此,安全管理器此时不会生效。这个安全弱点可以被利用,例如,编程并安装一个能泄露信息的异常处理程序,泄露那些合法处理程序会过滤掉的信息。

####合规解决方案
下面的合规解决方案定义了一个自定义的权限ExceptionReporterPermission,与目标exc.reporter,用以禁止非法调用者设置默认异常处理程序。这可以通过子类化BasicPermission来实现,它允许二进制风格的权限(允许或不允许)。该解决方案然后使用安全管理器,检查调用者是否拥有必要的设置异常处理程序的权限。如果检查失败,代码会抛出SecurityException异常。自定义权限类ExceptionReporterPermission还定义了所需的两个构造函数。

class LoadLibrary {
 private void loadLibrary() {
  AccessController.doPrivileged(
   new PrivilegedAction() {
    public Object run() {
     // Privileged code
     System.loadLibrary("myLib.so");

     // Perform some sensitive operation like
     // setting the default exception handler
     MyExceptionReporter.setExceptionReporter(reporter);
     return null;
    }
   });
 }
}

final class MyExceptionReporter extends ExceptionReporter {
 public void setExceptionReporter(ExceptionReporter reporter) {
  SecurityManager sm = System.getSecurityManager();
   if(sm != null) {
    sm.checkPermission(
     new ExceptionReporterPermission("exc.reporter"));
   }
   // Proceed to set the exception reporter
  }

  // ... Other methods of MyExceptionReporter
}

final class ExceptionReporterPermission extends BasicPermission {
 public ExceptionReporterPermission(String permName) {
  super(permName);
 }

 // Even though the actions parameter is ignored,
 // this constructor has to be defined
 public ExceptionReporterPermission(String permName,
               String actions) {
  super(permName, actions);
 }
}`
策略文件需要授予两个权限:将ExceptionReporterPermission权限授予exc.reporter;将RuntimePermission权限授予loadlibrary.myLib。以下策略文件假设上述资源位于Windows系统的c:package目录下。

grant codeBase "file:/c:/package" {
 //For *nix, file:${user.home}/package/
 permission ExceptionReporterPermission "exc.reporter";
 permission java.lang.RuntimePermission "loadLibrary.myLib";
};```
默认情况下,不能使用BasicPermission将权限定义为支持动作,如果需要的话,可以在ExceptionReporterPermission的子类中自由地实现这些动作。BasicPermission是一个抽象类,尽管它不包含抽象方法;它声明了所有从Permission类继承的方法。BasicPermission类的自定义子类必须定义两个构造函数,调用最合适的(单参数或双参数)超类构造函数(因为超类没有默认构造函数)。双参数构造函数也接受一个动作,即使基本权限不会使用它。从策略文件中构造权限对象时,需要这种行为。注意,BasicPermission类的自定义子类要被声明成final类。

####适用性

你可能感兴趣的:(《Java编码指南:编写安全可靠程序的75条建议》—— 指南19:对细粒度的安全定义自定义安全权限...)