likes
comments
collection
share

用JavaScript和Node.js构建一个随机数发生器

作者站长头像
站长
· 阅读数 10

简介

在一些使用情况下,一个程序可能需要一个安全的随机数生成源。通常情况下,我们需要随机数用于游戏功能,如骰子或抽奖,私钥生成,或其他类似的程序,需要一个加密的安全源。

在JavaScript中,我们有Math 对象中的random() 方法的本地实现,该对象是一个内置的对象,具有用于执行数学计算的属性或方法。random() 方法帮助我们生成随机数,顾名思义。

Math.random() 方法返回一个十进制数或浮点数,在零(包括)和一(不包括)之间的伪随机数。在数学术语中,这被表示为0 >= x < 1

虽然有不同的方法来使用这个方法在某些范围内产生随机结果,但Math.random() 并不是一个真正的随机数发生器。这是因为它是伪随机的;随着时间的推移,数字会开始重复,最终显示出非随机的模式。正如你可能知道的,计算机很难生成真正的随机数。

然而,虽然由Math.random() 生成的伪随机数通常在大多数情况下是足够的,但有时我们需要一个加密安全的随机数生成源。我的意思是,我们想要的随机数不能轻易通过模式来猜测,或者最终会随着时间的推移而重复。

在这篇文章中,我们将重点介绍这些情况下的推荐方法。但在此之前,让我们研究一下Math.random() 方法的一些基本用例,这样我们就可以学习在JavaScript中生成随机数的最简单方法。

Math.random() 方法在JavaScript中的使用情况

Math.random() 返回一个非加密的随机数,它从一个被称为 "种子 "的隐藏内部表示开始。种子代表了在指定范围内均匀生成的隐藏数字序列的起点。这个方法的一些用例解释如下。

Math.random() 方法的第一个(也是最简单的)用例是生成0到1之间的随机小数或浮点数字。

const randomNumber = Math.random()
console.log(randomNumber) outputs -&gt; //0.8446144685704831

请注意,通过生成零到一之间的随机数,我们可以通过将随机数与另一个数字相乘,将结果扩大到我们需要的任何大小。

比如说。

const max = 6
const randomNumber = Math.floor(Math.random() * max)
console.log(randomNumber) outputs -&gt; 0,1,2,3,4,5 

这个方法的另一个用例是用Maths 对象中另一个名为floor 的方法生成两个特定整数范围之间的随机整数。floor 方法返回小于或等于指定数字的最大整数。

我们可以在一个指定的范围内生成一个浮点数,就像下面的例子。

// generating floating point numbers within a range
const max = 4
const min= 2
const result = Math.random()*(max - min)
console.log(result) //1.4597999233994834

// generating random integers within a range
const max = 4
const min= 2
const result = Math.random()*(max - min) + min
console.log(Math.floor(result))//3

Math.random() 函数的其他用例包括在某个指定范围内生成具有最大限制的随机数。在这里,我们可以利用ceil ,即Maths 对象中的另一个方法。

现在,在下一节中,让我们探讨一下利用这些伪随机数生成器的一些弊端。

中的安全隐患Math.random()

Math.random() ,在安全方面有几个缺点。根据MDN文档,Math.random() 并不能保证随机数的加密安全。因此,建议在我们的程序中不要用它们来做与安全有关的事情。

这些安全缺陷部分是由于以下原因。

  • 在均匀分布范围内生成随机整数时采用的逻辑不充分,而且通常有偏见
  • 浏览器在利用多少比特/字节的随机性方面的不一致
  • 随机结果总是难以持续重放,使其具有非决定性和不规则性
  • 内置的种子可以被篡改,使其在完整性方面不适合。

由于这些漏洞,万维网联盟提出了一个网络加密API的实现。在撰写本文时,所有流行的浏览器都通过crypto 对象为JavaScript应用程序提供了该API的实现。

让我们快速了解一下Web Crypto API以及如何使用它。

Web Crypto API简介

Web Crypto API提供了许多加密方法和函数,可以通过Window.crypto 属性访问。在浏览器中,我们可以利用crypto.getRandomValues(Int32Array) ,该方法承诺以加密方式生成随机数字。

在服务器端,Node.js也提供了一个标准Web Crypto API的实现。为了利用这个模块,我们可以用require('crypto').randomBytes(size) 来初始化它,因为加密包是Node的本机。

在Web Crypto API中使用的伪随机数生成器算法(PRNG)可能在不同的浏览器客户端中有所不同。然而,只要内部种子有足够的熵,它适用于大多数加密目的,可能来自外部来源,如Unix/dev/urandom

在下一节中,我们将讨论如何利用Web Crypto API,包括语法、我们可以传递的参数和返回值。让我们从下面的基本用法开始。

使用Web Crypto API

Crypto.getRandomValues() 方法让我们获得加密强度高的随机值。 从本质上讲,Crypto 接口代表了一种通用的加密功能。

它在大多数网络浏览器中都可以使用,虽然实现方式可能不同,但都需要使用一个具有足够熵的种子。这是为了确保不会对性能和安全产生负面影响。

getRandomValues() 方法是Crypto 接口的唯一成员,可以从不安全的环境中使用。因此,在生成加密密钥时不建议使用,因为它们不能保证返回安全的结果。在这种情况下,我们可以使用generateKey()方法。

现在,让我们看看网页加密API的getRandomValues 方法的语法、接受的参数和返回值。

语法

网络密码学API接受ArrayBuffer 类和TypedArray 的实例作为输入,以表示字节序列。

请看下面的语法。

typedArray = cryptoObj.getRandomValues(typedArray);

参数

typedArray 是一个基于整数的TypedArray 对象。它可以是一个Int8Array ,一个Uint8Array ,一个Int16Array ,一个Uint16Array ,一个Int32Array ,或者一个Uint32Array

注意,数组中的所有元素都是用随机数填充的。

返回值

返回值是作为typedArray 传入的同一个数组,但其内容被新生成的随机数所取代。

在下一节中,我们将看看如何编写一个简单的程序来生成安全的加密随机数。

生成随机数

你为安全目的需要的每一个随机值(即任何存在攻击者可能性的地方),都应该使用加密安全伪随机数生成器,也被称为CSPRNG来生成。

这包括验证或重置令牌、抽奖号码、API密钥、生成的密码、加密密钥等等。

那么,我们如何才能生成安全、可靠的随机数呢?最好的选择是采用一个库,在设计上照顾到这些安全问题。在Node中,我们有几个选择。

  • 对于生成范围内的随机数,有一个随机数-csprng,它使用引擎盖下的Crypto API。
  • 对于API密钥或令牌**,**有uuid,特别是uuid.v4() 函数。

让我们看看下面的一个例子。

旋转一个简单的Node应用程序,采用npm包中最简单的例子。

var Promise = require("bluebird");
var randomNumber = require("random-number-csprng");

Promise.try(function() {
    return randomNumber(10, 30);
}).then(function(number) {
    console.log("Your random number:", number);
}).catch({code: "RandomGenerationError"}, function(err) {
    console.log("Something went wrong!");
});

Output shown below: 
retina@alexander random-number-generator % node index.js 
Your random number: 24
retina@alexander random-number-generator % node index.js
Your random number: 14
retina@alexander random-number-generator % node index.js
Your random number: 20
retina@alexander random-number-generator % node index.js
Your random number: 21
retina@alexander random-number-generator % node index.js
Your random number: 11
retina@alexander random-number-generator % node index.js
Your random number: 26
retina@alexander random-number-generator % node index.js
Your random number: 23
retina@alexander random-number-generator % node index.js
Your random number: 15
retina@alexander random-number-generator % node index.js
Your random number: 22
retina@alexander random-number-generator % node index.js
Your random number: 28

正如在上面的例子中看到的,我们可以在一个范围内生成加密安全的伪随机数。randomNumber 方法返回一个承诺,该承诺解析为指定范围内的一个随机数。更多细节可以在GitHub存储库的API部分找到。

在Node.js中使用Web Crypto API

Node.js提供了一个标准Web Crypto API的实现,尽管在撰写本文时,它仍然是该语言的一个实验性功能。

我们可以在Node中通过调用require('crypto').webcrypto 来使用这个模块。这将返回一个Crypto 类的实例,它提供了对加密API其余部分的访问。

正如我们前面所讨论的,crypto.getRandomValues(typedArray) 生成密码学上的强随机值。关于Node中网络加密API的更多细节可以在Node文档中找到。

结论

真正的随机性,即没有模式或算法适用的随机性,是否真的存在是值得商榷的。然而,对于安全相关的代码,我们需要一个攻击者无法预测的随机数。在这种情况下,数据是如何产生的并不重要,只要它不能被猜到。

为此,万维网联盟发布了Web Cryptography API,它允许浏览器中的JavaScript应用程序使用常见的加密功能,而无需使用任何第三方库。

而正如我们前面提到的,这个API的crypto.getRandomValues 方法是网络应用程序获得加密安全的随机数据的最安全方式。

Web Crypto API的所有其他功能都可以通过crypto.subtle 对象访问。这里可以找到网络加密标准的链接。

感谢阅读用JavaScript和Node.js构建一个随机数发生器 ,请不要犹豫,将你的问题或评论写在下面的部分。

The postBuilding a random number generator with JavaScript and Node.jsappeared first onLogRocket Blog.