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

    xiaoxiao2024-04-15  135

    本节书摘来异步社区《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类。 ####适用性
    最新回复(0)