パスワードを保存しない
CoddyのNode.jsジャーニー「認証とセキュリティ」セクションの一部。レッスン 1/17。
データベースが漏えいすると、入力されたままのパスワードはすべて読み取られてしまいます。また、同じパスワードをほかのサイトでも使っている人がいます。そのため、代わりにハッシュを保存します。ハッシュとは、パスワードから計算され、元のパスワードに戻すことができない値です。
パスワードの処理には、Node の crypto.scrypt が使えます。意図的に処理が遅くなっているため、何百万ものパスワードを推測するには、攻撃者は何時間もかかります。ハッシュ化の前に混ぜるランダムなバイト列であるソルトを使うと、同じパスワードを使っている2人でも、異なるハッシュが得られます。ソルトは秘密にする必要はありません。ハッシュと一緒に保存します。
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
const salt = randomBytes(16).toString('hex');
const key = await scryptAsync('pin 4821', salt, 32);
console.log(key.toString('base64'));promisify は、scrypt のコールバックを await できる promise に変換します。
チャレンジ
簡単passwords.jsで、hashPassword(password)がsalt:hashを返すようにします。16個のランダムなソルトバイトと64バイトのscryptキーを、どちらも16進数で返します。GET /debug/users/:usernameで、サインアップ時に保存された内容を確認できます。
実行を押します。POST /signupに{"username": "ada", "password": "correct horse"}を送信し、次に同じパスワードでbobを登録してから、2人のユーザーを比較します。
自分で試してみよう
import { randomBytes, scrypt } from 'node:crypto';
import { promisify } from 'node:util';
const scryptAsync = promisify(scrypt);
// パスワードをsignupが保存するテキストに変換します。
// 現時点では、パスワードを入力されたままの形で保持します。
export async function hashPassword(password) {
return password;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。