web-dev-qa-db-ja.com

JavaのhashCode()はどの程度安全ですか?

Java= Webアプリケーションのビューでは、現在、オブジェクトのIDとしてhashCodeを使用しているため、サーバー側で同じオブジェクトを取得できます。

しかし、JavaのhashCodeが本当に安全で、他の人のオブジェクトを取得するためにハッキングできないのではないかと思います。多くのCPUを使用するため、暗号化/復号化メカニズムにはあまり向いていません。

他にどんなfastまだsecureメカニズムを使用できますか?

21
Novice User

hashCode()タブーの1つを壊しています。その出力をキー識別子として使用しています。 それは間違っています。

ご覧のとおり、(デフォルトの実装では)hashCode()の出力は32ビットの符号なし整数で、約40億の一意のハッシュコードです。かなりたくさん聞こえますか?まあ、それほどではありません。この場合、 誕生日の問題 を適用すると、約77000のオブジェクトの場合、衝突の可能性が約50%あることがわかります。 2つのオブジェクトが同じhashCodeを持つ確率は50%です。

もう1つの問題は、hashCode()の実装が1つのJava=バージョンから別のバージョンに変更される可能性があることです。これは、オブジェクトの永続的な識別子ではないため、強制的に実行するものはありません。バージョン間で一貫している。

オブジェクト識別子としてハッシュを使用する場合は、hashCode()ではなく独自のメソッドを使用して、キー識別子(getMySpecialHashKey()など)を使用することをお勧めします。オブジェクトをナイス256ビットキーにダイジェストするには、MessageDigest.getInstance("SHA-256")のようにします。

私の推奨事項:オブジェクトをハッシュするというアイデア全体を捨て、構築するときにオブジェクトのランダムな識別子を生成します。 (Javaで)の線に沿った何か

SecureRandom secRand = new SecureRandom();
byte[] objIdBytes = new byte[16]; //128-bit
secRand.nextBytes(objIdBytes);
String objId = Base64.encodeBase64String(objIdBytes); //Here's your ID

また、オブジェクトへのアクセスを、そのキーの知識にのみバインドするようにも見えます。 それも間違っています。適切な認証と承認を備えた適切なアクセス許可ベースのモデルが必要です。

54
Adi

Java hashCode()は、このように使用するためのものではありませんでした。絶対にしないでください!クラスのすべてのインスタンスが同じhashCodeを返すことも(推奨されませんが)正当です。 Java=のコントラクトは、「等しいと見なされる2つのオブジェクトは同じハッシュコードを持つ必要があります」です。それ以上でもそれ以下でもありません。たとえば、すべての不均一な数値に対してハッシュコード1を返し、でも。

hashCodeは、HashMapなどのコレクションの検索を高速化するために使用され、衝突はexpectedです。

多くのクラスは独自のバージョンのhashCode()を定義しており、コードを知っている場合は、ハッシュコードを簡単に認識または推測できます。

したがって、これは完全に安全ではありません。

30
Axel

これは要件の一部ではないため、暗号的に安全ではありません。

HashCodeの実装方法は、JVMまでの実装の詳細であり、オブジェクトタイプごとに異なる場合があります(オブジェクトはhashCodeメソッドをオーバーライドして独自の実装を提供できます)。

Java hashCodeの目的は、オブジェクトをハッシュテーブルに配置するときにオブジェクトを識別することです。その主な要件はパフォーマンスです。また、32ビットの長さであり、衝突を避けるには短すぎます。その意図された目的(ハッシュテーブル)が同じハッシュを持つ2つのオブジェクトは小さな問題にすぎませんが、あいまいな衝突なしにオブジェクトを識別することは大きな問題です。

ただし、オブジェクトのハッシュコードを知っているという理由だけで、ユーザーがオブジェクトにアクセスすることを許可すべきではありません。適切な権利管理スキームを使用します。パスワードで保護されたユーザーアカウントを使用します。各ユーザーには、異なる一連のアクセス許可パラメーターがあります。ユーザーがオブジェクトにアクセスしようとしたときに、そのアクセス許可で許可されているかどうかを確認し、許可されていない場合は要求を拒否します。

12
Philipp

推測値が情報を明らかにする可能性がある状況では、これは十分に安全ではありません。

少なくとも一部のオーバーライドは、ユーザーが選択した任意の入力に対してハッシュコードとして使用するのに十分なほど安全ではありません(JavaのString.hashCode()を使用して何かに対してハッシュDoS攻撃を行うのは本当に簡単ですオーバーライド)。

識別子が必要な場合は、単純な識別子(データベースの数値キー、ハッシュテーブルへのキーであるアトミックに増分された整数など)を取得し、その暗号化ハッシュとソルトを追加することをお勧めします。

つまり、公開IDは次の形式になります(言語にとらわれない形式)。

Concatenate(PrivateID, HexString(SHA256(UTF8Bytes(Concatenate(Salt, PrivateID)))))

(ブルートフォースにかかる時間を短縮して、より小さなIDのハッシュの一部を削除することができます)。

次に、プライベートIDをサブストリングとして取得し、完全なIDを再度確認できます。一般的な手順も言語間で簡単に移植できます。

このコストがかかる一握りのCPUサイクルは、システムがそれほどCPUを使用しないほど簡単で、これを実行していない限り、システムの他の部分に比べて大きな影響はありません。本当に低電力のもの(たとえば、安価な電話よりはるかに強力ではない)は問題にはなりません。

ハッシュコードとしてハッシュコードを実際に使用し、ユーザーが選択した入力を処理する必要がある場合は、シード可能なハッシュアルゴリズム(SpookyHashなど)を使用し、起動時間にシードを基にします(または、 、起動時間とハッシュコンテナーを作成する時間の組み合わせ)。 (暗号化ハッシュとは関係がないので、はるかに高速になる可能性があります。-only回避するセキュリティリスクは、ハッシュDoSingです)。

2
Jon Hanna