事の発端
webシステム初心者として認証するときにパスワードをどのように扱えばいいかよくわからない。
とりあえず以下のことに気をつけたい。
- frontend → backend へusername、passwordをPOSTする際に、平文は避けたい
- DBに登録しておくパスワードは平文で保存したくない
- DBに登録したパスワードは、簡単に復号化させたくない
構成
- frontendはjavascript/typescript でcrypto が使えれば何でも良いはず
- backendも同様にjavascript/typescript でcrypto、bcrypt が使えること。expressを想定しています
- 認証するのは独自のユーザ情報が格納されたDB内のデータで認証
どうやって暗号化・復号化するかしてDBに格納するか
こちらの記事を参考にさせていただきました。
bcryptに関してはこちらの記事を参考にされていただきました。
流れはこんな感じ。
とりあえず、frontend、backendの両方で以下のような関数とパスフレーズを保持。
import crypto from 'crypto';
const passphrase = 'hogehoge';
const algorithm = 'aes-256-ctr';
function encrypt(pass: string): string {
const cipher = crypto.createCipher(algorithm, passphrase);
let crypted = cipher.update(pass, 'utf8', 'base64');
crypted += cipher.final('base64');
return crypted;
}
function decrypt(decryped_pass: string): string {
const decipher = crypto.createDecipher(algorithm, passphrase);
let dec = decipher.update(decryped_pass, 'base64', 'utf8');
dec += decipher.final('utf8');
return dec;
hash化は以下の処理で生成。
import bcrypt from 'bcrypt';
let hashed_password = bcrypt.hashSync(password, 10);
どうやって認証させるか
流れはこんな感じ。
まずはDBに保存するためのhash化。ユーザ登録時にはこのhash化した値をパスワードとして保存。
entity はちょっと省きますが、こんな感じでusernameに紐づくデータを
検索して、見つかったらパスワードを復号化し、hash値と比較。
import bcrypt from 'bcrypt';
import { createConnection, getRepository } from "typeorm";
import { User } from "../entity/User";
const user = getRepository(User).findOne({username: username});
if (user) {
const dec = decrypt(req.body.password);
if (bcrypt.compareSync(dec, hash_password)) {
res.sendStatus(200);
}
}
res.sendStatus(401);
とりあえず、こんな感じでやれば目的は達成できてるんじゃないかな。。。
ここまでお付き合いしていただきありがとうございます。