124

最近、インターネットで偶然見つけたログイン スクリプトに独自のセキュリティを実装しようとしています。ユーザーごとにソルトを生成する独自のスクリプトを作成する方法を学ぶのに苦労した後、私はpassword_hash.

私が理解していることから (このページの読み取りに基づいて)、 を使用すると、行にソルトが既に生成されていますpassword_hash。これは本当ですか?

私が持っていた別の質問は、2つの塩を持つのは賢明ではないかということでした. ファイルに直接1つ、DBに1つ?そうすれば、誰かが DB であなたのソルトを危険にさらしたとしても、ファイルに直接ソルトが残っていますか? ここで、塩を保存することは決して賢明な考えではないことを読みましたが、人々がそれを意味することを常に混乱させていました.

4

6 に答える 6

8

はい、それは本当だ。関数に関するphp faqを疑うのはなぜですか? :)

running の結果には、次のpassword_hash()4 つの部分があります。

  1. 使用されるアルゴリズム
  2. パラメーター
  3. 実際のパスワード ハッシュ

ご覧のとおり、ハッシュはその一部です。

確かに、セキュリティ層を追加するためにソルトを追加することもできますが、正直なところ、通常の php アプリケーションではやり過ぎだと思います。デフォルトの bcrypt アルゴリズムは優れており、オプションのフグのアルゴリズムは間違いなくさらに優れています。

于 2015-05-16T18:38:31.647 に答える
6

PHP のパスワード関数に組み込まれている後方互換性と前方互換性については、明らかに議論が不足しています。特に:

  1. 下位互換性:パスワード関数は本質的に の適切に作成されたラッパーであり、古いハッシュ アルゴリズムや安全でないハッシュ アルゴリズムを使用している場合でも、-format ハッシュcrypt()と本質的に下位互換性があります。crypt()
  2. フォワード互換性:認証ワークフローに少しのロジックを挿入password_needs_rehash()することで、現在および将来のアルゴリズムでハッシュを最新の状態に保つことができ、ワークフローへの将来の変更はゼロになる可能性があります。注: 指定されたアルゴリズムに一致しない文字列は、暗号と互換性のないハッシュを含め、再ハッシュが必要であるというフラグが立てられます。

例えば:

class FakeDB {
    public function __call($name, $args) {
        printf("%s::%s(%s)\n", __CLASS__, $name, json_encode($args));
        return $this;
    }
}

class MyAuth {
    protected $dbh;
    protected $fakeUsers = [
        // old crypt-md5 format
        1 => ['password' => '$1$AVbfJOzY$oIHHCHlD76Aw1xmjfTpm5.'],
        // old salted md5 format
        2 => ['password' => '3858f62230ac3c915f300c664312c63f', 'salt' => 'bar'],
        // current bcrypt format
        3 => ['password' => '$2y$10$3eUn9Rnf04DR.aj8R3WbHuBO9EdoceH9uKf6vMiD7tz766rMNOyTO']
    ];

    public function __construct($dbh) {
        $this->dbh = $dbh;
    }

    protected function getuser($id) {
        // just pretend these are coming from the DB
        return $this->fakeUsers[$id];
    }

    public function authUser($id, $password) {
        $userInfo = $this->getUser($id);

        // Do you have old, turbo-legacy, non-crypt hashes?
        if( strpos( $userInfo['password'], '$' ) !== 0 ) {
            printf("%s::legacy_hash\n", __METHOD__);
            $res = $userInfo['password'] === md5($password . $userInfo['salt']);
        } else {
            printf("%s::password_verify\n", __METHOD__);
            $res = password_verify($password, $userInfo['password']);
        }

        // once we've passed validation we can check if the hash needs updating.
        if( $res && password_needs_rehash($userInfo['password'], PASSWORD_DEFAULT) ) {
            printf("%s::rehash\n", __METHOD__);
            $stmt = $this->dbh->prepare('UPDATE users SET pass = ? WHERE user_id = ?');
            $stmt->execute([password_hash($password, PASSWORD_DEFAULT), $id]);
        }

        return $res;
    }
}

$auth = new MyAuth(new FakeDB());

for( $i=1; $i<=3; $i++) {
    var_dump($auth->authuser($i, 'foo'));
    echo PHP_EOL;
}

出力:

MyAuth::authUser::password_verify
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$zNjPwqQX\/RxjHiwkeUEzwOpkucNw49yN4jjiRY70viZpAx5x69kv.",1]])
bool(true)

MyAuth::authUser::legacy_hash
MyAuth::authUser::rehash
FakeDB::prepare(["UPDATE users SET pass = ? WHERE user_id = ?"])
FakeDB::execute([["$2y$10$VRTu4pgIkGUvilTDRTXYeOQSEYqe2GjsPoWvDUeYdV2x\/\/StjZYHu",2]])
bool(true)

MyAuth::authUser::password_verify
bool(true)

最後の注意として、ログイン時にのみユーザーのパスワードを再ハッシュできることを考えると、ユーザーを保護するために安全でないレガシー ハッシュを「廃止」することを検討する必要があります。つまり、一定の猶予期間の後、すべての安全でない [例: 裸の MD5/SHA/その他の脆弱な] ハッシュを削除し、ユーザーがアプリケーションのパスワード リセット メカニズムに依存するようにします。

于 2018-06-26T21:29:31.817 に答える