環境
PHP 7.1
Python 2.7.6
確認したいこと
現在、PHP で新規開発をしていて、パスワードの暗号化に password_hash
を使用している。
かなり先のことだが、将来的に別の言語(ここでは Python)に移行した際に、暗号化したパスワードが同じように使えるのか疑問
つまり、 Python に移行してもユーザーのパスワードの照合が正常にできて、ログインできることを確認したい。
もう少しミクロな言い方をすると、 password_hash
は Blowfish という暗号化アルゴリズムを使用しているので(後述)、Python でも Blowfish が使えて照合できるかを確認したい。
PHP で暗号化する
password_hash('password', PASSWORD_DEFAULT);
// $2y$10$BN2hH0B3gnZceNlW1JXiNOUN8NWybLlfqZh6WQ/imah4htM8fktFW
password_hash('password', PASSWORD_BCRYPT);
// $2y$10$CuZkO0N29B1YtHHI9mwvIOCSUitQh4ptyfxYWvHhHoHHP2GZqC5Ga
解説
password_hash
では現在、PASSWORD_DEFAULT と PASSWORD_BCRYPT という 2 種類の定数を指定できる。
http://php.net/manual/ja/function.password-hash.php
定数の中身を確認してみた(スタブだけど)
define("PASSWORD_DEFAULT", 1);
define("PASSWORD_BCRYPT", 1);
結局 PASSWORD_DEFAULT も PASSWORD_BCRYPT も同じ値を指している。
この場合、Bcrypt での実装になる。
Bcrypt ≒ Blowfish なので、現在の password_hash
の暗号化アルゴリズムは必ず Blowfish になるもよう。
※ Bcrypt の解説はここが分かりやすかった
https://goo.gl/kpS5En
※他の暗号化アルゴリズムを使いたかったら Crypt
を使えばできそう
http://php.net/manual/ja/function.crypt.php
Python で照合できるか確認
import bcrypt
password = b'password'
phpHash = '$2y$10$BN2hH0B3gnZceNlW1JXiNOUN8NWybLlfqZh6WQ/imah4htM8fktFW'
if bcrypt.checkpw(password, phpHash):
print("It Matches!")
else:
print("It Does not Match :(")
# It Matches!
無事にマッチした
解説
- bcrypt モジュールを用いて、PHP で暗号化したパスワードがマッチするか確認している
- 事前に bcrypt というモジュールのインストールが必要
-
bcrypt.checkpw
が PHP で言うpassword_verify
にあたる
マメ知識(知らなかっただけ)
PHP の password_hash
を用いて生成した値の暗号化バージョン(1番左の部分)は $2y$
になる。
しかし Python の bcrypt モジュールを用いて生成する場合、暗号化バージョンは $2a$
と $2b$
のみしか指定できないもよう。
salt = bcrypt.gensalt(rounds=10, prefix=b'2a')
password = b'password'
hashed = bcrypt.hashpw(password, salt)
※prefix
の部分
これでは同じパスワードとみなしてくれないのでは? と思ったが、上述の通りマッチした。
逆に bcrypt.hashpw
で生成した値を password_verify
で照合しても無事にマッチした。
つまり、暗号化バージョンが $2a$
と $2y$
のように異なっていても同じパスワードとして認識してくれるので、将来的に Python に移行した際にわざわざ $2y$
を $2a$
に置換するなどの処理は不要。