偶遇 JDK 1.8 还未修复的 SecureRandom.getInstance(“SHA1PRNG”) 之 bug

0
(0)

楼主今天兴高采烈的在部署环境,下载 JDK,打包项目,上传至服务器。

配置 JDK ,打包上传项目楼主就不在这里重复了,读者自行解决哈!

1. 启动项目

java -jar xxxx.jar 

令楼主没有想到的是:程序卡主了,卡在了数据库建立连接的位置。(查看方法方式: jstack <pid> 即可)

2. 堆栈信息

由于是项目刚一启动,初始化数据库连接池,并没有太多的线程堆栈。这里我贴一下我遇到的主要问题的堆栈信息:


"restartedMain" #11 prio=5 os_prio=0 tid=0x00007f4430002800 nid=0x65b0 runnable [0x00007f447837a000]
   java.lang.Thread.State: RUNNABLE
	at java.io.FileInputStream.readBytes(Native Method)
	at java.io.FileInputStream.read(FileInputStream.java:255)
	at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:539)
	at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:144)
	at sun.security.provider.SecureRandom$SeederHolder.<clinit>(SecureRandom.java:203)
	at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:221)
	- locked <0x00000000d6eb8930> (a sun.security.provider.SecureRandom)
	at java.security.SecureRandom.nextBytes(SecureRandom.java:468)
	at oracle.security.o5logon.O5Logon.a(Unknown Source)
	at oracle.security.o5logon.O5Logon.<clinit>(Unknown Source)
	at oracle.jdbc.driver.T4CTTIoauthenticate.<init>(T4CTTIoauthenticate.java:566)
	at oracle.jdbc.driver.T4CConnection.logon(T4CConnection.java:370)
	at oracle.jdbc.driver.PhysicalConnection.<init>(PhysicalConnection.java:546)
	at oracle.jdbc.driver.T4CConnection.<init>(T4CConnection.java:236)
	at oracle.jdbc.driver.T4CDriverExtension.getConnection(T4CDriverExtension.java:32)
	at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:521)

或许你会问我,为什么你要定位到这个线程?主要是因为道友经过好几次 jstack 操作,发现该线程一直都停留在该位置,这就足以说明这个线程是当前线程!

3. 分析堆栈信息

从上面的堆栈信息中,我们可以得知那些信息?

  • 当前线程名称为 : restartedMain
  • 当前线程状态为: RUNNABLE
  • 当前线程 ID: 0x00007f4430002800
  • native 线程 ID: 0x65b0
  • 当前运行位置 : at java.io.FileInputStream.readBytes(Native Method)

通过分析堆栈,想必读取文件不会有什么问题,我们往线程堆栈的上层追踪。目标点落在 

    at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedBytes(SeedGenerator.java:539)

很明显,这里是  JDK 源码的调用,接下来打卡 jdk 源码进行查看!

4. 源码分析

我们通过堆栈信息一步步跟进源码查看,

从方法  nextBytes 上来看,他调用这个是为了:生成用户指定的随机字节数。好吧,那就是它在生成的时候,需要读取某个文件来生成随机数。

5. 写个测试验证想法

[ryan@ryanmacbook ~]$ vim HelloWorld.java 
import java.security.SecureRandom;

class HelloWorld {

    public static void main(String args[]) throws Exception {

        byte[] bytes = new byte[32];

        SecureRandom.getInstance("SHA1PRNG").nextBytes(bytes);

        System.out.println("SourceRandom nextBytes : " + new String(bytes));
    }
}

紧接着执行

javac HelloWorld.java

这个要是读者你不会,那你就放弃java吧,java 界可能不适合你。

接下来执行 

java HelloWorld

执行后,,的结果是 

[ryan@ryanmacbook ~]$ java HelloWorld


^C

[ryan@ryanmacbook ~]

$

卡住了,楼主强制 kill 了。

说明我们的问题点就是这里。

接下来,解决办法是啥?你要问楼主楼主也不知道,咋办?上百度呗,百度都不会用的程序员不是好程序员:

6. 解决办法

最后的解决办法就是 ,在项目启动的时候,修改 java.security.egd,通过如下方式,专业术语叫做    熵池策略   

java -Djava.security.egd=file:/dev/urandom HelloWorld

问题的本质还是 Oracle 驱动类中调用了 SecureRandom.nextBytes() 。楼主还没来得及看其他驱动程序是否也有这个问题,当然也不排除与操作系统有关系。待验证其他操作系统后,再补充!

果断成功!

道友查了下,说是 JVM 的 bug , 在收集噪点的时候没有收集全导致的。如果你的也有遇到这样的问题,时而可用,时而不可用,那就是噪点收集的问题。

[参考链接] http://ifeve.com/jvm-random-and-entropy-source/

这篇文章有用吗?

平均评分 0 / 5. 投票数: 0

到目前为止还没有投票!成为第一位评论此文章。

很抱歉,这篇文章对您没有用!

让我们改善这篇文章!

告诉我们我们如何改善这篇文章?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据