現(xiàn)象
CentOS 7系統(tǒng)中安裝好openjdk和Tomcat后,啟動過程很慢,長達數(shù)分鐘,日志如下:
17:27:53.596 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.38
17:27:53.644 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/docs]
17:32:31.001 WARNING [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [276,660] milliseconds.
17:32:31.022 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/docs] has finished in [277,378] ms
17:32:31.022 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/manager]
17:32:31.101 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/manager] has finished in [79] ms
17:32:31.101 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/examples]
17:32:31.509 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/examples] has finished in [408] ms
17:32:31.510 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/host-manager]
17:32:31.559 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/host-manager] has finished in [49] ms
17:32:31.559 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/ROOT]
17:32:31.576 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/ROOT] has finished in [17] ms
17:32:31.605 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
17:32:31.660 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
17:32:31.662 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 278084 ms
tomcat啟動耗時278084ms折合278秒,對于剛剛安裝的干凈tomcat,這肯定是不對勁的。
其中有一條日志引起了筆者的注意:
17:32:31.001 WARNING [localhost-startStop-1] org.apache.catalina.util.SessionIdGeneratorBase.createSecureRandom Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [276,660] milliseconds.
顯然tomcat執(zhí)行到這里時出問題了,google了一下,經(jīng)過一番搜索明白了其中的緣由。
原因
在tomcat官方wiki文檔的HowToFasterStartUp章節(jié)中,Entropy Source部分有一段這樣的說明:
Tomcat 7+嚴重依賴SecureRandom類為其sessionID和其他地方提供隨機值。如果用于初始化SecureRandom的熵源缺少熵,則可能會在啟動期間導(dǎo)致延遲,具體取決于您的JRE。發(fā)生這種情況時,您會在日志中看到警告,例如:
<DATE> org.apache.catalina.util.SessionIdGenerator createSecureRandom INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [5172] milliseconds.有一種方法可以通過設(shè)置以下系統(tǒng)屬性來配置JRE以使用非阻塞熵源:
-Djava.security.egd = file:/dev/./urandom另請注意,使用非阻塞源替換阻塞熵源實際上會降低安全性,因為您獲得的隨機數(shù)據(jù)較少。
從這里我們得知Tocmat的Session ID是通過SHA1PRNG算法計算得到的,計算Session ID的時候必須有一個密鑰,為了提高安全性Tomcat在啟動的時候會通過隨機生成一個密鑰,它強依賴于獲取熵池中的隨機數(shù)來進行創(chuàng)建。
那么什么是/dev/random?什么是熵池?
/dev/random
從維基百科得知,在UNIX操作系統(tǒng)(包括類UNIX系統(tǒng))中,/dev/random是一個特殊的設(shè)備文件,可以用作隨機數(shù)生成器或偽隨機數(shù)生成器。
Linux內(nèi)核中的是第一個以背景噪聲產(chǎn)生真正的隨機數(shù)產(chǎn)生的實現(xiàn),它允許程序訪問來自設(shè)備驅(qū)動程序或其它來源的背景噪聲。
Linux上有兩個通用的隨機設(shè)備:/dev/random和/dev/urandom。其中/dev/random的隨機性最好,因為它是一個阻塞的設(shè)備。而/dev/random的一個副本是/dev/urandom(“unblocked”,非阻塞的隨機數(shù)生成器),它會重復(fù)使用熵池中的數(shù)據(jù)以產(chǎn)生偽隨機數(shù)據(jù)。這表示對/dev/urandom的讀取操作不會產(chǎn)生阻塞,但其輸出的熵可能小于/dev/random的。所以它可以作為生成較低強度密碼的偽隨機數(shù)生成器,不建議用于生成高強度長期密碼。
熵池
熵池本質(zhì)上是若干字節(jié),/proc/sys/kernel/random/entropy_avail中存儲了熵池現(xiàn)在的大小,/proc/sys/kernel/random/poolsize是熵池的最大容量,單位都是bit。如果entropy_avail的值小于要產(chǎn)生的隨機數(shù)bit數(shù),那么/dev/random就會堵塞。
為什么熵池不夠用?
熵池實際上是從各種noice source中獲取數(shù)據(jù),noice source可能是鍵盤事件、鼠標事件、設(shè)備時鐘中等。linux內(nèi)核從2.4升級到2.6時,處于安全性的考慮,廢棄了一些source。source減少了,熵池補給的速度當然也變慢,進而不夠用。
其實,通過消耗熵池,可以構(gòu)造DDOS攻擊。原理很簡單,熵池空了,依賴隨機數(shù)的業(yè)務(wù)(SSL,加密等)就不能正常進行。
通過以上信息,筆者得知該問題是由于熵池不足導(dǎo)致的。怎么解決?
解決方案
方法一、降低熵生成的隨機性要求
使用非阻塞性的生成器/dev/urandom代替/dev/random。
1、可在JVM環(huán)境中配置
通過配置發(fā)生器指定熵收集守護進程
修改$JAVA_PATH/jre/lib/security/java.security中參數(shù)securerandom.source為:
securerandom.source=file:/dev/./urandom
2、也可在Tomcat環(huán)境中配置
通過配置JRE使用非阻塞的Entropy Source獲取熵
在$TOMCAT_HOME/bin/catalina.sh中加入:
if [[ "$JAVA_OPTS" != *-Djava.security.egd=* ]]; then
JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"
fi
這個系統(tǒng)屬性egd表示熵收集守護進程(entropy gathering daemon)。
方法二、使用熵生成器補充熵池(推薦)
1、[硬件隨機數(shù)生成器]安裝并使用rng-tools作為額外的熵隨機數(shù)生成器(推薦)
# 安裝rng-tools
yum install rng-tools -y
# 測試rngd
rngd -f
# 啟動rngd
systemctl start rngd
# 設(shè)置自啟動
systemctl enable rngd
# 查看自啟動列表
systemctl list-unit-files
cat /dev/random命令會消耗熵池,rngd守護進程會補充熵池,可使用如下命令來測試隨機數(shù)生成的情況:
cat /dev/random | rngtest -c 100
# 測試結(jié)果
rngtest 6
Copyright (c) 2004 by Henrique de Moraes Holschuh
This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
rngtest: starting FIPS tests...
rngtest: bits received from input: 2000032
rngtest: FIPS 140-2 successes: 100
rngtest: FIPS 140-2 failures: 0
rngtest: FIPS 140-2(2001-10-10) Monobit: 0
rngtest: FIPS 140-2(2001-10-10) Poker: 0
rngtest: FIPS 140-2(2001-10-10) Runs: 0
rngtest: FIPS 140-2(2001-10-10) Long run: 0
rngtest: FIPS 140-2(2001-10-10) Continuous run: 0
rngtest: input channel speed: (min=13.823; avg=42.721; max=10761.019)Kibits/s
rngtest: FIPS tests speed: (min=93.041; avg=129.531; max=136.239)Mibits/s
rngtest: Program run time: 45733452 microseconds
2、[軟件隨機數(shù)生成器]在rng-tools仍不滿足的情況下,可使用haveged作為額外的熵隨機數(shù)生成器
haveged項目的目的是提供一個簡單易用的不可預(yù)測隨機數(shù)生成器,基于HAVEGE算法。Haveged可以解決在某些情況下,系統(tǒng)熵過低的問題。此程序無法保證熵的質(zhì)量,如果對安全要求較高,請考慮使用硬件隨機數(shù)生成器rng-tools。
要檢查是否需要 Haveged,可使用下面命令查看當前收集到的熵:
cat /proc/sys/kernel/random/entropy_avail
如果結(jié)果比較低 (<1000),建議安裝 haveged,否則加密程序會處于等待狀態(tài),直到系統(tǒng)有足夠的熵。
# 安裝haveged
yum install haveged -y
# 啟動haveged
systemctl start haveged
# 設(shè)置自啟動
systemctl enable haveged
安裝 haveged 之后,可以再次查看系統(tǒng)熵看下有無提升。
因為方法一存在一定的不安全性,且需要對環(huán)境進行配置,為了滿足熵的需要,這里筆者選擇了第二種方法,使用rng-tools作為額外的熵隨機數(shù)生成器,同以上操作后順利解決了問題。
操作后重啟tomcat日志如下,啟動速度快了兩個數(shù)量級:
17:58:07.068 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.38
17:58:07.088 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/docs]
17:58:07.740 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/docs] has finished in [652] ms
17:58:07.740 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/manager]
17:58:07.815 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/manager] has finished in [75] ms
17:58:07.816 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/examples]
17:58:08.241 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/examples] has finished in [425] ms
17:58:08.241 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/host-manager]
17:58:08.268 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/host-manager] has finished in [27] ms
17:58:08.269 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory [/opt/tomcat_8_5_38/webapps/ROOT]
17:58:08.306 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory [/opt/tomcat_8_5_38/webapps/ROOT] has finished in [37] ms
17:58:08.335 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
17:58:08.424 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
17:58:08.429 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1411 ms
參考文檔:
https://stackoverflow.com/questions/40383430/tomcat-takes-too-much-time-to-start-java-securerandom
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6202721
http://openjdk.java.net/jeps/123
https://zh.wikipedia.org/zh-hans//dev/random
https://wiki.apache.org/tomcat/HowTo/FasterStartUp
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sect-security_guide-encryption-using_the_random_number_generator
https://wiki.archlinux.org/index.php/Rng-tools
https://wiki.archlinux.org/index.php/Haveged
https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged