web-dev-qa-db-ja.com

bcryptと定数ソルトを使用したパスワードのハッシュはSHA1より安全ではありませんか?

ユーザーが暗号化されたデータを送信してクラウドに保存できるようにするAPIを作成しました。 APIは、データを取得するために、ユーザーが最初にデータを送信したときに与えられたMongoDBオブジェクトIDと、データの暗号化に使用したパスワードのSHA1ハッシュのみを提供するように要求します。オブジェクトIDとパスワードハッシュの両方を一意のキーとして使用することを選択しました。異なるオブジェクトIDは複雑で推測しにくいため、APIを介してユーザーがデータをリクエストするのを防ぎます。

ハッシュ方式はより安全であるため、SHA1からbcryptに切り替えましたが、問題がありました。 bcryptは毎回異なるソルトを生成するため、ハッシュは常に異なります。つまり、アプリがbcryptハッシュを生成するたびに同じソルトを使用するように強制しない限り、生成されたハッシュを使用してデータベース内のユーザーのデータを識別できなくなります。注:定数ソルトを使用する場合、ソースコードはオープンソースであるため、一般に知られています。

私の質問は、パスワードハッシュを生成するためにbcryptで定数ソルトを使用する場合、これにより、元のようにSHA1を使用するよりもハッシュを解読しやすくなりますか?

または、ユーザーに詳細情報を要求せずに、データベース内のユーザーのデータに一意のキーを指定するためのより良いアプローチはありますか?


編集:質問をできるだけ単純にするために、私が持っているアプローチを選択した理由について十分なコンテキストが実際には提供されていないことに気づきました。物事がより明確になり、人々が可能な限り正確な答えを提供できるようになります。

意図は、アプリをサポートする安全で匿名のサービスを作成し、誰でも、どこでも実行できるようにすることです。アプリとAPIはオープンソースであるため、アプリの他のユーザーにサーバースペースを提供したい人は、APIの独自のインスタンスを実行できます。アプリのユーザーは、選択したAPIのURLでそれをポイントできます。これにより、APIのパブリックホストインスタンスを使用したり、自分だけが使用できる独自のサーバーでインスタンスをホストしたりできます。

ユーザーのデータはどのパブリックサーバーにも配置できるため、APIサーバーの所有者(または他の誰か)が暗号化を解除したい場合に備えて、データがクライアント側で暗号化され、ユーザーが平文のパスワードを送信しないようにすることが重要です。ホストされているユーザーデータ。このサービスは、セキュリティと利便性の理由から匿名です。そのため、アプリのユーザーはメールアドレスやその他の識別情報を提供する必要がなく、アプリのボタンをクリックするだけで、データがパスワードで暗号化されて送信されます。 APIとハッシュ化されたパスワード:

投稿本文の例:

{
    "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "passwordHash":"d4de34f15aeadfb34bdf1fbbd57134b2baeb142c"
}

応答:

{
    "id":"507f191e810c19729de860ea",
    "lastUpdated":"2016-07-06T12:43:16.866Z"
}

Mongodbエントリは次のようになります。

{
    "id": "507f191e810c19729de860ea",
    "passwordHash": "d4de34f15aeadfb34bdf1fbbd57134b2baeb142c",
    "data": "DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "lastUpdated": "2016-07-06T12:43:16.866Z"
}

ユーザーは/api/data/{id}/{passwordHash}へのGETリクエストでデータを取得できるため、上記の例では次のようになります。

/api/data/507f191e810c19729de860ea/d4de34f15aeadfb34bdf1fbbd57134b2baeb142c

応答:

{
    "data":"DWCx6wR9ggPqPRrhU4O4oLN5P09onApoAULX4Xt+ckxswtFNH/QQ+Y/RgxdU+8+8/muo4jo/jKnHssSezvjq6aPvYK+EAzAoRmXenAgUwHOjbiAXFqF8gScbbuLRlF0MsTKn/puIyFnvJd...",
    "lastUpdated":"2016-07-06T12:43:16.866Z"
}

Id値(MongoDBオブジェクトID)は過度に複雑ではないため、悪意のあるユーザーは誰か他の人のIDを推測し、API経由でデータを取得する可能性があります。そのため、悪意のあるユーザーが他のユーザーの一意のキーを推測するのをより困難にするために、ユーザーのパスワードハッシュと共にIDをキーとして使用することにしました。ただし、オブジェクトIDのみをキーとして使用し、他のユーザーのIDを推測できたとしても、暗号化されたデータ(パスワードハッシュではなく)のみを取得するため、データを読み取る前に復号化する必要があります。これはパスワードハッシュを保存するより良い代替手段でしょうか?皮肉なことに、これはbcryptの問題に答えて、パスワードハッシュをサーバーに保存していないかのように、パスワード(クライアント側のデータの暗号化に使用)をハッシュする必要がないようにしています...

結論として、私のアプリ/ APIに関連する質問は、先に行った質問よりもはるかに複雑ですが、適切にフレームを作成する方法については本当に考えることができませんでした(おそらく質問を変更する必要があるかもしれません)。ただし、要件を考慮して、私のアプローチのセキュリティ面について誰かが意見を持っている場合は、私は入力に非常に感謝します。

3
nero120

定数ソルトを使用している場合、bcryptではありません。

bcrypt実装の重要な要件は、128ビットのソルトスペース全体を利用することです。

—将来適応可能なパスワード方式

Bcryptは毎回異なるソルトを生成するため、ハッシュは常に異なります。つまり、生成されたハッシュを使用してデータベース内のユーザーのデータを識別することはできなくなります。

もちろん可能です。以前のハッシュのソルトがすでにあるため、新しいハッシュを生成するときにそれを使用します。

6
Jim

免責事項:この回答は、質問に詳細が追加される前に作成されたことに注意してください。したがって、一部のポイントは適用されなくなり、他のポイントは適用されます。

アプローチの問題

[...]データの暗号化に使用したパスワード。

暗号化キーとしてパスワードを使用していますか?ユーザーが選択したパスワードはエントロピーが低く、ブルートフォースされる可能性があるため、これは良い考えではありません。

APIは、データを取得するために、ユーザーにパスワードのSHA1ハッシュを提供するように要求します[...]。

ユーザーはハッシュではなくパスワードを送信する必要があります。ユーザーがハッシュを送信することで、ハッシュは効果的にパスワードになります。つまり、有効なパスワード(つまり、ハッシュ)は保護されずに保存されます。詳細については、「ハッシュを渡す」を検索してください。

しかし、パスワードが暗号化に使用されていて、ユーザーからのみハッシュを取得している場合、どうすれば復号化できますか?

Bcryptは毎回異なるソルトを生成するため、ハッシュは常に異なります。つまり、アプリがbcryptハッシュを生成するたびに同じソルトを使用するように強制しない限り、生成されたハッシュを使用してデータベース内のユーザーのデータを識別できなくなります。

なぜハッシュを使用してデータを識別するのですか?そのためにMongoDBオブジェクトIDを使用します。認証にはパスワードとハッシュを使用します。

ハッシュを渡さず、代わりにパスワードを渡す場合は、認証に個々のソルトを使用してbcryptを使用できます。ユーザーごとにランダムなものを生成し、データベースに保存します。次に、ユーザーがパスワードを送信すると、そのソルトを使用してハッシュし、比較します。 bcryptを実行するライブラリには、このための関数が必要です。

これを正しく行う方法の概要

ユーザーが自分のデータをサーバーに保存するときに、パスワードを提供します。一意のランダムソルトを生成して、データベースに保存します。次に、bcryptとそのソルトを使用してパスワードをハッシュし、暗号化キーを取得します。このキーを使用してデータを暗号化します。

ユーザーがデータにアクセスする場合は、パスワードを再入力します。キーを取得するには、bcryptと保存されているソルトでハッシュします。これを使用してデータを復号化します。最後にMACをチェックして、復号化が実際に機能したことを確認します。パスワードが間違っていると、間違ったキーを取得し、MACが一致しなくなります。

これはたくさんの細かい説明があるため、上記の2つの段落を完全なガイドとして使用しないでください。

最後に、ここで自分をロールバックしますか?おそらく、あなたがやりたいことを実行する既存のソリューションがあるでしょう。独自のプログラムを作成して、小さな間違いを犯し、すべてのユーザーのデータが盗まれる場合。

6
Anders

どちらも使用しないでください。

定数saltを使用すると、bcryptを使用する目的が無効になります。可変ソルトを使用してください! SHA1と同様に、簡単にクラックされます。それは尋ねるようなものです-木製の箱、または木製のドアが付いているテルミットに耐える三重強化鋼の箱のどちらがより安全ですか? トムスコットによる優れた説明

コードのにおいが原因で、コードがSQLインジェクションに対して脆弱である可能性があります。いいにおいがする。 SQLインジェクション、XSS、CSRFなどのコードを確認してください。

enter image description here

(これらはすべて復号化されています。)

補遺

データを暗号化する場合は、公開/秘密鍵システムを使用します。ただし、これにより、管理者を含め、ユーザー以外の全員がデータを表示できなくなります。パスワードでデータを暗号化しない-適切なキーでデータを暗号化します。機密性の高い情報ではない場合はRSA-2048を、スズフォイルハットセキュリティを保証する場合はRSA-4096をお勧めします(NSAがこれを使用します)。政府を知っている場合はRSA-8192をお勧めします。スパイはユーザーの情報を解読しようとするか、数兆ドルがデータベースのセキュリティを脅かします。

ハッシュを使用してユーザーデータを識別することもできます。データにソルトを含め、ユーザーデータをソルトでハッシュするだけです。

クライアントに署名を生成してユーザーの身元を確認させ、認証局として機能させることができます。また、個人を特定する情報の代わりに、ランダムなUUIDを使用することもできます。しかし、ユーザーを識別できることは、匿名性の目的に反します。

1