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設置,但我們需要手動對其進行配置 - 如果使用
SHA1PRNGfile:/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的一些神話。