読者です 読者をやめる 読者になる 読者になる

Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

generate_password_hashが毎回違う結果を返すのにパスワードとして使える理由

改めて読むと勉強になる。確かにここは気になる。


python - Flask - generate_password_hash not constant output - Stack Overflow

Flaskでは色んなスニペットが登録されており、パスワードのハッシュについても項目がある。ベストプラクティスを提示してくれている。

Salted Passwords | Flask (A Python Microframework)

from werkzeug.security import generate_password_hash, \
     check_password_hash

class User(object):

    def __init__(self, username, password):
        self.username = username
        self.set_password(password)

    def set_password(self, password):
        self.pw_hash = generate_password_hash(password)

    def check_password(self, password):
        return check_password_hash(self.pw_hash, password)

generate_password_hashメソッドは実行すると毎回返ってくる値が違う。それでも、check_password_hashを使って元の文字列を入れてみると生成されたハッシュ値が違ってもTrueを返してくる。この仕組みはどうなっているのか、改めて学んでみた。

ハッシュとソルト

徳丸先生が解説している。ハッシュ値はSaltがなければ平文同然のセキュリティでしか無いことがよく分かる。任意長のデータを固定長のデータに圧縮することがハッシュ、ハッシュ値を計算する前にパスワードの前後に付け加える短い文字列がソルト。

本当は怖いパスワードの話(3/4) − @IT

上記にあるレインボーテーブルというハッシュ文字列を解読する攻撃用の対策として、generate_password_hashではsaltをその都度生成し、かつ総当り攻撃対策として1,000回計算して返している。これにより、別のユーザーが同じパスワードを利用していたとしても、全く別のハッシュ値が求められ、レインボーテーブル攻撃をほぼ無効化できる、という。

ログイン認証

毎回求めるハッシュが違うことが前提になる。メアド(当然UNIQUE INDEXついている前提)とパスワードにてログインする場合においては、「メアドをキーに検索し、ヒットすればハッシュしたパスワードをチェックする」というロジックになる。

user = User.query.filter_by(email = self.email.data.lower()).first()
    if user and user.check_password(self.password.data):
      return True
return False

CakePHPの場合はsaltの文字列をconfig.phpにベタに書くので、入力パスワードをSecurityComponentでハッシュしてemailとパスワードをチェックする格好だった。どっちがよりセキュアなんだろう。55:45ぐらいなのかな。