pbkdf2からBcryptへ移行

Photo by Farhan Siddicq on Unsplash

node.jsのデフォルトのモジュールにcryptoパッケージがあり、node.jsで認証を実装する場合に広く使われている。

crypto: 使い方

const crypto = require('crypto')
const salt = crypto.randomBytes(16).toString('hex')
const hash = crypto
.pbkdf2Sync('password', salt, 10000, 512, 'sha512')
.toString('hex')

このsalthashを保存しておき、入力されたpasswordを同様にhash化したものと検証する。

しかし、pbkdf2よりもBcryptのほうがアルゴリズムが強固であり、こちらを使った方が望ましい。

bcrypt: 使い方

const bcrypt = require('bcrypt')
const main = async () => {
const hash = await bcrypt.hash('pass', 10)
console.log(hash)
// => $2a$10$Q9ppTJAXdSlC5S8jNGa9K.JC00A5Gq5DfJV8jYLVccaGequxzbUUG
  const ok = await bcrypt.compare('pass', hash)
console.log(ok) // => true
  const ng = await bcrypt.compare('nopass', hash)
console.log(ng) // => false
}
main()

生成されたhashを保存しておきbcrypt.compareを使いpasswordと検証する。なぜ、ソルトを保存しなくていいかというと、hash値の8文字目から22文字が生成されたソルトであるからだ。生成されたhashは全てが暗号化されたパスワードではない。Hashに中身について見てみると以下のように分類できる。

$: セパレータ

2文字目~: 2a

暗号化のバージョン。2a が主流。

4文字目~: 10

コスト。暗号化を何回繰り返すか。ここが大きければ復号が困難になるが、サーバへの負荷が大きくなる。このライブラリのデフォルトは10。回数は2のn乗であるので、コストが10の場合1024回演算を行う。

8文字目~:Q9ppTJAXdSlC5S8jNGa9K.

この22文字がソルトと呼ばれるランダムで生成された文字列である。

~:JC00A5Gq5DfJV8jYLVccaGequxzbUUG

暗号化されたパスワード本体。


なぜBcryptではソルトを別に保存しなくていいのだろうと思ったが、生成されたHashにソルトが含まれていたからだった。

アルゴリズムは常に破られる可能性があるので、常にセキュリティを意識して開発する必要があります。今回は、pbkdf2からBcryptへ移行しました。何か議論があればコメントまたは、@akameco までお願いします。

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.