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

相關文章
相關標籤/搜索