当Java SecurityManager授予所有权限时,SpringBoot Web应用程序会抛出异常

3
我们有一个使用Spring Boot(1.1.6)开发的应用程序,以.war文件的形式部署到Tomcat 7.0.52 / OpenJDK 7服务器上。我们需要在SecurityManager下运行此服务器。 即使我们使用允许所有代码具有AllPermission的策略(与不在安全管理器下运行相同),由于反射活动而抛出异常。这里是其中一个异常的完整堆栈跟踪。
java.lang.IllegalAccessException: Class org.apache.catalina.security.SecurityUtil$1 can not access a member of class org.springframework.boot.context.web.ErrorPageFilter with modifiers "public"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:109) ~[na:1.7.0_65]
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261) ~[na:1.7.0_65]
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253) ~[na:1.7.0_65]
    at java.lang.reflect.Method.invoke(Method.java:599) ~[na:1.7.0_65]
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277) ~[catalina.jar:7.0.52]
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274) ~[catalina.jar:7.0.52]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:536) ~[na:1.7.0_65]
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309) ~[catalina.jar:7.0.52]
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187) ~[catalina.jar:7.0.52]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.7.0_65]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) ~[catalina.jar:7.0.52]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.52]
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [catalina.jar:7.0.52]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.52]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) [catalina.jar:7.0.52]
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683) [catalina.jar:7.0.52]
    at ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:178) [logback-access-1.0.13.jar:na]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.52]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [catalina.jar:7.0.52]
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) [tomcat-coyote.jar:7.0.52]
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) [tomcat-coyote.jar:7.0.52]
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313) [tomcat-coyote.jar:7.0.52]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_65]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_65]
    at java.lang.Thread.run(Thread.java:745) [na:1.7.0_65]

应用于服务器的策略文件如下所示:

grant { 
  permission java.security.AllPermission;
  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};

我们在代码中添加了明确的ReflectPermission,以防AllPermission没有包含它,但我们尝试了两种方法。

请问为什么只有在使用上述策略的SecurityManager下运行时才会抛出异常?

1个回答

4
错误不是由Java安全性引起的,而是由Java语言访问规则引起的。
ErrorPageFilter类是包可见的[1]。Tomcat尝试通过反射调用该类的公共方法,但无法实现,因为按照Java语言规则,该类本身是不可访问的。
[1] https://github.com/spring-projects/spring-boot/blob/master/spring-boot/src/main/java/org/springframework/boot/context/web/ErrorPageFilter.java (我链接到主分支,但实际上您正在使用版本1.1.6,因此上述链接的内容可能随时间变化而改变)
非公共过滤器是不寻常的。在所有过滤器都在web.xml中声明的旧时代,不可能使用这样的非公共过滤器。我不了解Spring Boot内部情况,但我猜想该过滤器是使用Servlet 3.0 API以编程方式添加到Web应用程序中的。
可能的处理方式:
a)请求Spring Boot开发人员将该类设置为public。 b) 改变Apache Tomcat的方法,使其不再查找特定类声明的方法,而是查找特定接口声明的方法。 由接口声明的java.lang.reflect.Method可以在实现该接口的类上调用。我希望这个解决方案将通过sun.reflect.Reflection.ensureMemberAccess()中的检查,但需要进行实际测试。

这需要更改内部Tomcat API以将接口类(在本例中为javax.servlet.Filter)作为这些方法的附加参数传递。

技术上,这需要:

  • 在Tomcat Bugzilla中提交问题-已完成。
  • 提供一个简单的重现步骤,以便进行测试
  • 等待下一个版本的发布

更新:我将此提交到Bugzilla中, https://issues.apache.org/bugzilla/show_bug.cgi?id=57281


是的,明白了,感谢您的回复。但问题是为什么只有在JVM有活动安全管理器(无论策略如何)时才会出现这种行为?当没有SecurityManager时,可以访问此类,而有SecurityManager时则无法访问。 - darrend
http://svn.apache.org/viewvc/tomcat/tc7.0.x/tags/TOMCAT_7_0_52/java/org/apache/catalina/core/ApplicationFilterChain.java?view=markup 第237-238行与第241行相比,可以调用Filter接口的方法,但不能调用特定类的方法。 - Konstantin Kolinko
明白了,非常感谢。我还在SpringBoot的Github页面上查询了类的可见性,那里几个月前曾讨论过类似的问题:https://github.com/spring-projects/spring-boot/issues/933 - darrend
SpringBoot问题已提出:https://github.com/spring-projects/spring-boot/issues/2026 - darrend

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接