Für Sicherheitscodes generieren Sie Ihre Token bitte nicht wie folgt: $token = md5(uniqid(rand(), TRUE));
Probieren Sie es aus:
Generieren eines CSRF-Tokens
PHP 7
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
Nebenbemerkung: Eines der Open-Source-Projekte meines Arbeitgebers ist eine Initiative zum Backport random_bytes()
und random_int()
in PHP 5-Projekte. Es ist MIT-lizenziert und auf Github und Composer als paragonie / random_compat verfügbar .
PHP 5.3+ (oder mit ext-mcrypt)
session_start();
if (empty($_SESSION['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['token'];
Überprüfen des CSRF-Tokens
Nicht nur verwenden ==
oder sogar ===
verwenden hash_equals()
(nur PHP 5.6+, sondern für frühere Versionen mit der Hash-kompatiblen Bibliothek verfügbar ).
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
Mit Per-Form-Token noch weiter gehen
Sie können Token weiter einschränken, damit sie nur für ein bestimmtes Formular verfügbar sind, indem Sie verwenden hash_hmac()
. HMAC ist eine bestimmte verschlüsselte Hash-Funktion, die auch bei schwächeren Hash-Funktionen (z. B. MD5) sicher verwendet werden kann. Ich empfehle jedoch, stattdessen die SHA-2-Familie von Hash-Funktionen zu verwenden.
Generieren Sie zuerst ein zweites Token zur Verwendung als HMAC-Schlüssel und verwenden Sie dann die folgende Logik, um es zu rendern:
<input type="hidden" name="token" value="<?php
echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />
Verwenden Sie dann eine kongruente Operation, um das Token zu überprüfen:
$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
Die für ein Formular generierten Token können nicht ohne Wissen in einem anderen Kontext wiederverwendet werden $_SESSION['second_token']
. Es ist wichtig, dass Sie ein separates Token als HMAC-Schlüssel verwenden als das, das Sie gerade auf der Seite ablegen.
Bonus: Hybridansatz + Zweigintegration
Jeder, der die Twig-Template-Engine verwendet, kann von einer vereinfachten Doppelstrategie profitieren, indem er diesen Filter zu seiner Twig-Umgebung hinzufügt:
$twigEnv->addFunction(
new \Twig_SimpleFunction(
'form_token',
function($lock_to = null) {
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
if (empty($_SESSION['token2'])) {
$_SESSION['token2'] = random_bytes(32);
}
if (empty($lock_to)) {
return $_SESSION['token'];
}
return hash_hmac('sha256', $lock_to, $_SESSION['token2']);
}
)
);
Mit dieser Twig-Funktion können Sie beide Allzweck-Token wie folgt verwenden:
<input type="hidden" name="token" value="{{ form_token() }}" />
Oder die gesperrte Variante:
<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />
Twig befasst sich nur mit dem Rendern von Vorlagen. Sie müssen die Token noch ordnungsgemäß validieren. Meiner Meinung nach bietet die Twig-Strategie mehr Flexibilität und Einfachheit bei gleichzeitiger Wahrung der Möglichkeit maximaler Sicherheit.
CSRF-Token für den einmaligen Gebrauch
Wenn Sie die Sicherheitsanforderung haben, dass jedes CSRF-Token genau einmal verwendet werden darf, wird es nach jeder erfolgreichen Validierung mit der einfachsten Strategie neu generiert. Dadurch wird jedoch jedes vorherige Token ungültig, was sich nicht gut mit Personen vermischt, die mehrere Registerkarten gleichzeitig durchsuchen.
Paragon Initiative Enterprises unterhält eine Anti-CSRF-Bibliothek für diese Eckfälle. Es funktioniert ausschließlich mit Einweg-Token pro Formular. Wenn in den Sitzungsdaten genügend Token gespeichert sind (Standardkonfiguration: 65535), werden die ältesten nicht eingelösten Token zuerst ausgewechselt.
token_time
wird verwendet?