Webサービスののログイン機能で必要なパスワードですが、ユーザーがセキュリティに配慮したパスワードを考えるのは難しいです。
最近ではプログラムで自動でパスワードを生成するのが当たり前になり、仕組みをザックリ言うと「ランダムに文字を組み合わせる」ということをやっています。
今回はJavaScriptを使って自動でランダムなパスワードを作るパスワードジェネレータの実装方法を紹介します。
登場するアルゴリズムは初心者でも理解できるものしか使用していないのでぜひ最後までご覧ください。
また動画もあるのでお好みでどうぞ。
JavaScriptでパスワード自動生成させる方法
まず簡単にパスワードのフォームをHTMLで作ります。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="./script.js" defer></script>
</head>
<body>
<div class="container">
<div>
<input type="text" id="inputPass" />
</div>
<div>
<button id="btn">パスワード生成</button>
</div>
</div>
</body>
</html>
登場する要素は「入力欄」「実行ボタン」の2つだけです、JavaScriptで要素の取得をしておきます。
今回作っていくものは「ボタンをクリックすると自動でパスワードを作って入力欄に表示する」というものを想定しています。
パスワードを自動生成する部分は「createPass」という名前で関数にして作っていきます。
ボタンをクリックするごとにcreatePassが実行されてパスワードが自動生成される予定です。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
// ボタンをクリックしたらcreatePassを実行する
btn.addEventListener("click", createPass);
function createPass() {
//パスワードを生成する処理
}
それでは関数createPassの中身を作っていきましょう。
パスワードを自動で生成する場合、基本的にはプログラム側で「パスワードの素材」「パスワードの桁数」を事前に用意しておくことになります。
パスワードの素材となり得るものは、
・小文字の英語
・大文字の英語
・半角数字
・半角記号
がメインの候補です。
パスワードの桁数については多ければ多いほどセキュリティが高まりますが、一般的に言われているのは「8文字以上」というものです。
今回は「小文字の英語」「半角数字」の2点を使って「8桁」のパスワードを作ることにします。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
btn.addEventListener("click", createPass);
function createPass() {
//ここから追加
//文字の素材
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
// パスワードの長さは8文字
const passLength = 8;
}
素材と桁数をもとにパスワードを作るのですが、ザックリ仕組みを説明すると「素材からランダムな位置から1文字選ぶ」ということを8回繰り返します。
8回繰り返すのは今回のパスワードは8桁で作ることを決めたためなので、桁数が増えると繰り返す回数も合わせることになります。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
btn.addEventListener("click", createPass);
function createPass() {
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
const passLength = 8;
//ここから追加
let password = "";
for (let i = 0; i < passLength; i++) {
// 素材からランダムな位置から1文字選ぶ処理
}
}
変数passwordを初期値を空文字として用意しておき、for文で8回分だけ回して変数passwordに1桁ずつ文字をセットしていく形です。
続いてfor文の中を作っていきましょう。
まず素材である定数strからランダムに1文字を選ぶのは以下のようにします。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
btn.addEventListener("click", createPass);
function createPass() {
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
const passLength = 8;
let password = "";
for (let i = 0; i < passLength; i++) {
// ここから追加
console.log(Math.floor(Math.random() * str.length));
}
}
まだコンソールに表示するだけにしておいて、画面上からボタンを1回だけクリックしてみましょう。
ランダムな数字が8桁分だけ表示されていますね。
またブラウザをリロードしてクリックし直すと違う数字が8桁並ぶようにもなっています。
まずJavaScriptではMath.random( )とするとランダムな数字を自動で作ってくれます。
しかし1点だけ問題があってMath.random( )で作ってくれるランダムな数字は「0以上1未満の数字のみ」ということです。
どういうことかと言うと単純にMath.random( )だけ実行すると以下のような結果になるからです。
ランダムな数字ではあるものの一般的に考えて少し使いづらいですよね。
そこでMath.random( )で作った上図の数字に素材の桁数を掛けます。
素材の桁数とは定数strで用意している文字の数のことです。
定数strで用意している文字の数は今回の場合だと「36個」です。
とはいえ素材の中身が将来的に変わることも考えられるので「36」ではなく、「str.length」としておきます。
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
// str.lengthで定数strにある文字の数を数えてくれる。
ランダムの数字を「Math.random( )」でそのまま作るのではなく「Math.random( ) * str.length」とすることで以下のようにになります。
これでランダムな数字が「0以上の数字」になりました。
ランダムな数字が「0以上の数字」になったおかげで「定数strの文字が36個あるなかで左から○番目の文字を選ぶ」ということが可能になったわけです。
ちなみになぜ上図のようになるかは簡単で、Math.random( )が何をしているかをもう一度思い出してみましょう。
Math.random( )は上図のように「0以上1未満の数字」になる仕組みでした。
「0以上1未満」ということは考えられる最小値は「0」で最大値は「0.99….」です。
また素材が入っている定数strの中身は36個ですので、それぞれ掛け算すると
・最小値:0 * 36 = 0
・最大値:0.99… * 36 = 35.99…
になるわけです。
つまり素材が入っている定数strの中身を並んでいる順番で指定したい時に0番目〜35番目ということで綺麗に選ぶ範囲が36パターンになるというカラクリです。
最後に小数点ありの数字ではなく整数でやりたいのですが、JavaScriptではMath.floor( )の引数に小数点ありの数字を入れると自動で整数に変換してくれます。
そのため最初にお見せした「Math.floor(Math.random() * str.length)」という式が完成します。
〜省略〜
for (let i = 0; i < passLength; i++) {
console.log(Math.floor(Math.random() * str.length));
}
}
もう一度おさらいすると以下の3ステップです。
①Math.random( )で「0以上1未満」のランダムな数字を出す
②素材の文字数だけを①に掛け合わせる
③Math.floor( )で小数点をなくす
以上3ステップによって「素材の文字のうち左から○番目」という指定をするための数字をランダムに生成することができます。
アルゴリズムはいきなり理解できなくても大丈夫です。
1個ずつ細かくしてコンソールログで確認して理解してみてください。
コードの続きを作っていきましょう。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
btn.addEventListener("click", createPass);
function createPass() {
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
const passLength = 8;
let password = "";
for (let i = 0; i < passLength; i++) {
// ここから追加
let selected = Math.floor(Math.random() * str.length);
password += str.substring(selected, selected + 1);
}
}
ランダムな整数を生成するための「Math.floor(Math.random() * str.length)」の結果を変数selectedに格納しました。
さらに変数selectedで生成したランダムな整数を使って、実際のパスワードになる変数passwordに文字を1文字セットします。
1文字セットするのはJavaScriptの場合「+=」とすればOKです。
また素材の文字が入っている定数strにsubstring( )という関数を使うことで定数strの中から1文字を取得しています。
substring( )は引数を2つ取り、第一引数に「取得する開始位置」で第二引数に「取得する桁数」を指定します。
第一引数にはランダムな整数である変数selectedにしていて、0〜35のどれかの数字が入ることになります。
第二引数は取得する桁数ということで今回は1桁なので「1」にします。
substring( a, a+1 )という具合に引数を指定すれば「1桁だけ取得する」という意味になります。
あとはfor文を8回分だけ回すので変数passwordに定数strの中からランダムに取得された文字が8桁分だけセットされていくことになります。
最後に入力欄に完成したパスワード候補(変数password)を表示したいので、inputタグのvalueに変数passwordをセットします。
const inputPass = document.querySelector("#inputPass");
const btn = document.querySelector("#btn");
btn.addEventListener("click", createPass);
function createPass() {
const str = "0123456789abcdefghijklmnopqrstuvwxyz";
const passLength = 8;
let password = "";
for (let i = 0; i < passLength; i++) {
let selected = Math.floor(Math.random() * str.length);
password += str.substring(selected, selected + 1);
}
// ここから追加
inputPass.value = password;
}
画面上の動きを確認してみましょう。
ブラウザをリロードしてボタンをクリックします。
ボタンをクリックするとランダムな8桁の文字列が入力欄に表示されています。
さらにクリックするたびに8桁の中身がランダムに変わっていくのも確認できますね。
パスワード自動生成は何となく難解な仕組みに見えて、実際には非常に簡易的なコードによって実現できます。
もちろんゼロベースから自力でアルゴリズムを考えるのは難しいかもしれませんが、本記事を含め誰かが作ったものを理解して真似するのであれば初心者でも対応できると思います。
今ではバリバリのエンジニアの方でも最初は誰かのコードを理解して真似することから始めていますので、初心者の方もマイペースに少しずつ練習していきましょう。