Frage:
Wie sicher ist Javas hashCode ()?
Novice User
2014-03-07 13:33:28 UTC
view on stackexchange narkive permalink

In unseren Ansichten in einer Java-Webanwendung verwende ich derzeit hashCode als ID für Objekte, damit ich am Serverende dasselbe Objekt zurückerhalten kann.

Allerdings Ich frage mich, wie sicher Javas hashCode wirklich ist, damit jemand ihn nicht hacken kann, um die Objekte anderer Personen abzurufen. Ich bin nicht sehr geneigt zum Verschlüsselungs-Entschlüsselungs-Mechanismus, da er viel CPU verursacht.

Welche anderen schnellen und dennoch sicheren Mechanismen kann ich verwenden? P. >

Haben Sie die richtigen Krypto-Hashes verglichen oder behaupten Sie einfach, dass sie zu langsam sind?
Es gibt keine Garantie dafür, dass "hashCode" eindeutige Bezeichner generiert. Überprüfen Sie die Dokumentation.
"Ist Java` hashCode () sicher? " = "Ist die Verwendung eines Polynoms als Hash-Funktion sicher?"
Sorry, aber diese Frage ist ... sehr umwerfend. ich brauche ein Glas Wasser
Vier antworten:
#1
+55
Adi
2014-03-07 14:40:30 UTC
view on stackexchange narkive permalink

Sie brechen eines der Tabus hashCode () . Sie verwenden die Ausgabe als Schlüsselkennung. Das ist falsch.

Sie sehen, die Ausgabe von hashCode () (in der Standardimplementierung) ist eine 32-Bit-Ganzzahl ohne Vorzeichen, das sind ungefähr 4 Milliarden eindeutige Hashcodes. Klingt ziemlich viel? Nun, nicht so sehr. Das Anwenden des Geburtstagsproblems in diesem Fall zeigt, dass bei ungefähr 77000 Objekten eine Kollisionswahrscheinlichkeit von ungefähr 50% besteht. 50% ige Wahrscheinlichkeit, dass zwei Objekte denselben Hashcode haben.

Ein weiteres Problem besteht darin, dass sich die Implementierung von hashCode () von einer Java-Version zur anderen ändern kann. Es ist nicht als permanente Kennung eines Objekts gedacht, daher gibt es nichts, was es dazu zwingt, über Versionen hinweg konsistent zu sein.

Wenn Sie darauf bestehen, Hashes als Objektkennungen zu verwenden, ist es viel besser, stattdessen eine eigene Methode zu verwenden hashCode () zur Verwendung für Ihre Schlüsselkennungen (z. B. getMySpecialHashKey () . Sie können so etwas wie MessageDigest.getInstance ("SHA-256") , um das Objekt in einen schönen 256-Bit-Schlüssel zu verdauen.

Meine Empfehlung: Lassen Sie die ganze Idee des Hashing des Objekts hinter sich und generieren Sie stattdessen eine zufällige Kennung für Ihr Objekt, wenn Sie konstruieren es. Etwas in der Art von (in Java)

  SecureRandom secRand = new SecureRandom (); byte [] objIdBytes = neues Byte [16]; //128-bitsecRand.nextBytes ( objIdBytes); String objId = Base64.encodeBase64String (objIdBytes); // Hier ist Ihre ID  

Sie scheinen den Zugriff auf ein Objekt nur an die Kenntnis seines Schlüssels zu binden. Das ist auch falsch. Ein richtiger Ein berechtigungsbasiertes Modell mit ordnungsgemäßer Authentifizierung und Autorisierung ist erforderlich.

Nichts zwingt hashCode () dazu, auch über verschiedene JVM-Aufrufe hinweg konsistent zu sein.
_ "Wenn Sie darauf bestehen, Hashes als Objektkennungen zu verwenden" _ ** NICHT **.
Gute Antwort. Ein Diagramm, das die Wahrscheinlichkeit mindestens einer Hash-Kollision in einer Reihe von n Objekten zeigt, finden Sie hier: http://blogs.msdn.com/b/ericlippert/archive/2010/03/22/socks-birthdays-and-hash- collisions.aspx
+1 gute Antwort. Es ist jedoch möglicherweise einfacher, UUID.randomUUID () anstelle von SecureRandom zu verwenden, um eine ID zu generieren.
@EricLippert: Und das setzt wahrscheinlich eine vollkommen zufällige Hash-Funktion voraus. Für die Leistung optimierte Hash-Funktionen sind wahrscheinlich noch schlechter
Nein, keine gute Antwort. Gute Diagnose, schreckliche Empfehlung. Alle Zufallszahlen können kollidieren, auch solche, die mit Algorithmen für die Kryptostärke generiert wurden. Verwenden Sie einfach einen Atomzähler. Alles, was die unvorhersehbaren IDs tun, unterstützt die Einstellung, dass die Unklarheit des Schlüssels ausreichende Sicherheit bietet. Es ist nicht so, wie der letzte Absatz zeigt. Sobald eine geeignete ACL-Methode verwendet wird, bietet die Randomisierung von IDs keinen Vorteil mehr.
@BenVoigt Ich schlage vor, dass Sie einen Einführungskurs in Krypto absolvieren, bevor Sie die Empfehlungen anderer als "schrecklich" bezeichnen.
@Terry: Versuchen Sie, mehr als sechs Wörter meines Kommentars zu lesen, bevor Sie mit der Straftat beginnen. Sie haben offensichtlich keine Ahnung, was meine Ausbildung ist. Ich könnte empfehlen, dass Sie einen angemessenen Kurs über stochastische Prozesse absolvieren, bevor Sie Aussagen über die Eindeutigkeit von Pseudozufallszahlen machen, aber stattdessen werde ich mich nur auf den letzten Satz dieser Antwort selbst beziehen, um zu erklären, warum die Empfehlung, eine zufällige Kennung zu verwenden Zugang zu kontrollieren ist falsch **. Oh warte, ich habe es schon getan.
@BenVoigt Es ist vollkommen in Ordnung, sich so zu fühlen. Lassen Sie mich hier zuerst einige Verwirrung beseitigen. Wir haben zwei separate Probleme: 1- Die Verwendung eines kollisionsanfälligen UID-Generierungsprozesses mit hoher Wahrscheinlichkeit. 2- Einschränkung der Zugriffsrechte basierend auf der Kenntnis der ID. Das sind ** zwei ** getrennte und _ völlig_ unterschiedliche Probleme. Der erste betrifft die hohe Wahrscheinlichkeit von Kollisionen zwischen Objekten und die Unfähigkeit eines solchen Identifikationsschemas. Dieses Problem wird mithilfe von CSPRNG behandelt, bei denen solche Kollisionen äußerst unwahrscheinlich sind. Die zweite Ausgabe (Fortsetzung im nächsten Kommentar)
@BenVoigt Das zweite Problem sind Berechtigungen und Zugriffsrechte für Objekte und deren Beschränkung auf die Kenntnis der ID. Dieses Problem wird mithilfe gut etablierter und ordnungsgemäß geplanter ACL-Modelle behoben. Diese Antwort nähert sich ** nicht ** dem zweiten Problem (außer im letzten Absatz). Die "Schrecklichkeit" der Empfehlung beruht auf Ihrem Unverständnis (bitte verstehen Sie das nicht falsch. Wir alle hatten irgendwann kein Verständnis mehr, dann haben wir besser gelernt). Die Empfehlung in dieser Antwort bezieht sich ausschließlich auf die Verwendung von Hashes als Objektkennungen (und ich zitiere aus mir selbst). Nichts mehr.
@Adnan: Ich stimme dem letzten Absatz voll und ganz zu. Der Vorschlag von zufälligen IDs widerspricht dem jedoch. (Fügen Sie dazu die Reihenfolge hinzu, in der sie präsentiert werden, und ein Fragesteller, der nach einer schnellen Lösung sucht, wird sich wahrscheinlich auf "SecureRandom" fixieren.) Das zweite Problem * ändert * das erste, weil es Unvorhersehbarkeit von geringer Bedeutung macht ... und dann sollte man aus Leistungsgründen ein CSPRNG vermeiden, da es teuer zu berechnen ist und die Suche ineffizient macht.
Ich nehme an, dass es noch Argumente für das Hinzufügen von Zufälligkeiten gibt, z. B. die Nichtoffenlegung der Anzahl der Einträge in der Datenbank (oder der damit verbundenen Rate, mit der sie generiert werden). In Bezug auf das erste Problem - das Generieren von Kennungen, die nicht kollidieren - ist ein CSPRNG jedoch minderwertig. Der Bezeichner muss eindeutig sein, er muss nicht zufällig sein.
Ein letzter kurzer zusammenfassender Punkt: Die Kollisionsrate in zufällig generierten IDs wird durch die Größe der IDs gesteuert, und ob ein CSPRNG verwendet wird, spielt überhaupt keine Rolle.
@Adnan Sicherlich kein Krypto-Experte (und ein 256-Bit-Schlüssel macht die Wahrscheinlichkeit einer Kollision, gelinde gesagt, minimal - funktioniert gut für Git), aber ich stimme Ben hier zu: Wenn Sie den Hash / Schlüssel / was auch immer des Objekts nicht für die Autorisierung verwenden , warum nicht einfach einen einfachen Zähler verwenden? Garantiert kollisionsfrei, schneller und einfacher - auch vorhersehbar, aber unter der Annahme einer korrekten Authentifizierungsmethode, die nicht schädlich ist.
Kleiner Implementierungshinweis: Um eine sichere 128-Bit-Zufalls-ID in Java zu generieren, verwenden Sie einfach [`UUID.randomUUID ()`] (http://docs.oracle.com/javase/1.5.0/docs/api/java/). util / UUID.html # randomUUID% 28% 29).
@Voo ein Zähler ist nur für einen einzelnen Prozess eindeutig. Wenn Sie mehrere Server oder nur mehrere Prozesse haben, die diese IDs erstellen, wird es zu einem echten Problem, sie zu koordinieren, um einen Zähler zu implementieren. Eine Zufallszahl aus einem ausreichend großen Raum wird schnell viel einfacher.
#2
+30
Axel
2014-03-07 17:12:43 UTC
view on stackexchange narkive permalink

Java hashCode () sollte niemals so verwendet werden. Tu es niemals! Es ist sogar legal (obwohl nicht empfohlen), dass alle Instanzen einer Klasse denselben Hashcode zurückgeben. Der Vertrag in Java lautet "Zwei Objekte, die als gleich angesehen werden, müssen denselben Hashcode haben". Nicht mehr und nicht weniger. Es wäre beispielsweise gültig, Hashcode 1 für alle ungeraden Zahlen und 0 für gerade zurückzugeben.

Hashcode wird für eine schnellere Suche in Sammlungen wie HashMap verwendet Code> und Kollisionen werden erwartet.

Viele Klassen definieren ihre eigene Version von hashCode () , und wenn Sie den Code kennen, können Sie dies häufig problemlos tun Sagen oder erraten Sie den Hashcode.

Das ist also absolut unsicher.

So wie ich es gerne betrachte, besteht der Zweck von Hash-Codes darin, einige (hoffentlich die meisten) Vergleiche zwischen Dingen zu beschleunigen, die unterschiedlich sind, da alles, dessen Hashcode nicht dem Hashcode von X entspricht, als ungleich X angesehen werden kann, ohne es überhaupt zu haben um es anzusehen. Nicht alle Klassen können ihren Hashcode so implementieren, dass eine Beschleunigung möglich ist, aber es gibt Hashcode, damit diejenigen, die ihn sinnvoll implementieren können, dies tun können.
#3
+12
Philipp
2014-03-07 14:31:03 UTC
view on stackexchange narkive permalink

Es ist nicht kryptografisch sicher, da dies nicht Teil seiner Anforderungen ist.

Die Implementierung des HashCodes ist ein Implementierungsdetail bis zur JVM und kann für verschiedene Objekttypen unterschiedlich sein (Objekte können die überschreiben hashCode-Methode und stellen eine eigene Implementierung bereit.

Der Zweck des Java-hashCode besteht darin, Objekte zu identifizieren, wenn sie in Hash-Tabellen platziert werden. Ihre Hauptanforderung ist die Leistung. Es hat auch eine Länge von nur 32 Bit, was zu kurz ist, um Kollisionen zu vermeiden. Für den beabsichtigten Zweck (Hash-Tabellen) sind zwei Objekte mit demselben Hash nur ein kleines Problem. Die Identifizierung von Objekten ohne Mehrdeutigkeitskollisionen ist jedoch ein großes Problem.

Sie sollten jedoch im Allgemeinen keinem Benutzer den Zugriff auf Objekte erlauben Objekt, nur weil sie den Hash-Code des Objekts kennen. Verwenden Sie ein ordnungsgemäßes Rechteverwaltungsschema. Verwenden Sie kennwortgeschützte Benutzerkonten, bei denen jeder Benutzer einen anderen Satz von Berechtigungsparametern hat. Wenn der Benutzer versucht, auf ein Objekt zuzugreifen, überprüfen Sie, ob seine Berechtigungen dies zulassen, und lehnen Sie die Anforderung ab, wenn dies nicht der Fall ist.

#4
+2
Jon Hanna
2014-03-07 23:07:31 UTC
view on stackexchange narkive permalink

Es ist sicherlich nicht sicher genug für eine Situation, in der das Erraten von Werten Informationen enthüllen kann.

Zumindest einige der Überschreibungen sind nicht sicher genug, um angesichts von als Hash-Code verwendet zu werden Beliebige vom Benutzer ausgewählte Eingaben (mit Javas String.hashCode () überschreiben ist es wirklich einfach, einen Hash-DoS-Angriff gegen alles durchzuführen).

In Fällen, in denen Sie eine Kennung wünschen, Ich empfehle, einen einfachen Bezeichner (z. B. einen numerischen Schlüssel in einer Datenbank, eine atomar inkrementierte Ganzzahl, die ein Schlüssel für eine Hash-Tabelle ist usw.) zu verwenden und dann einen kryptografischen Hash davon und ein Salt anzuhängen.

Das heißt, Ihre öffentlich zugängliche ID hätte die Form (in sprachunabhängiger Form):

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

(Sie können einen Teil des Hashs für eine kleinere ID entfernen, um die Zeit bis zur Brute-Force zu verkürzen.)

Dann erhalten Sie die private ID als eine Teilzeichenfolge, und die vollständige ID kann erneut überprüft werden. Das allgemeine Verfahren lässt sich auch leicht zwischen Sprachen portieren.

Die Handvoll CPU-Zyklen, die dies kosten wird, werden im Vergleich zum Rest des Systems keine großen Auswirkungen haben, es sei denn, Ihr System ist so trivial, dass Sie Es wird sowieso nicht viel CPU verbraucht. Wenn Sie dies also nicht auf einem Gerät mit sehr geringem Stromverbrauch ausführen (wie in, weitaus weniger leistungsstark als ein billiges Telefon), ist dies kein Problem.

In Fälle, in denen Sie tatsächlich einen Hash-Code als Hash-Code verwenden möchten und sich mit benutzerdefinierten Eingaben befassen müssen, verwenden Sie dann einen Startwert-Hash-Algorithmus (z. B. SpookyHash) und stützen Sie Ihren Startwert auf die Startzeit (oder noch besser auf die Startzeit). eine Mischung aus Startzeit und der Zeit, zu der Sie den Hash-Container erstellen). (Nichts mit kryptografischen Hashes zu tun, daher können sie viel schneller sein. Das einzige Sicherheitsrisiko, das dadurch vermieden wird, ist Hash-DoSing.)



Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...