如何设置权限以避免使用https-URLS时出现安全管理器错误?

13
在为客户编写的软件中,我们需要读取给定的URL以解析它们的内容。此外,客户需要激活Tomcat-Security-Manager以让Java-Policies控制程序执行的内容。
现在,在读取URL时,只有在特定条件下才会发生“javax.net.ssl.SSLKeyException: RSA premaster secret error”异常:
  • 如果URL是HTTPS而不是HTTP
  • 如果Security-Manager被激活,而不是在其被停用时或者在全局grant-Block中设置了AllPermission
  • 只在Java 6下出现,而不是在Java 7下出现(客户目前需要Java 6)
  • 只在Tomcat6下出现,而不是在Tomcat 7下出现(客户目前需要Tomcat 6)
安全违规事件发生在Java代码的某个位置,对于我们代码库受限的AllPermission并不能防止错误发生。
那么,是否有人有想法,在Java 6中设置哪些权限可以处理HTTPS呢?
其他信息:它运行在Debian-Linux上的Tomcat内部,使用OpenJDK。
编辑:我在变量JAVA_OPTS中向Tomcat的/etc/default/tomcat6添加了Java参数“-Djava.security.debug=access,failure”。但是在日志中我没有得到额外的消息。可能代码在触发权限之前会询问它们吗?
编辑2:我找到了正确的位置并获得了完整的堆栈跟踪(删除了特定客户的部分)。
javax.net.ssl.SSLKeyException: RSA premaster secret error

            at [...]
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:537)
            at java.lang.Thread.run(Thread.java:701)
    Caused by: java.security.NoSuchAlgorithmException: SunTlsRsaPremasterSecret KeyGenerator not available
            at javax.crypto.KeyGenerator.<init>(KeyGenerator.java:141)
            at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:191)
            ... 14 more

编辑3:到目前为止,我一直以为Java类URL用于访问资源的内容。但这是不正确的。它使用了Groovy-URL对象与getText()方法从Grails代码中:

new URL(params.url).text

错误发生在此行。它是Grails版本2.2.4。


您需要访问https网址,然后对页面执行某些操作吗? - Akash Agarwal
@AkashAggarwal:是的,然后应用程序会解析URL后面的内容。但是由于无法访问URL,因此不会到达这一点。 - Mnementh
URL会在桌面浏览器中打开还是在应用程序内部打开? - Akash Agarwal
你能修正一下倒数第二句的语法吗? - Akash Agarwal
@AkashAggarwal:我的意思是,在那个时候不会向用户显示任何内容,没有浏览器窗口或其他东西(就像你之前问过的那样)。无论如何,这是一个服务器应用程序。 - Mnementh
显示剩余10条评论
2个回答

9

解决方案(概要)

问题的根本原因是存在多个位置的sunjce_provider.jar。在建议它作为可能的根本原因之一后,OP发现了这一点(请参见此答案末尾和评论轨迹)。按照OP的评论:

我在多个目录中都有sunjce_provider.jar。我试图给Java 6的所有三个位置权限,尽管显然只有一个是JAVA_HOME - 它起作用了。不知何故,其中一个其他位置被使用,虽然它不在java.ext.dirs属性中。

因此,在这种情况下,解决方法是确保应用程序有权访问正确的sunjce_provider.jar副本。

我保留了原始答案和诊断过程中有帮助的评论,以供以后查看。

原始答案和导致解决方案的评论

  1. 这不会发生在 http 上,因为您的 Web 应用程序(即此连接的客户端,尽管它在 Tomcat 中运行)在此配置中不需要生成密钥。

  2. 仅当启用 SecurityManager 时才会发生此问题,但如果禁用或具有全局 AllPermission,则不会发生。这表明这是一个文件权限错误。这表明这不是密钥长度的问题(例如 在这里提到的那个)。

其他 类似 的报告 网上表明,可能的根本原因是缺少一个 jar 包(通常引用 sunjce_provider.jar)。堆栈跟踪证实了根本原因异常是 NoSuchAlgorithmException,其中 KeyGenerator 正在查找算法 SunTlsRsaPremasterSecret,但找不到它。在您的情况下,由于特定的 SecurityManager 配置,这仅会发生一次,可能是由于安全权限导致 jar 包无法访问。

我猜测您没有启用 grant codeBase 权限来访问包含所需 RSA 密钥生成算法的 jar 包的正确目录。我的建议是检查您的 web 应用程序和 JRE 目录结构,找到运行时 jar 文件所在的位置,并确保它们在 catalina.policy 中被授予 grant 权限。

在默认配置下,例如,您应该在某个地方看到
// These permissions apply to all shared system extensions
grant codeBase "file:${java.home}/jre/lib/ext/-" {
        permission java.security.AllPermission;
};

有关此内容的详细信息,请参阅tomcat安全管理器"How To"的this section。您需要检查一些内容-确保${java.home}/jre/lib/ext/是您的运行时jar包所在的位置。如果不是,请更改路径以指向正确的位置(它在我的OpenJDK 6版本中的构建27中确实是它们所在的位置)。特别是,您应该在策略文件中看到上述部分存在。

可能代码依赖于某些位于您的Web应用程序内的jar包-例如,在${catalina.base}/path/to/your/webapp/WEB-INF/classes/中,因此您需要授予权限。


导致相同或类似症状的其他问题

  1. 应用程序无法找到或访问sunpkcs11.jar将会给出相同的错误消息(在Ubuntu+openjdk6+tomcat6系统上验证)。很可能重复拷贝该jar文件也会引起此问题。

  2. 检查/etc/java-6-openjdk/security/java.security文件。它应该列出提供程序 - 检查是否有一行类似于security.provider.n = sun.security.pkcs11.SunPKCS11的内容 - 如果该行缺失,您也会收到此错误(在同一系统上验证)

  3. 这个Debian bug report谈到了在SecurityManager下运行时与jar文件位置相关的问题


调试注释

按照其他答案所说,您可以尝试将-Djava.security.debug=access,failure添加到您的catalina.sh中的CATALINA_OPTSJAVA_OPTS中以启用调试 - 这应该默认记录到catalina.out(或者根据您在catalina.sh中通过CATALINA_OUT设置日志记录的位置)。您应该在那里看到来自SecurityManager的输出。

您还可以尝试-Djava.security.debug=all。您将得到一个巨大的


从堆栈跟踪中查看代码

你的异常在这里被抛出。看起来可能是这个方法返回了null。它吞噬了Exceptions,这不好,使得很难确切地诊断哪部分代码失败了。我猜测问题出在这一行——canUseProvider()可能会返回false。所有这些都指向提供程序jar因某种原因而无法访问。
我假设你在输出中没有看到任何访问违规,即使使用了-Djava.security.debug=access,failure。你可以尝试-Djava.security.debug=all,尽管这可能只会产生更多无关的日志记录。如果没有访问违规,你可能在类路径上有两个版本的该jar包,运行时正在访问(或尝试访问)错误的版本。类似于这种情况在此Q/A中有描述。

sunjce_provider.jar已经被授予了AllPermissions(就像您在jre/lib/ext/-的示例中一样)。我再次授予了它,但没有改变任何事情。 - Mnementh
@mnemeth 好的-所以我的好奇心让我决定做了一件事情。我在一个Ubuntu虚拟机上安装了Tomcat6和openjdk6,然后将“https://google.co.uk”的检索添加到其中一个Tomcat Servlet示例中。通过删除对 "sunpkcs11.jar"(而不是 "sunjce_provider.jar")的访问,我可以复制您的错误。如果没有详细访问您的".policy"文件和目录结构,我不知道是否能够提供更多的诊断帮助,但我相信访问此jar是问题所在。尽管如此,对于我的新安装,它“只是工作了”。 - J Richard Snape
您还可以通过运行find / -iname sunpkcs11.jar来检查是否存在多个sunpkcs的副本,以消除错误运行的可能性。在我的安装中,我只有一个副本(和一个符号链接)。最后一个想法是-检查/etc/java-6-openjdk/security/java.security。它应该列出提供程序-检查是否有一行类似于security.provider.n = sun.security.pkcs11.SunPKCS11的内容。我已经验证,在其中缺少提供程序也会复制您的错误。 - J Richard Snape
请查看Debian上的此错误报告,同时使用OpenJDK6 - 也许您正在遭受与/jre/lib/ext确切位置相关的类似问题 https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=649046 - J Richard Snape
太棒了 - 很高兴听到你找到了它!!! 我一定会将其编辑到主要解决方案中。只是为了明确(所以我可以从我的上面的评论中编辑正确的部分)- 根本原因是多个版本的 sunjce_provider.jar吗? - J Richard Snape
显示剩余5条评论

8

发现所有所需权限的简单方法是使用参数运行

-Djava.security.debug=access,failure

您将会收到有关每次安全访问失败的完整信息,包括生效的保护域等详细信息。


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