java.security.egd JVM選項

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.egdsecurerandom.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/randomfile:/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行為的更重要的事件:

了解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/randomfile:/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/randomfile:/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的一些神話。