13

在客户的软件中,我们必须阅读给定的 URL 来解析他们的内容。此外,客户需要激活 Tomcat-Security-Manager 以让 Java-Policies 控制程序的功能。

现在,在读取 URL 时,会发生异常“javax.net.ssl.SSLKeyException: RSA premaster secret error”,但仅在某些条件下:

  • 如果 URL 是 HTTPS 但不是 HTTP
  • 如果安全管理器被激活,而不是在它被停用时,或者如果在全局授权块中设置了 AllPermission
  • 仅适用于 Java 6,不适用于 Java 7(客户目前需要 Java 6)
  • 只带Tomcat6,不带Tomcat 7(客户目前需要Tomcat 6)

安全违规发生在 Java 代码中的某个地方,仅限于我们的代码库的 AllPermission 并不能防止错误。

那么,是否有人有想法,为 Java 6 设置哪个权限,以便它可以处理 HTTPS?

其他信息:它在一个 tomcat 中运行,在一个带有 OpenJDK 的 Debian-Linux 上。

编辑:我在变量 JAVA_OPTS 中将 Java 参数“-Djava.security.debug=access,failure”添加到 Tomcats /etc/default/tomcat6 中。但是在日志中我没有其他消息。代码是否有可能在触发权限之前询问权限?

EDIT2:我找到了正确的位置并获得了完整的堆栈跟踪(删除了特定的客户部分):

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

EDIT3:到目前为止,我假设 Java 类 URL 用于访问资源的内容。但这是不正确的。它使用 Grails-Code 中的 Groovy-URL-object 和 getText()-method:

new URL(params.url).text

错误发生在这条线上。它是 Grails 版本 2.2.4。

4

2 回答 2

8

解决方案遵循几条评论和 OP 确认解决方案(摘要)

根本原因是存在sunjce_provider.jar于多个位置。这是在被建议为许多可能的根本原因之一后由 OP 发现的(请参阅此答案的最后和评论线索)。根据OP的评论:

我在多个目录中有 sunjce_provider.jar。我试图为 Java 6 的所有三个位置赋予权利,尽管显然只有一个是 JAVA_HOME - 而且它有效。不知何故使用了其他位置之一,尽管它不在 java.ext.dirs-property

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

对于以后发现此问题的任何人,我已将原始答案中的要点和有助于诊断的评论留在下面

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

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

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

网络的其他类似报告表明,可能的根本原因是缺少 jar(通常引用 sunjce_provider.jar)。堆栈跟踪确认根本原因异常是在寻找算法但找不到它的地方。在您的情况下,由于这只发生在特定配置中,它可能是一个无法访问的jar(由于安全权限)。NoSuchAlgorithmExceptionKeyGeneratorSunTlsRsaPremasterSecretSecurityManager

我的猜测是您没有启用grant codeBase对包含 RSA 密钥生成算法所需 jar 的正确目录的权限。我建议的做法是通过您的 webapp 和 JRE 目录结构来查找运行时 jar 的保存位置,并确保它们具有grantcatalina.policy.

在默认配置中 - 例如 - 你应该在某处看到

// These permissions apply to all shared system extensions
grant codeBase "file:${java.home}/jre/lib/ext/-" {
        permission java.security.AllPermission;
};

有关这意味着什么的详细信息,请参阅tomcat 安全管理器“如何”的这一部分。您需要检查几件事 - 确保这${java.home}/jre/lib/ext/是您的运行时 jar 所在的位置。如果不是 - 更改路径以指向正确的位置(这它们在我的 OpenJDK 6 版本上的位置 - build 27)。特别是你应该看到sunjce_provider.jarsunpkcs11.jar在那里。确保上述部分存在于您的策略文件中。

可能代码取决于您的 webapp 中的某些 jar - 例如 in ${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 错误报告讨论了在 jar 下运行时的位置问题SecurityManager


调试注释

根据另一个答案,您可以尝试在 catalina.sh 中添加或添加-Djava.security.debug=access,failure以启用调试 -默认情况下应该记录到(或者您在 catalina.sh 中通过设置日志记录到的任何位置。您应该从那里看到输出。CATALINA_OPTSJAVA_OPTScatalina.outCATALINA_OUTSecurityManager

您也可以尝试-Djava.security.debug=all. You will get a huge catalina.out`,但您可以使用 grep 查找可能有帮助的单词(例如“失败”!!!)


遵循堆栈跟踪中的代码

你的异常在这里被抛出。查看如何抛出该异常 -此方法必须返回 null。它吞下了Exceptions - 这不好,并且很难准确诊断该代码的哪一部分失败。我的钱会放在这条线上——哪里canUseProvider()可能会返还false。这一切都指向提供者 jar 由于某种原因无法访问。

我假设您在输出中没有看到任何访问冲突,即使使用-Djava.security.debug=access,failure. 您可以尝试-Djava.security.debug=all,尽管这很可能只会产生更多不相关的日志记录。如果没有访问冲突,您的类路径上可能有两个版本的 jar,并且运行时正在访问(或尝试访问错误的)。本Q/A中描述了与此类似的情况。

于 2015-09-27T20:52:29.010 回答
8

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

-Djava.security.debug=access,failure

然后,您将获得有关每个失败的安全访问、有效的保护域等的完整信息。

于 2015-09-18T09:54:34.330 回答