現在は稼働していないが、ある時点で稼働する可能性のある(高セキュリティではない)プロジェクトに取り組んでいます。
サーバー上でREST API(RestletおよびNeo4jを使用して実装))が実行されており、Androidクライアントアプリがあります。
ステートレスを維持するには、各リクエストとともに認証情報を送信する必要があります。 MACベースのアプローチを使用することにしました。HMAC-SHA256アルゴリズムを使用して、一連のヘッダー値と各HTTPリクエストのエンティティ本体に署名します。次に、そのハッシュをユーザー名と一緒にリクエストのAuthorization
ヘッダーに入れます。
HMACシークレットには、ユーザーが選択したパスワードを使用します。より安全にするために、パスワードをハッシュしてから使用し、クライアントに保存します。
もちろん、サーバーがHMAC-SHA256ヘッダーを検証できるようにするには、シークレットを1回送信する必要があります。ただし、これは1回だけ発生するため、セキュリティリスクはそれほど大きくありません。
このセットアップの問題は、ユーザーパスワードの安全な保管です。 Rainbowテーブル攻撃を防ぐために、ソルトを使用せずにパスワードをハッシュしてはならないことを知っています。しかし、安全な/ランダムなソルトを生成すると、ユーザーを初めてログインさせるクライアントは、正しいハッシュを生成するためにそのソルトにアクセスする方法がありません。
この場合、何が最善の決定でしょうか?ソルトを使用せずに、SHA256のような「従来の」ハッシュアルゴリズムを使用して、パスワードを単純に保存する必要がありますか?私はそれが非常に過失であろうと思います。また、bcryptやPBKDF2などのより安全なアルゴリズムを使用して、次のような「ダミーソルト」を使用することもできます。 ユーザー名 ユーザー名のMD5ハッシュとより高い反復回数。塩は知られていますが、レインボーテーブルを生成するのは非常に遅く、苦痛です。
「obscurityによるセキュリティ」ソルトを使用したbcryptは十分に安全ですか?または、セットアップ全体が安全ではなく、別の認証方法と交換する必要がありますか?
あなたがしなければならない最も重要なことは:SSLを使用です。 HTTPではなくHTTPSを使用します。
正当化:
SSLを使用する場合、そのアプローチは合理的です。
戦術の詳細:反復回数の多いPBKDF2を使用して、パスワードからHMACキーを生成することをお勧めします。固定値(またはユーザー名のハッシュ)をソルトとして使用できます。
これには確かにいくつかの弱点があります。クライアントデバイスにパスワードのハッシュを保存しているため、モバイルデバイスにアクセスした人が辞書攻撃を使用してパスワードを回復しようとする可能性があります。パスワードの強度。また、モバイルデバイスにアクセスできる人はだれでも暗号鍵を知ることができます。これは、認証されたHTTPリクエストを送信するために必要なすべてです。多くの場合、この弱点は許容できるリスクである可能性があります。
SSLを使用しない場合、スキーマにセキュリティ上の大きな問題が発生する可能性があります。ワイヤーを盗聴できる人なら誰でもパスワードのハッシュを知ることができ、パスワードが強力でない場合は、辞書検索を使用してユーザーのパスワードを回復できる可能性があります。
さらに優れたセキュリティが必要な場合は、少し強力なアプローチを次に示します。
SSL全体を使用暗号化されていないHTTPをいじらないでください。すべてにHTTPSを使用します。
完全な強度の暗号キーを使用します。 HMACで使用するために、サーバーに完全な強度の128ビット暗号ランダム暗号キーを生成させます。サーバーはこのキーを保存できます。
クライアントが初めて接続するとき、この暗号鍵を学習する必要があります。これを行うには、クライアントがそのユーザー名とパスワードを提供し、パスワードが正しい場合に応答として暗号鍵を受信する特別な要求があります。 (サーバーは、辞書攻撃を阻止するために、これらの要求をレート制限できます。)クライアントは暗号鍵を受信すると、それをローカルに保管します。
以降のすべてのリクエストでは、クライアントはローカルに保存された暗号鍵のコピーを検索し、それを使用してHMACを計算できます。
ユーザーが新しいデバイスからWebサイトにログオンした場合、問題はありません。そのデバイスは、上記の初期化手順を実行して暗号キーを取得するだけで、すべてが機能し続けます。
これにより、エンドデバイスにユーザーのパスワードまたはユーザーのパスワードのハッシュを保存する必要がなくなります。また、暗号キーに対する辞書検索攻撃を防ぎます。暗号キーは完全にランダムな値であり、パスワードとは無関係にランダムに選択されるため、パスワードに対するオフラインの辞書検索攻撃は、キーの取得に成功することはありません。ただし、悪意のあるユーザーがクライアントデバイスを手に入れると、暗号キーを学習して偽造されたリクエストを発行できるという弱点は保持されます。あなたの目標を考えると、それはあなたができる限りのことだと思います。
私はあなたの問題を完全に理解しているかどうかわかりません。
ソルトは通常、bcrypt文字列表現でエンコードされます。
ただし、ユーザー名をsaltとして使用しても、bcryptは正確にsaltとして16バイトを期待するため、おそらく機能しません。したがって、前にユーザー名を変換する必要があります。私が理解していないのは、なぜ両方の側が塩を持てないのですか?あなたが言ったように、ソルトはレインボーテーブルの攻撃を防ぐためだけのものなので、セキュリティ上の問題がなくても送信できます。
ハッシュされたパスワードをHMACキーとして使用する場合、ハッシュは共有シークレットになります。 (saltの有無にかかわらず)ハッシュすると、他の場所で使用される場合に備えてパスワードが保護されますが、ハッシュは直接使用できるため、サービスは保護されません。
私は、hmacキーを資格情報、トークンと考えるのが最善だと思います。そして、あなたはそれらを本当に安全に保管することはできません。もちろん、とにかく安全な場所に置いてください。
「パスワードを1回送信する」のではなく、一時的なシークレットを導出するためにOAUTHトークンに類似したものを使用することをお勧めします。ユーザーがそれらをコピーできるようにします(これは、例えばAmazon AWSが行うことです)。これがランダムな文字列である場合、ユーザーパスワードの漏洩の危険はありません(もちろん、資格情報も同様です)。
別の方法として、SRPなどを使用することもできます。これにより、リクエストの署名鍵に使用できる共有のプリマスターシークレットが作成されます。