# Java 中的安全随机数生成

> 原文： [https://howtodoinjava.com/java8/secure-random-number-generation/](https://howtodoinjava.com/java8/secure-random-number-generation/)

如果您已经开发软件已有一段时间，那么您就会知道如何使用 Java 的`SecureRandom`类甚至甚至安全地生成随机数。 不幸的是，生成*安全随机数*并不像简单地使用`SecureRandom`那样容易。

在此 Java 示例中，我们组装了一个简单的清单，以帮助您在应用程序中使用安全随机数时获得成功。

> 阅读更多：[用 Java](https://howtodoinjava.com/security/how-to-generate-secure-password-hash-md5-sha-pbkdf2-bcrypt-examples/) 生成安全哈希

## 1\. 如何生成安全的随机数

通常，随机数的生成取决于熵（随机性）的来源，例如信号，设备或硬件输入。 在 Java 中，`java.security.SecureRandom`类被广泛用于生成密码强的随机数。

确定性随机数已成为许多软件安全漏洞的根源。 这个想法是，给定几个随机数样本，对手（黑客）应该无法确定原始种子。 如果违反了此限制，则对手可能会成功预测所有将来的随机数。

```java
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

public class Main 
{
	public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchProviderException 
	{
		SecureRandom secureRandomGenerator = SecureRandom.getInstance("SHA1PRNG", "SUN");

		// Get 128 random bytes
		byte[] randomBytes = new byte[128];
		secureRandomGenerator.nextBytes(randomBytes);

		//Get random integer
		int r = secureRandomGenerator.nextInt();

		//Get random integer in range
		int randInRange = secureRandomGenerator.nextInt(999999);
	}
}

```

## 2\. 安全随机数 - 最佳做法

#### 2.1 确定性能标准和工作负载平衡

如果性能是首要考虑因素，请使用`SHA1PRNG`，它是`/dev/urandom`的种子。`SHA1PRNG`可以比`NativePRNG`快 17 倍，但播种选项是固定的。

使用`NativePRNG`进行播种更加灵活，但是如果服务器上的熵不够大（因为它从`/dev/random`读取），它将阻止。 如果您不知道从哪里开始，请从`SHA1PRNG`开始。

#### 2.2 不接受默认值； 指定 PRNG 和要使用的供应器

像这样指定您的条件：

```java
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
```

以下是有关受支持的 PRNG 和供应器的其他信息。

以下是 SUN 供应器的 PRNG 列表：

*   **`SHA1PRNG`**（目前，初始播种是通过系统属性和`java.security`熵收集设备的组合完成的）
*   **`NativePRNG`**（`nextBytes()`使用`/dev/urandom`，`generateSeed()`使用`/dev/random`）
*   **`NativePRNGBlocking`**（`nextBytes()`和`generateSeed()`使用`/dev/random`）
*   **`NativePRNGNonBlocking`**（`nextBytes()`和`generateSeed()`使用`/dev/urandom`）
*   **`NativePRNGBlocking`**和**`NativePRNGNonBlocking`**在 JRE 8+ 中可用。

有关其他供应器的信息，请参见 [Java 密码架构 JDK 8 的 Oracle 供应器文档](https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html)。 Oracle 还提供了按 OS 平台描述供应器的文档。

#### 2.3 提供更多机会增加熵

定期创建`SecureRandom`的新实例并重新设定种子，如下所示：

```java
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "SUN");
sr.setSeed(SecureRandom.generateSeed(int))
```

如果种子泄漏，定期重新播种可防止数据泄露。 如果使用`SHA1PRNG`，则始终在创建 PRNG 的新实例后立即调用`java.security.SecureRandom.nextBytes(byte[])`。

#### 2.4 降低可预测性

如果为`egdSource`，`java.security`文件中的配置参数或`java.security.egd`系统属性分配了可预测的文件/ URL，则`SecureRandom`可以变为可预测的。

#### 2.5 旧版 Java 的补丁

低于 1.4.2 的 JRE 版本在生成`SHA1PRNG`安全种子方面存在已知问题。 再说一次，如果您使用的 Java 版本如此之旧，则存在更大的安全隐患。

Java 的旧版本非常不安全，因此更新补丁程序非常重要。 确保客户安全的最佳方法之一是针对可能出现的最新 [Oracle 重要补丁更新](https://www.oracle.com/technetwork/topics/security/alerts-086861.html)快速认证您的软件。

学习愉快！