前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >偶遇 JDK 1.8 还未修复的 SecureRandom.getInstance(“SHA1PRNG”) 之 bug

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

作者头像
前Thoughtworks-杨焱
发布于 2021-12-07 12:22:25
发布于 2021-12-07 12:22:25
1.2K00
代码可运行
举报
文章被收录于专栏:杨焱的专栏杨焱的专栏
运行总次数:0
代码可运行

发表于2019-05-232020-03-03 作者 Ryan

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

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

1. 启动项目

java -jar xxxx.jar

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

2. 堆栈信息

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
"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. 写个测试验证想法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[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

执行后,,的结果是

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[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/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-05-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档