意味悲鳴

PythonとかUnityとか.技術ブログでしたが,研究ブログにシフトしました.

python3でbcryptを使ってパスワード認証をつくる

タイトルの通りです.試したら上手くいったやーつなのであまり当てにしないこと.参考文献は一番下にまとめて載っけています.

bcryptを使って.htpasswdファイルを生成してBASIC認証実装している日本人はビックリするほど存在していないようで.役に立つ人もいるかも,と思い投稿します.ひょっとしたらBASIC認証自体が弱いからわざわざこういうことしないってことなのかな.偉い人教えてください.

.htpasswdの生成

以下のコマンドでファイルを生成します.

htpasswd -Bcb .htpasswd user passwd

詳細について全部は説明しませんが,大文字のBがbcryptを使った暗号化を指定するオプションです.

\(๑╹◡╹)ノ>>>htpasswd                                                                      
Usage:
    htpasswd [-cimBdpsDv] [-C cost] passwordfile username
    htpasswd -b[cmBdpsDv] [-C cost] passwordfile username password

    htpasswd -n[imBdps] [-C cost] username
    htpasswd -nb[mBdps] [-C cost] username password
 -c  Create a new file.
 -n  Don't update file; display results on stdout.
 -b  Use the password from the command line rather than prompting for it.
 -i  Read password from stdin without verification (for script usage).
 -m  Force MD5 encryption of the password (default).
 -B  Force bcrypt encryption of the password (very secure).
 -C  Set the computing time used for the bcrypt algorithm
     (higher is more secure but slower, default: 5, valid: 4 to 31).
 -d  Force CRYPT encryption of the password (8 chars max, insecure).
 -s  Force SHA encryption of the password (insecure).
 -p  Do not encrypt the password (plaintext, insecure).
 -D  Delete the specified user.
 -v  Verify password for the specified user.
On other systems than Windows and NetWare the '-p' flag will probably not work.
The SHA algorithm does not use a salt and is less secure than the MD5 algorithm.

上記のマニュアルを見れば分かる通り,他の暗号化オプションはだいたいinsecureと記載されているので,みんなbcryptを使おうなというお話のようです.調べた限りでは,実際他よりも安全らしい.

Python上での実装

生で実装とか無謀なので,ライブラリ使います.

pip install bcrypt

あとはライブラリに実装されている関数を使う.が,その前に.htpasswdそのものの中身を開かないといけない.

import bcrypt
def basic_check(user, password):
    passwd_file = open(root_path + "/../config/.htpasswd", mode="r")
    hashed_line = passwd_file.readline()
    passwd_file.close()
    hashed_user, hashed_passwd = hashed_line.strip().split(":")

strip()でファイルに含まれる改行を取り除いて,split()でユーザ名とパスワードをわけて代入するところがミソ.↑の関数内に以下のような一文を加えて判定する.

return bcrypt.hashpw(password.encode("utf-8"), hashed_passwd.encode("utf-8")) == hashed_passwd.encode("utf-8") \
       and user == hashed_user

bytesにしないといけないので忘れてはいけない.あとはこれをWebアプリなりなんなりに実装する.

以下参考文献.

pythonでbottleで暗号化パスワード(.htpasswd)でのBasic認証 - Qiita

Salt and pepper - How to encrypt database passwords

CRYPT_BLOWFISHのアルゴリズム$2a$, $2x$, $2y$について英語のドキュメントを読んでみた | kanonjiのブログ

python - Why can bcrypt.hashpw be used both for hashing and verifying passwords? - Stack Overflow

python - How to store and compare password in db using py-bcrypt - Stack Overflow