java.security.egd JVM選項
- java
1.概述
啟動Java虛擬機(JVM)時,我們可以定義各種屬性,這些屬性將改變JVM的行為。這樣的屬性之一就是java.security.egd.
在本教程中,我們將檢查它是什麼,如何使用它以及產生什麼效果。
2.什麼是java.security.egd
?
作為JVM屬性,我們可以使用java.security.egd
來影響SecureRandom
類的初始化方式。
像所有JVM屬性一樣,我們在啟動JVM時在命令行中-D
java -Djava.security.egd=file:/dev/urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
通常,如果我們正在運行Java 8或更高版本,並且在Linux上運行,則我們的JVM默認情況下file:/dev/urandom
3. java.security.egd
有什麼作用?
當我們第一次調用從SecureRandom
讀取字節時,我們使它初始化並讀取JVM的java.security
配置文件.該文件包含securerandom.source
屬性:
securerandom.source=file:/dev/random
安全提供程序(例如默認的sun.security.provider.Sun
在初始化時會讀取此屬性。
當我們設置java.security.egd
JVM屬性時,安全提供程序可以使用它來覆蓋securerandom.source
配置的屬性。
SecureRandom
生成隨機數java.security.egd
和securerandom.source
控制哪個entropy gathering device
(EGD)作為種子數據的主要來源。
在Java 8之前,我們在$JAVA_HOME/jre/lib/security
java.security
,但在以後的實現中,它在$JAVA_HOME/conf/security
。
egd
選項是否有效取決於安全提供程序的實現。
java.security.egd
可以取什麼值?
我們可以使用java.security.egd
,其值如下:
-
file:/dev/random
-
file:/dev/urandom
-
file:/dev/./urandom
此設置是否有效,還是其他值有所不同,取決於我們使用的平台和Java版本以及如何配置JVM的安全性。
在基於Unix的操作系統(OS)上, /dev/random
是一個特殊的文件路徑,在文件系統中以普通文件的形式出現,但從中讀取的內容實際上與OS的設備驅動程序進行交互以生成隨機數。一些設備實現還通過/dev/urandom
甚至/dev/arandom
URI提供訪問。
5.關於file:/dev/./urandom
有何特別之處?
首先,讓我們了解文件/dev/random
和/dev/urandom:
-
/dev/random
從各種來源收集熵;/dev/random
將一直阻塞,直到它具有足夠的熵來滿足我們的不可預測數據的讀取請求為止 -
/dev/urandom
將從可用的任何內容中得出偽隨機性,而不會阻塞。
當我們第一次使用SecureRandom
,我們的默認Sun SeedGenerator
初始化。
當我們使用特殊值file:/dev/random
或file:/dev/urandom
,我們使Sun SeedGenerator
使用本機(平台)實現。
Unix上的提供程序實現可能仍通過/dev/random
讀取而阻塞。在Java 1.4中,發現某些實現存在此問題。該錯誤隨後在Java 8的JDK增強建議(JEP 123)下得到修復。
file:/dev/./urandom
類的URL或任何其他值,會導致SeedGenerator
將其視為指向我們要使用的種子源的URL 。
在類似Unix的系統上,我們的file:/dev/./urandom
URL解析為相同的非阻塞/dev/urandom
文件。
但是,我們並不總是要使用此值。在Windows上,我們沒有此文件,因此我們的URL無法解析。這觸發了產生隨機性的最終機制,並且可能使我們的初始化延遲約5秒鐘。
SecureRandom
的演變
在各種Java版本中java.security.egd
的影響已經改變。
因此,讓我們看一些影響SecureRandom
行為的更重要的事件:
- Java 1.4
- 在JDK-4705093下引發的/ dev / random阻止問題:使用/ dev / urandom而不是/ dev / random(如果存在)
- Java 5
- 修復JDK-4705093
- 添加了
NativePRNG
算法以遵守java.security.egd
設置,但我們需要手動對其進行配置 - 如果使用
SHA1PRNG
file:/dev/urandom.
以外的其他任何東西,它可能會阻塞。換句話說,file:/dev/./urandom
,它可能會阻塞
- 添加了
- 修復JDK-4705093
- Java 8
- JEP123:可配置的安全隨機數生成
- 添加了新的
SecureRandom
實現,該實現尊重安全屬性 - 為平臺本地強隨機數添加一個新的
getInstanceStrong()
非常適合生成高價值和長期存在的秘密,例如RSA私鑰/公鑰對 - 我們不再需要
file:/dev/./urandom
解決方法
- 添加了新的
- JEP123:可配置的安全隨機數生成
- Java 9
- JEP273:基於DRBG的SecureRandom實現
- 實現了三種確定性隨機位生成器(DRBG)機制,如使用確定性隨機位生成器生成隨機數的建議中所述
- JEP273:基於DRBG的SecureRandom實現
了解SecureRandom
更改方式後,我們可以深入了解java.security.egd
屬性的可能效果。
7.測試java.security.egd
要確定JVM屬性的效果,最好的方法是嘗試一下。因此,讓我們通過運行一些代碼來創建新的SecureRandom
並定時獲取它需要多長時間**java.security.egd
** 一些隨機字節。
首先,讓我們使用main()
方法JavaSecurityEgdTester
我們將使用System.nanoTime()
secureRandom.nextBytes()
調用,並顯示結果:
public class JavaSecurityEgdTester {
public static final double NANOSECS = 1000000000.0;
public static void main(String[] args) {
SecureRandom secureRandom = new SecureRandom();
long start = System.nanoTime();
byte[] randomBytes = new byte[256];
secureRandom.nextBytes(randomBytes);
double duration = (System.nanoTime() - start) / NANOSECS;
System.out.println("java.security.egd = " + System.getProperty("java.security.egd") + " took " + duration + " seconds and used the " + secureRandom.getAlgorithm() + " algorithm");
}
}
現在,通過啟動一個新的Java實例並為java.security.egd
屬性JavaSecurityEgdTester
java -Djava.security.egd=file:/dev/random -cp . com.baeldung.java.security.JavaSecurityEgdTester
讓我們檢查輸出以查看測試花費了多長時間以及使用了哪種算法:
java.security.egd=file:/dev/random took 0.692 seconds and used the SHA1PRNG algorithm
由於我們的系統屬性僅在初始化時讀取,因此讓我們在新的JVM中針對java.security.egd
每個不同值啟動類:
java -Djava.security.egd=file:/dev/urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
java -Djava.security.egd=file:/dev/./urandom -cp . com.baeldung.java.security.JavaSecurityEgdTester
java -Djava.security.egd=baeldung -cp . com.baeldung.java.security.JavaSecurityEgdTester
在使用Java 8或Java 11的Windows上,使用值file:/dev/random
或file:/dev/urandom
進行測試的時間小於2秒鐘。使用其他file:/dev/./urandom
,甚至baeldung
,會使我們的測試花費5秒鐘以上!
有關為什麼會發生這種情況的說明,請參見我們前面的部分。在Linux上,我們可能會得到不同的結果。
8.關於SecureRandom.getInstanceStrong()
呢?
Java 8引入了SecureRandom.getInstanceStrong()
方法。讓我們看看這如何影響我們的結果。
首先,讓我們用SecureRandom.
new SecureRandom()
getInstanceStrong()
:
SecureRandom secureRandom = SecureRandom.getInstanceStrong();
現在,讓我們再次運行測試:
java -Djava.security.egd=file:/dev/random -cp . com.baeldung.java.security.JavaSecurityEgdTester
在Windows上運行時, SecureRandom.getInstanceStrong()
java.security.egd
屬性的值沒有明顯的作用。甚至無法識別的值也可以使我們快速響應。
讓我們再次檢查輸出,注意不到0.01秒的時間。我們還要觀察一下,該算法現在是Windows-PRNG:
java.security.egd=baeldung took 0.003 seconds and used the Windows-PRNG algorithm
請注意,算法名稱中的PRNG代表偽隨機數生成器。
9.播種算法
由於隨機數在加密技術中大量用於安全密鑰,因此它們必須不可預測。
因此,我們播種算法的方式直接影響它們產生的隨機數的可預測性。
為了產生不可預測性, SecureRandom
實現使用從累積的輸入中收集的熵來播種其算法。這來自IO設備,例如鼠標和鍵盤。
在類Unix系統上,我們的熵累積在文件/dev/random
。
Windows上沒有/dev/random
文件。將-Djava.security.egd
設置為file:/dev/random
或file:/dev/urandom
會導致默認算法(SHA1PRNG)使用本機Microsoft Crypto API播種。
10.虛擬機如何?
/dev/random
收集很少或沒有熵的虛擬機中運行。
虛擬機沒有物理鼠標或鍵盤來生成數據,因此/dev/random
的熵累積的速度要慢得多。這可能會導致我們的默認SecureRandom
調用阻塞,直到有足夠的熵使其生成不可預測的數字為止。
我們可以採取一些步驟來減輕這種情況。例如,在RedHat Linux中運行VM時,系統管理員可以配置虛擬IO隨機數生成器virtio-rng
。這將從託管它的物理機讀取熵。
11.故障排除技巧
如果我們的應用程序或其依賴項在生成SecureRandom
編號時掛起,請考慮java.security.egd
,特別是在我們在Linux上運行以及在Java 8之前的版本上運行時。
我們的Spring Boot應用程序經常使用嵌入式**Tomcat** 。這使用SecureRandom
來生成會話密鑰。當我們看到Tomcat的“創建SecureRandom實例”操作花費5秒鐘或更長時間時,我們應該為**java.security.egd** .
12.結論
在本教程中,我們學習了JVM屬性java.security.egd
是什麼,如何使用它以及它具有什麼作用。我們還發現,其影響可能會根據我們所運行的平台和所使用的Java版本而有所不同。
最後,我們可以在《 JCA參考指南》和“ SecureRandom API規範SecureRandom
及其工作方式的更多信息,並了解有關urandom的一些神話。