# PHP - Wie Hash'e Ich ein string?



## BloodSteam (9. Juli 2018)

Hallo,
ich hab auf meiner Internetseite ein Login System und würde gerne auch den Benutzernamen Hashen.

Ich hab mal folgendes versucht und leider funktioniert es nicht:

```
$LoginHash = hash("adler32",$login);
```

Wieso muss bei gleichem Wort/Login immer ein anderer Hash herauskommen?


----------



## taks (9. Juli 2018)

Und was ist wenn du statt $login einen fixen String verwendest? Ist der Hash dann auch immer anders?

btw: Ich würd als Algorithmus eher etwas wie md5  nehmen.


----------



## shorty1990 (9. Juli 2018)

Hi erstmal,



BloodSteam schrieb:


> Ich hab mal folgendes versucht und leider funktioniert es nicht


Mhh wenn ich mir die "hash" Funktion anschaue, frage ich mich wo du du den Hashing-Algorythmus festlegst.

Ich würde das so machen:
$LoginString = "adler32";
$LoginHash = md5($LoginString);
Dann halt Abgleich mit dem Hash in der Datenbank.

Wirklich sicher ist das jedoch nicht.
Hier weitere Info's dazu:
PHP: Password Hashing - Manual




BloodSteam schrieb:


> Wieso muss bei gleichem Wort/Login immer ein anderer Hash herauskommen?


Ein Hash ist eine Prüfsumme die in Verbindung zu den geprüften Daten entsteht.
Also entweder war dein String nicht "Bit-identisch". Oder es liegt an deinem Code.


----------



## taks (9. Juli 2018)

shorty1990 schrieb:


> Mhh wenn ich mir die "hash" Funktion anschaue, frage ich mich wo du du den Hashing-Algorythmus festlegst.



adler32 ist ein Hash-Algorithmus


----------



## shorty1990 (9. Juli 2018)

taks schrieb:


> adler32 ist ein Hash-Algorithmus



Krass! Man lernt immer was dazu!!


----------



## DataDino (9. Juli 2018)

Ich denke es geht hier darum, Benutzernamen zu maskieren, damit jemand, der Zugriff auf die Tabelleninhalte bekommt, nicht den Passwort-Hash einem bestimmten Nutzer zuordnen kann. Das funktioniert aber nur bedingt und vor allem bringt es einem nicht allzuviel. Man bekommt immer ein Hash mit fester Länge, wodurch direkt zu sehen ist, mit welcher Tiefe dieser arbeitet und man kann damit die Algorithmen eingrenzen. Bei MD5 sind es 32 Stellen. Dann kann man auch den Benutzernahmen vorher hashen und stattdessen nach dem Hash suchen. Wenn du es besser machen willst, dann arbeite auch hier mit einem Salt und hänge ihn an den Hash. Dann benötigt man definitiv die komplette Tabelle, um die Salt's mit dem Benutzernamen zusammen zu hashen und den richtigen zu finden. Das dauert dann auch meist ein kleines bisschen Länger und es ist eher selten, das jemand direkten Zugriff auf die komplette Tabelle hat.

Wenn es dir nur darum geht, zwischen "user" und "User" zu unterscheiden, dann kannst du auch mit der Funktion strcmp nachträglich vergleichen: PHP: strcmp - Manual
Solltest du aber mit einer relationalen Datenbank arbeiten (wovon ich ausgehe), dann kannst du aber auch die WHERE-Klausel mit BINARY erweitern:

```
WHERE BINARY username=:username
```


----------



## BloodSteam (10. Juli 2018)

shorty1990 schrieb:


> Hi erstmal,
> 
> 
> 
> ...





Spoiler



Results: (in microseconds)
   1.  md4             -              5307.912
   2.  md5               -            6890.058
   3.  crc32b           -             7298.946
   4.  crc32             -            7561.922
   5.  sha1              -            8886.098
   6.  tiger128,3          -          11054.992
   7.  haval192,3         -           11132.955
   8.  haval224,3          -          11160.135
   9.  tiger160,3           -         11162.996
  10.  haval160,3        -            11242.151
  11.  haval256,3         -           11327.981
  12.  tiger192,3          -          11630.058
  13.  haval128,3         -           11880.874
  14.  tiger192,4          -          14776.945
  15.  tiger128,4          -          14871.12
  16.  tiger160,4          -          14946.937
  17.  haval160,4         -           15661.954
  18.  haval192,4        -            15717.029
  19.  haval256,4         -           15759.944
  20.  adler32           -            15796.184
  21.  haval128,4         -           15887.022
  22.  haval224,4         -           16047.954
  23.  ripemd256          -           16245.126
  24.  haval160,5          -          17818.927
  25.  haval128,5         -           17887.115
  26.  haval224,5         -           18085.002
  27.  haval192,5          -          18135.07
  28.  haval256,5         -           18678.903
  29.  sha256             -           19020.08
  30.  ripemd128          -           20671.844
  31.  ripemd160         -            21853.923
  32.  ripemd320         -            22425.889
  33.  sha384          -             45102.119
  34.  sha512          -              45655.965
  35.  gost                -          57237.148
  36.  whirlpool        -             64682.96
  37.  snefru             -           80352.783
  38.  md2                -           705397.844





DataDino schrieb:


> Ich denke es geht hier darum, Benutzernamen zu maskieren, damit jemand, der Zugriff auf die Tabelleninhalte bekommt, nicht den Passwort-Hash einem bestimmten Nutzer zuordnen kann. Das funktioniert aber nur bedingt und vor allem bringt es einem nicht allzuviel. Man bekommt immer ein Hash mit fester Länge, wodurch direkt zu sehen ist, mit welcher Tiefe dieser arbeitet und man kann damit die Algorithmen eingrenzen. Bei MD5 sind es 32 Stellen. Dann kann man auch den Benutzernahmen vorher hashen und stattdessen nach dem Hash suchen. Wenn du es besser machen willst, dann arbeite auch hier mit einem Salt und hänge ihn an den Hash. Dann benötigt man definitiv die komplette Tabelle, um die Salt's mit dem Benutzernamen zusammen zu hashen und den richtigen zu finden. Das dauert dann auch meist ein kleines bisschen Länger und es ist eher selten, das jemand direkten Zugriff auf die komplette Tabelle hat.
> 
> Wenn es dir nur darum geht, zwischen "user" und "User" zu unterscheiden, dann kannst du auch mit der Funktion strcmp nachträglich vergleichen: PHP: strcmp - Manual
> Solltest du aber mit einer relationalen Datenbank arbeiten (wovon ich ausgehe), dann kannst du aber auch die WHERE-Klausel mit BINARY erweitern:
> ...



Bei mir wird es ein bisschen anders verlaufen.

Login kann die gleichen Zeichen haben wie ein Password. Also Zb Dät@_D1No etc.
Login wird zum einlogen benutzt, der Benutzername wird sich vom Login unterscheiden. Die Säule in meiner Tabelle sind auch nicht sichtbar beschriftet. Also weißt du am Ende nicht mal ob du einen Benutzernamen decryptest oder ein Password. (Ich weiß wo was ist  ).

Mein Plan ist es das Login als eine 1-Way encryption zu machen, (Password wird schon mit password_hash() gehasht) und den Benutzernamen werde Ich als 2-Way encryption machen.


----------



## taks (10. Juli 2018)

BloodSteam schrieb:


> Die Säule in meiner Tabelle sind auch nicht sichtbar beschriftet. Also weißt du am Ende nicht mal ob du einen Benutzernamen decryptest oder ein Password. (Ich weiß wo was ist  ).



Security by Obscurity ist ein schlechter Designansatz.
Die Sicherheit sollte gleich bleiben auch wenn der Angreifer das System kennt.


----------



## DataDino (10. Juli 2018)

BloodSteam schrieb:


> Login kann die gleichen Zeichen haben wie ein Password. Also Zb Dät@_D1No etc.
> Login wird zum einlogen benutzt, der Benutzername wird sich vom Login unterscheiden. Die Säule in meiner Tabelle sind auch nicht sichtbar beschriftet. Also weißt du am Ende nicht mal ob du einen Benutzernamen decryptest oder ein Password. (Ich weiß wo was ist  ).


Ich verstehe ehrlich gesagt nicht, was du einem damit sagen willst. Was ist für dich 1-Way und 2-Way Encryption? Soll "Login" bei dir für "Passwort" stehen oder steht es für den eigentlichen Prozess? Wieso drückst du das nicht klarer aus?

Deine Auflistung mit der Geschwindigkeit einzelner Algorithmen sagt zu deiner Entscheidung, Adler32 zu nutzen, garnichts aus. Er ist weder der effizienteste noch der ineffizienteste. Adler32 ist eine reine Prüfsumme und nicht dafür gedacht, Strings zu verschleiern. Denn die liefern wie CRC32 ausschließlich 8-stellige Hashes. Dies erhöht die Kollisionswahrscheinlichkeit drastisch. Im Grunde bringt dir in PHP ein ineffizienter Algorithmus nichts, wenn es von dem Algorithmus in anderen Bibliotheken bereits effizientere Implementierungen gibt. Oder glaubst du wirklich, das ein Angreifer zum Cracken bzw. Bruteforce auch PHP verwendet?

Außerdem bringt es einem nichts, wenn man die Tabellenspalten mit irgendwelchen abstrusen Namen kaschiert. Auf Grund der Tabellen-Inhalte lässt sich darauf schließen, was am Ende was ist. Das Passwort erkennt ein kundiger sofort, gerade wenn es mit der Password-Hash Funktion verarbeitet wurde. Algo$Coast&Hash&Salt erkennt jeder, der es weiß auf einen Blick und schon kannst du die Spalte Schweineschwarte2000 nennen. Er sieht, das es die Passwortspalte ist. Dann hast du noch eine weitere Spalte mit Hashes und er findet keine Benutzernamen. Und schon weiß er, das die Spalte mit den anderen Hashes die gehashten Benutzernamen sein müssen. Den Schritt mit der "maskierten" Spalte kannst du dir also komplett sparen und stellt einen Angreifer vor keine Herausforderung. Da ist es schon deutlich schwieriger, zu einem Passwort den richtigen Benutzernamen bzw. zum Benutzernamen das richtige Passwort zu finden. Aber wie ich schon gesagt habe, wird ein Hash ohne Salt (was übrigens sehr schwer zu implementieren ist) diesen Vorgang auch nicht schwerer machen, weil er den Benutzernamen, den er angreifen will selbst erst einmal hasht und dann nach dem Hash statt nach dem Benutzer sucht.

Und zum Thema "Security by Obscurity". Ein geschlossenes und konfuses System versucht, Schwächen an den sicherheitsrelevanten Komponenten zu kaschieren. Im Idealfall sollte ein Angreifer garnicht zu den Tabellen kommen. Wenn er es dann doch schafft, dann liegt das Problem an einer völlig anderen Stelle. Wenn er also erst einmal so weit ist, dann hilft es auch nicht, den Karren im letzten Moment durch solche Verwirrungen aus dem Dreck zu ziehen. Genauso ist es auch beim Hashen und verschlüsseln. Wenn er bei den Benutzernamen ein Adler32, CRC32, MD5, Sha1 oder What-ever sieht, dann zuckt dieser nur mit den Schulter. Wenn er aber das Passwort mit erhöhtem Kostenfaktor sieht, dann lässt er es meist sowieso bleiben. Das lohnt meistens nicht. Du machst dir also beim kaschieren unnötig Arbeit, bringen tut es dir nichts und weckt nur unnötig die Neugier eines Angreifers. Zudem machst du dir selbst das Leben schwer, wenn es um die Wartung geht.


----------



## ZAM (10. Juli 2018)

Und hört mal auf doppelte Anführungszeichen bei normalen Strings ohne Ersetzungen zu verwenden ...


----------



## BloodSteam (12. Juli 2018)

ZAM schrieb:


> Und hört mal auf doppelte Anführungszeichen bei normalen Strings ohne Ersetzungen zu verwenden ...



Kannst du dass mal genauer erklären?


----------



## ZAM (12. Juli 2018)

Doublequotes sind bei leeren und einfachen Strings einfach unnötig. Nicht zwingend vom Performance-Mythos her, da liegt der Unterschied wenn es hochkommt maximal im Tausendstel-Bereich, sondern einfach um den Interpreter an der Stelle nicht unnötig "nachschauen" zu lassen, ob Ersetzungsvariablen im String vorhanden sind. Hat keinen signifikanten Impact ist aber einfach unsauber.


----------



## BloodSteam (15. Juli 2018)

ZAM schrieb:


> Doublequotes sind bei leeren und einfachen Strings einfach unnötig. Nicht zwingend vom Performance-Mythos her, da liegt der Unterschied wenn es hochkommt maximal im Tausendstel-Bereich, sondern einfach um den Interpreter an der Stelle nicht unnötig "nachschauen" zu lassen, ob Ersetzungsvariablen im String vorhanden sind. Hat keinen signifikanten Impact ist aber einfach unsauber.



Also einfach

```
$bob;
```
 lassen?


----------



## ZAM (15. Juli 2018)

Das knallt. 
$bob = '';


----------



## BloodSteam (16. Juli 2018)

ZAM schrieb:


> Das knallt.
> $bob = '';



Ich kenne nicht wirklich den Unterschied zwischen '' und ""


----------



## DataDino (16. Juli 2018)

BloodSteam schrieb:


> Ich kenne nicht wirklich den Unterschied zwischen '' und ""


Double-Quotes (") unterstützen das Ersetzen von Variablen durch ihre Inhalte. Außerdem werden Escapesequenzen für Sonderzeichen erlaubt. Das alles kostet aber performance, die sich zwar im Einzelfall nicht bemerkbar, aber auf die Masse sich merklich auf die Skallierbarkeit einer Anwendung auswirken könnten. Desweiteren hat das Einfügen von Variableninhalten in einen String durch Verkettung den Vorteil, das in IDE's sowie Editoren direkt zu sehen ist, wo in einem String sich die variablen Inhalte befinden.



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        


Handbuch: PHP: Strings - Manual


----------



## grasshopper_1975 (24. Juli 2018)

Bsp.: 2 Variablen - $a="hallo", $b="welt"

Unterschied doppelte und einfache Anführungszeichen
 - doppelte Anführungszeichen 	- php wertet $ etc bei der Ausgabe aus,
 - einfache Anführungszeichen 	- php gibt den String wieder, wertet nichts aus!  

gibt folgendes aus:
c="$a; $b"   -> gibt den string 'hallo welt' aus
c='$a $b'      -> gibt den string '$a $b' aus

.. das ist in etwa der unterschied, ist die selbe Syntax wie in der Bash- bzw. Shell-Programmierung.
Aber daran denken, wenn du einen String angeben bzw. ausgeben willst, sollte man per Default immer
die doppelten Hochkommata nehmen


----------

