JVM上的随机数与熵池策略

bug(端口监听启动后,Tomcat耗时2min+ ):html

2017-09-01 15:51:05.146  WARN 20923 --- [http-nio-80-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [141,273] milliseconds.
2017-09-01 15:51:05.160  WARN 20923 --- [http-nio-80-exec-4] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [67,573] milliseconds.
2017-09-01 15:51:05.160  WARN 20923 --- [http-nio-80-exec-3] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [72,205] milliseconds.
2017-09-01 15:51:05.163  WARN 20923 --- [http-nio-80-exec-2] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [132,321] milliseconds.
2017-09-01 18:24:26.447  WARN 21241 --- [http-nio-80-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [166,806] milliseconds.
2017-09-01 20:11:12.953  WARN 21508 --- [http-nio-80-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [173,287] milliseconds.
2017-09-03 16:50:59.385  WARN 25289 --- [http-nio-80-exec-1] o.a.c.util.SessionIdGeneratorBase        : Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [154,563] milliseconds.

这个SecureRandom的初始化居然花了100秒之多。。。java

后来查了一下,发现这个问题抱怨的仍是蛮多的,以致于tomcat的wiki里面还单独列出来做为加速启动的一个方面:linux

Tomcat 7+ heavily relies on SecureRandom class to provide random values for its session ids and in other places. Depending on your JRE it can cause delays during startup if entropy source that is used to initialize SecureRandom is short of entropy. You will see warning in the logs when this happens.算法

 

There is a way to configure JRE to use a non-blocking entropy source by setting the following system property: -Djava.security.egd=file:/dev/./urandomapache

尝试使用-Djava.security.egd=file:/dev/./urandom启动了一下,果真快了不少。ubuntu

不过tomcat的wiki中提到,若是使用这个非阻塞的/dev/urandom的话,会有一些安全方面的风险,这块我倒确实不太明白,不过好在有明白人,并且还写了一篇长文来证实使用/dev/urandom是没问题的,因此就先用着吧:-)tomcat

 

另外:安全

有两种解决办法:服务器

1.在Tomcat环境中解决

能够经过配置JRE使用非阻塞的Entropy Source。

在catalina.sh中加入这么一行:-Djava.security.egd=file:/dev/./urandom 便可。

加入后再启动Tomcat,整个启动耗时降低到Server startup in 6213 ms,大大下降了启动的时间。session

2.在JVM环境中解决

先执行which javac命令检查jdk安装路径

/usr/local/java/jdk1.8.0_92/bin/javac

去到$JAVA_PATH/jre/lib/security/java.security这个文件,找到下面的内容:

securerandom.source=file:/dev/urandom

替换成

securerandom.source=file:/dev/./urandom

 

这样问题就解决了

 

 

在apache-tomcat官方文档:
如何让tomcat启动更快里面提到了一些启动时的优化项,其中一项是关于随机数生成时,采用的“熵源”(entropy source)的策略。

他提到tomcat7的session id的生成主要经过java.security.SecureRandom生成随机数来实现,随机数算法使用的是”SHA1PRNG”

private String secureRandomAlgorithm = "SHA1PRNG";

在sun/oracle的jdk里,这个算法的提供者在底层依赖到操做系统提供的随机数据,在linux上,与之相关的是/dev/random/dev/urandom,对于这两个设备块的描述之前也见过讨论随机数的文章,
wiki中有比较详细的描述,摘抄过来,先看/dev/random
在读取时,/dev/random设备会返回小于熵池噪声总数的随机字节。
/dev/random可生成高随机性的公钥或一次性密码本。
若熵池空了,对/dev/random的读操做将会被阻塞,直到收集到了足够的环境噪声为止

/dev/urandom则是一个非阻塞的发生器:

 

dev/random的一个副本是/dev/urandom (”unlocked”,非阻塞的随机数发生器),它会重复使用熵池中的数据以产生伪随机数据。
这表示对/dev/urandom的读取操做不会产生阻塞,但其输出的熵可能小于/dev/random的。
它能够做为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。

https://bugs.openjdk.java.net/browse/JDK-6202721

另外wiki里也提到了为何linux内核里的随机数生成器采用SHA1散列算法而非加密算法,是为了避开法律风险(密码出口限制)。

回到tomcat文档里的建议,采用非阻塞的熵源(entropy source),经过java系统属性来设置:

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

这个系统属性egd表示熵收集守护进程(entropy gathering daemon),但这里值为什么要在devrandom之间加一个点呢?是由于一个jdk的bug,在这个bug的链接里有人反馈及时对 securerandom.source 设置为/dev/urandom它也仍然使用的/dev/random,有人提供了变通的解决方法,其中一个变通的作法是对securerandom.source设置为/dev/./urandom才行。也有人评论说这个不是bug,是有意为之。

我看了一下我当前所用的jdk7的java.security文件里,配置里仍使用的是/dev/urandom

## Select the source of seed data for SecureRandom. By default an# attempt is made to use the entropy gathering device specified by# the securerandom.source property. If an exception occurs when# accessing the URL then the traditional system/thread activity# algorithm is used.## On Solaris and Linux systems, if file:/dev/urandom is specified and it# exists, a special SecureRandom implementation is activated by default.# This "NativePRNG" reads random bytes directly from /dev/urandom.## On Windows systems, the URLs file:/dev/random and file:/dev/urandom# enables use of the Microsoft CryptoAPI seed functionality.#securerandom.source=file:/dev/urandom

我不肯定jdk7里,这个/dev/urandom也同那个bug报告里所说的等同于/dev/random;要使用非阻塞的熵池,这里仍是要修改成/dev/./urandom呢,仍是jdk7已经修复了这个问题,就是同注释里的意思,只好验证一下。

使用bug报告里给出的代码:

import java.security.SecureRandom;

public class JRand {

      public static void main(String args[]) throws Exception {
System.out.println("Ok: " +SecureRandom.getInstance("SHA1PRNG").nextLong());
     }
}

 

而后设置不一样的系统属性来验证,先是在个人mac上:
% time java -Djava.security.egd=file:/dev/urandomJRandOk: 8609191756834777000java -Djava.security.egd=file:/dev/urandom JRand0.11s user 0.03s system 115% cpu 0.117 total
% time java -Djava.security.egd=file:/dev/./urandomJRandOk: -3573266464480299009java -Djava.security.egd=file:/dev/./urandom JRand0.11s user 0.03s system 116% cpu 0.116 total

能够看到/dev/urandom/dev/./urandom的执行时间差很少,有点纳闷,再仔细看一下wiki里说的:

FreeBSD操做系统实现了256位的Yarrow算法变体,以提供伪随机数流。与Linux的/dev/random不一样,FreeBSD的/dev/random不会产生阻塞,与Linux的/dev/urandom类似,提供了密码学安全的伪随机数发生器,而不是基于熵池。而FreeBSD的/dev/urandom则只是简单的连接到了/dev/random。

 

尽管在个人mac上/dev/urandom并非/dev/random的连接,但mac与bsd内核应该是相近的,/dev/random也是非阻塞的,/dev/urandom是用来兼容linux系统的,这两个随机数生成器的行为是一致的。参考这里。

而后再到一台ubuntu系统上测试:

% time java -Djava.security.egd=file:/dev/urandomJRandOk: 6677107889555365492java -Djava.security.egd=file:/dev/urandom JRand0.14s user 0.02s system 9% cpu 1.661 total
% time java -Djava.security.egd=file:/dev/./urandomJRandOk: 5008413661952823775java -Djava.security.egd=file:/dev/./urandom JRand0.12s user 0.02s system 99% cpu 0.145 total

这回差别就彻底体现出来了,阻塞模式的熵池耗时用了1.6秒,而非阻塞模式则只用了0.14秒,差了一个数量级,固然代价是转换为对cpu的开销了。

// 补充,连续在ubuntu上测试几回/dev/random方式以后,致使熵池被用空,被阻塞了60秒左右。应用服务器端要避免这种方式。

http://www.th7.cn/Program/java/201406/226039.shtml

相关文章
相关标签/搜索