PHP Wie sicher sind Cookies?

obilaner

Lt. Junior Grade
Registriert
Apr. 2011
Beiträge
389
Hallo.
Ich wollte mich mal generell über Cookies informieren und wissen wie sicher Cookies sind. Genauer: Kann ein Client die Cookies in seinem Browser selber im klartext auslesen oder beschreiben?

Genaueres Beispiel:
Würde ich im PHP Code eine Abfrage machen ob ein Adminlogin Cookie mit Timeout gesetzt worden ist. Kann ein Client dann durch manipulation seiner Cookies einfach selber das Flag setzen, dh. es sind zb im code wiederholte passworthashabfragen notwendig statt einer einfachen cookie abfrage?

Vielen dank.
 
Natürlich. Der Client schreibt die Cookies, die auf ihm liegen.
Wenn du da selber keine Verschlüsselung einbaust liegen die auch im Klartext vor.
Kannst du auch in der Entwicklerkonsole deines Browsers sehen.

Solche Dinge wie 'Admin Ja/Nein' sollten demzufolge eher nicht in Cookies gespeichert werden ;)
 
  • Gefällt mir
Reaktionen: netzgestaltung, BeBur, e_Lap und eine weitere Person
Der Client kann sehr wohl seine Cookies bearbeiten. Kannst du im Browser in der Dev Konsole ausprobieren (F12).

Daher ist es auch wichtig dass die vom Client gesendeten Daten serverseitig überprüft werden. Daher beispielsweise im Cookie nicht einfach speichern "Admin: yes", sondern z.B. einen auth token hinterlegen, der dann am Server überprüft wird und entsprechende Berechtigung erteilt.
 
  • Gefällt mir
Reaktionen: guzzisti und M4ttX
Reicht es dann aus wenn man innerhalb eines auth cookies einen passwortabruck speichert, der dann vor ausführen des codes jeder php unterseite einmal mit dem db eintrag abgeglichen wird und wenn etwas nicht stimmt umleitung auf die login seite?

Gefahren wären dann ja immernoch das jemand die cookies auslesen kann, der Men in the Middle möglichkeiten hat...

Falls ja müsste man sich so eine Art eigene zweite verschlüsselung / gegenhash überlegen die aus irgendwas individuellem berechnet wird, als gegenschlüssel der auf dem server liegt hmm :/ :D

zb. ein hash der aus time() und dem Wort 'ha0mster' berechnet wird, immer aktuell
Ergänzung ()

Danke. Problem gelöst ^^
 
obilaner schrieb:
Gefahren wären dann ja immernoch das jemand die cookies auslesen kann, der Men in the Middle möglichkeiten hat...
Korrekt. Dagegen gibt es HTTPS.

Ein manuelles Loginsystem wie du es vorschlägst ist aber aus einem anderen Grund keine optimale Lösung.
Wenn ein Angreifer nur den Passworthash braucht, um sich ein Cookie zu erstellen und dann eingeloggt zu sein, wozu sollte man dann überhaupt hashen? Im Grunde wird der Hash zum Geheimnis, obwohl er das nicht sein sollte. Hashing wird ja überhaupt erst eingesetzt, damit man das eigentliche Geheimnis - das Passwort - nicht auf dem Server speichern muss (und sich somit angreifbar macht).
Man sollte also viel eher ein neues Geheimnis im Cookie speichern (und nur verschlüsselt per SSL übertragen).
Für das Problem gibt es bei PHP bereits eine sinnvolle Lösung, PHP Sessions. Letztlich wird damit automatisch ein Cookie namens PHPSESSID gesetzt - mit einer zufälligen ID. Auf dem Server werden mit dieser ID dann verschiedene Daten verknüpft, z.B. eben der Loginstatus, wenn du eine entsprechende Logik in deinem PHP-Code hast.
 
  • Gefällt mir
Reaktionen: Der Lord
Danke.

Heisst das ich kann mit Sessions einfach Auth = Admin oder so speichern und der Client kann das nicht manipulieren?

Die Session ID ist quasi auf dem Server selber. Bloss wie du sagst gäbe es auch das Cookie mit dem namen PHPSESSID. Damit hat er doch dann schonwieder die Session id, oder?!
 
Zuletzt bearbeitet:
Nein, das passiert automatisch. PHP setzt das Cookie automatisch für dich und übernimmt auch den Vergleich der ID, wenn du Sessions verwendest. Du kannst einfach $_SESSION-Variablen setzen, deren Wert automatisch an die ID geknüpft wird.
Auf der verlinkten Seite ist das beispielhaft erklärt. Ansonsten kann man auch ins PHP-Handbuch schauen.
 
Gut. Vielen dank.

Dann nehme ich ab jetzt einfach wieder Sessions. Cookies sind dann ja eh völlig sinnlos und session cookies sicherer und einfacher. Die kann man sicher für viel mehr verwenden als cookies. Musste bisher immer alles mit irgendwelchen POST übergaben übertragen um es nicht in cookies zu schreiben. Sehr schlau.
 
Generell sind Cookies Informationen die der Client sendet, sie sind also grundsätzlich nicht vertrauenswürdig. Deshalb speichert man da meistens einfach nur eine zufällige Session ID, und die echten Informationen liegen auf dem Server wie z.B. welche Recht der Benutzer mit dieser Session ID hat.

Wenn du weitere Informationen in Cookies speichern willst gibt es noch JWTs bei denen der Inhalt kryptografisch signiert wird. Ich würde das aber nicht empfehlen, die Vorteile dürften hier keine Rolle spielen und das ist nochmal deutlich komplexer.

Ansonsten gibt es noch Optionen die Cookies etwas sicherer machen können. Zum Beispiel kann ein HttpOnly Cookie nicht von Javascript aus gelesen werden im Browser. Siehe dazu auch die Dokumentation in der MDN:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
 
  • Gefällt mir
Reaktionen: guzzisti und Der Lord
Du vermischt da diverse Konzepte, Session Cookies sind auch nur Cookies, du kannst deine PHP SessionId aber auch zb als query argument übertragen.

Session Cookies sind nur Cookies die als Lebensdauer die aktuelle Session im Browser haben, das ist nicht so hübsch definiert wie es sich anhört, jeder Browser hat da seine eigenen Vorstellungen wann diese Cookies invalidiert werden.

Bzgl. Schreibbarkeit: Browser honorieren das sog. httpOnly attribut bei den Cookies, d.h. das Cookie wird vom Server gesetzt und kann auch nur über Http übertragen werden, also nicht mal von JS Code auf der Clientseite modifiziert werden (in der DEV Konsole kannst du eh alles machern, das zählt nicht). Zusammen mit secure-only und Themen wie strict mode, sind Cookies ein bewährtes und (mit HTTPS) sicheres Mittel vom Server gesetzte Authentication Information an den Client zu schicken und den das in jedem Request wieder mitschicken zu lassen. Der Inhalt der Cookies ist dann trotzdem signiert und ggf. verschlüsselt um vor bestimmten Angriffen zu schützen. Es ist Aufgabe des Servers (Framework) sicherzustellen dass ein Cookie nicht modifiziert wurde.
 
  • Gefällt mir
Reaktionen: BeBur und guzzisti
obilaner schrieb:
Normalerweise macht man sowas eher nicht selber, sondern verwendet ein einschlägiges Web-Framework wie Laravel. Die kümmern sich um solche technischen Details besser als man das selber üblicherweise könnte.
 
  • Gefällt mir
Reaktionen: sh.
Die Session-Verwaltung von PHP wird wahrscheinlich genau das sein, was du suchst. Hierbei wird der Inhalt der Sitzung auf dem Server gespeichert. Das Cookie enthält nur eine Referenz auf diese Sitzung.

Es gibt allerdings auch Anwendungsfälle bei denen dieses Verhalten nicht gewünscht ist. Als Beispiel fällt mir hier die "Angemeldet bleiben"-Funktion von Webseiten ein.
Diese kann über Sessions nicht abgebildet werden, da diese nur flüchtig gespeichert werden und zum Beispiel bei einem Serverneustart gelöscht werden.

Als Alternative zu Sessions bietet sich dafür wie bereits erwähnt JWT an. Das Prinzip dahinter ist, dass aller Inhalt in dem Cookie gespeichert ist und daher auch vom Benutzer eingesehen werden kann. Allerdings hat der Server den Inhalt mit einem geheimen Schlüssel signiert.
Erhält der Server ein solches Cookie, prüft dieser den Inhalt mit der Signatur ab. Hat der Benutzer das Cookie vorher manipuliert, lehnt der Server das Cookie ab.

Um diese Funktionalität zu realisieren braucht es für PHP auch kein Framework oder dergleichen. Die dazu notwendigen Funktionen liefert PHP von Haus aus mit. Eine Beispielimplementierung kann wie folgt aussehen:
PHP:
<?php
class ContentSigner {

    private readonly string $key;
    private readonly string $algo;
 
    public function __construct(string $key, string $algo = 'sha3-256') {
        $this->key = $key;
        $this->algo = $algo;
    }
 
    public function signContent(string $content) : string {
        $encodedContent = base64_encode($content);
        $hash = $this->hashContent($encodedContent);
        $encodedHash = base64_encode($hash);
        return "$encodedContent.$encodedHash";
    }
  
    public function verifyContent(string $signedContent) : bool {
        return $this->verifyContentInternal($signedContent, $encodedContent);
    }
  
    public function readVerifiedContent(string $signedContent) : ?string {
        if (!$this->verifyContentInternal($signedContent, $encodedContent)) return null;
        return base64_decode($encodedContent, true);
    }
  
    private function hashContent(string $content) : string {
        return hash_hmac($this->algo, $content, $this->key, true);
    }
  
    private function verifyContentInternal(string $signedContent, ?string &$encodedContent) : bool {
        if (substr_count($signedContent, '.') != 1) return false;
        [$encodedContent, $encodedHash] = explode('.', $signedContent);
        if (!($hash = base64_decode($encodedHash, true))) return false;
        return hash_equals($hash, $this->hashContent($encodedContent));
    }

}

////////////////////////////////////////////////////////////////////////////////////////////

$serverKey = '86Ds8WLbUmzKyK8GVPdHHoGiWPlxaS3sd3SlqZmjHY6kGUIV7HP6NBeVuEcAJKi4Cgr1Djziu80us3jv';

$signer = new ContentSigner($serverKey);

$content = 'admin=true';
$signedContent = $signer->signContent($content);

//$signedContent[2] = 'w'; // Einkommentieren für Manipulation

print "Content : $content\n";
print "Signed  : $signedContent\n";

if (($verifiedContent = $signer->readVerifiedContent($signedContent)) !== null) {
    print "Verified: $verifiedContent\n";
} else {
    print "Verified: INVALID\n";
}
Die Ausgabe des Programms ist:
Code:
Content : admin=true
Signed  : YWRtaW49dHJ1ZQ==.sq1de9Oju2EK1oK1R5rxGQHDUsWdUMOdEZMZPUFNgNQ=
Verified: admin=true

Durch Einkommentieren der auskommentierten Zeile wird der Inhalt des Cookies manipuliert und das Programm gibt "INVALID" aus.

Der Schlüssel muss dabei immer geheim gehalten werden und auf diese Weise signierte Cookies sind solange gültig, bis der Schlüssel oder der verwendete Algorithmus geändert werden.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: NPC
Zurück
Oben