[Node.js] Math.random()よりセキュアな乱数を生成する

  • このエントリーをはてなブックマークに追加
  • LINEで送る
この記事は 2019年7月14日 に書かれたものです

JavaScriptで乱数を利用したい場合はMath.random()を使うことがほとんどだと思いますが、内部のロジック的に暗号などセキュアな用途には向いていないとされています。Node.jsでは標準モジュールであるcryptoを利用することでこの問題を解決することができます。

サンプルコード

結論から言うと具体的なコードは以下になります。getSecureRandom()関数を実行する度にランダムな整数を取得できます。

const Crypto = require("crypto");

function getSecureRandom(){
  const buff = Crypto.randomBytes(8);  // バイナリで8byteのランダムな値を生成
  const hex  = buff.toString("hex");   // 16進数の文字列に変換

  return ( parseInt(hex,16) );         // integerに変換して返却
}
- Sponsored Link -

パフォーマンス

気になるのは実行時の速度ですね。もちろんcryptoモジュールのほうが重たいのは想像できるのですがどの程度の差が生まれるのか計測してみましょう。今回は以下の2種類のコードを用意しました。

Math.random()版

Math.random()を100万回実行するシンプルなコードです。

for(let i=0; i<1000000; i++){
  Math.random();
}

crypto版

こちらも同様に100万回実行します。

const Crypto = require("crypto");
for(let i=0; i<1000000; i++){
  const buff = Crypto.randomBytes(8);
  const hex  = buff.toString("hex");
  parseInt(hex,16);
}

実行結果

前者がMath.random()、後者がcryptoモジュールです。

$ time node test1.js
node test1.js  0.09s user 0.03s system 91% cpu 0.132 total

$ time node test2.js
node test2.js  4.04s user 0.17s system 105% cpu 3.997 total

最終的な実行スピードだけ見るとなんと約30倍の差があることがわかりました(3.997/0.132)。ちなみにCrypto.randomBytes()で生成するバイト数を2〜4に減らしても結果はそれほど大きく変わりませんでした。

ゲームやアニメーションのようなパフォーマンスを求められる場面では普通にMath.random()を使ったほうが良さそうですね。まぁそもそも使わないと思いますがw

なお今回実行したNodeのバージョンは以下になります。

$ node --version
v12.6.0

Webブラウザの場合

GoogleChromeなどWebブラウザで実行する場合はwindow.crypto.getRandomValues()で同様にセキュアな乱数を生成可能です。具体的なコードはMDNを参照ください。

執筆時点(2019-07-14)だと「Can I use」によると96.3%のブラウザが利用可能なようです。

参考ページ

コメント

コメント欄は休止中です。お問い合わせはこちらからどうぞ。ご質問はTwitterにリプを投げてください。

このブログを応援する

お寄せいただいたお気持ちは全額サーバ代や次の記事を執筆するための原資として活用させていただいております。この記事が参考になった場合などぜひご検討ください。

PayPal(ペイパル)
PayPalで300円支払う
※金額は任意で変更できます。
※100円でも泣いて喜びますw
※住所の入力欄が現れた場合は「no needed」を選択ください
これまでのご協力者さま
- Sponsored Link -