Перейти к основному содержимому

Параметр JVM java.security.egd

· 8 мин. чтения

1. Обзор

При запуске виртуальной машины Java (JVM) мы можем определить различные свойства, которые изменят поведение нашей JVM. Одним из таких свойств является java.security.egd.

В этом уроке мы рассмотрим, что это такое, как его использовать и какой эффект он дает.

2. Что такое java.security.egd ?

В качестве свойства JVM мы можем использовать java.security.egd , чтобы повлиять на инициализацию класса SecureRandom .

Как и все свойства JVM, мы объявляем его с помощью параметра -D в нашей командной строке при запуске JVM:

java -Djava.security.egd=file:/dev/urandom -cp . com.foreach.java.security.JavaSecurityEgdTester

Как правило, если мы используем Java 8 или более позднюю версию и работаем в Linux, то наша JVM по умолчанию будет использовать файл:/dev/urandom .

3. Какой эффект имеет java.security.egd ?

Когда мы делаем наш первый вызов для чтения байтов из SecureRandom , мы заставляем его инициализировать и читать файл конфигурации java.security JVM . Этот файл содержит свойство securerandom.source :

securerandom.source=file:/dev/random

Поставщики безопасности, такие как sun.security.provider.Sun по умолчанию, считывают это свойство при инициализации .

Когда мы устанавливаем наше свойство JVM java.security.egd , поставщик безопасности может использовать его для переопределения свойства, настроенного в securerandom.source .

Вместе java.security.egd и securerandom.source определяют , какое устройство сбора энтропии (EGD) будет использоваться в качестве основного источника начальных данных, когда мы используем SecureRandom для генерации случайных чисел.

До Java 8 мы находим java.security в $JAVA_HOME/jre/lib/security , но в более поздних реализациях он находится в $JAVA_HOME/conf/security .

Воздействует ли параметр egd на какой- либо эффект, зависит от реализации поставщика безопасности.

4. Какие значения может принимать java.security.egd ?

Мы можем указать java.security.egd в формате URL с такими значениями, как:

  • файл:/dev/случайный
  • файл: /dev/urandom
  • файл:/dev/./urandom

Имеет ли этот параметр какой-либо эффект или какое-либо другое значение имеет значение, зависит от используемой платформы и версии Java, а также от того, как настроена безопасность нашей JVM.

В операционных системах (ОС) на базе Unix /dev/random — это специальный путь к файлу, который отображается в файловой системе как обычный файл, но чтение из него фактически взаимодействует с драйвером устройства ОС для генерации случайных чисел. Некоторые реализации устройств также предоставляют доступ через /dev/urandom и даже /dev/arandom URI.

5. Что такого особенного в файле:/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 была обнаружена эта проблема в некоторых реализациях. Впоследствии ошибка была исправлена в соответствии с предложением по улучшению JDK для Java 8 (JEP 123) .

Использование URL-адреса, такого как file:/dev/./urandom или любого другого значения, заставляет SeedGenerator рассматривать его как URL-адрес исходного источника, который мы хотим использовать .

В Unix-подобных системах наш URL-адрес file:/dev/./urandom разрешается в тот же неблокирующий файл /dev/urandom .

Однако мы не всегда хотим использовать это значение. В Windows у нас нет этого файла, поэтому наш URL-адрес не разрешается. Это запускает последний механизм генерации случайности и может задержать нашу инициализацию примерно на 5 секунд.

6. Эволюция SecureRandom

Эффект java.security.egd изменился в различных выпусках Java.

Итак, давайте посмотрим на некоторые наиболее важные события, повлиявшие на поведение SecureRandom :

  • Ява 1.4

  • Проблема блокировки /dev/random, поднятая в JDK-4705093: используйте /dev/urandom, а не /dev/random, если он существует

  • Ява 5

  • Исправление для JDK-4705093

  • Добавляет алгоритм NativePRNG для соблюдения параметра java.security.egd , но нам нужно настроить его вручную .

  • Если используется SHA1PRNG , то он может заблокироваться, если мы используем что-либо кроме file:/dev/urandom. Другими словами, он может заблокироваться, если мы используем файл:/dev/./urandom

Понимание того, как изменился SecureRandom , дает нам представление о вероятном влиянии свойства java.security.egd .

7. Тестирование эффекта java.security.egd

Лучший способ убедиться в эффекте свойства JVM — попробовать его. Итак, давайте посмотрим на эффект java.security.egd , запустив некоторый код для создания нового SecureRandom и замерив время, необходимое для получения `` некоторых случайных байтов.

Во-первых, давайте создадим класс JavaSecurityEgdTester с методом main() . Мы установим время нашего вызова secureRandom.nextBytes() с помощью System.nanoTime() и отобразим результаты:

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");
}
}

Теперь давайте запустим тест JavaSecurityEgdTester , запустив новый экземпляр Java и указав значение для свойства java.security.egd :

java -Djava.security.egd=file:/dev/random -cp . com.foreach.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.foreach.java.security.JavaSecurityEgdTester
java -Djava.security.egd=file:/dev/./urandom -cp . com.foreach.java.security.JavaSecurityEgdTester
java -Djava.security.egd=foreach -cp . com.foreach.java.security.JavaSecurityEgdTester

В Windows, использующей Java 8 или Java 11, тесты со значениями file:/dev/random или file:/dev/urandom дают меньше секунды. Использование чего-либо еще, например, file:/dev/./urandom или даже foreach , делает наши тесты более 5 секунд!

Смотрите наш предыдущий раздел для объяснения того, почему это происходит. В Linux мы можем получить другие результаты.

8. Как насчет SecureRandom.getInstanceStrong() ?

В Java 8 появился метод SecureRandom.getInstanceStrong() . Посмотрим, как это повлияет на наши результаты.

Во-первых, давайте заменим наш новый SecureRandom() на SecureRandom. получитьInstanceStrong() :

SecureRandom secureRandom = SecureRandom.getInstanceStrong();

Теперь давайте снова запустим тесты:

java -Djava.security.egd=file:/dev/random -cp . com.foreach.java.security.JavaSecurityEgdTester

При запуске в Windows значение свойства java.security.egd не оказывает заметного влияния, когда мы используем SecureRandom.getInstanceStrong() . Даже нераспознанное значение дает нам быстрый ответ.

Давайте снова проверим наш вывод и заметим время менее 0,01 секунды. Давайте также заметим, что алгоритм теперь Windows-PRNG:

java.security.egd=foreach took 0.003 seconds and used the Windows-PRNG algorithm

Обратите внимание, что PRNG в названиях алгоритмов означает генератор псевдослучайных чисел.

9. Заполнение алгоритма

Поскольку случайные числа широко используются в криптографии для ключей безопасности, они должны быть непредсказуемыми.

Таким образом, то, как мы задаем наши алгоритмы, напрямую влияет на предсказуемость случайных чисел, которые они производят.

Чтобы создать непредсказуемость, реализации SecureRandom используют энтропию, собранную из накопленных входных данных, для заполнения своих алгоритмов. Это происходит от устройств ввода-вывода, таких как мыши и клавиатуры.

В 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 системный администратор может настроить генератор случайных чисел виртуального ввода-вывода, 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.

В заключение, мы можем прочитать больше о SecureRandom и о том, как он работает, в разделе SecureRandom Справочного руководства JCA и Спецификации API SecureRandom, а также узнать о некоторых мифах о urandom .

Как обычно, код можно найти на GitHub .