Ich betreibe eine Website und es gibt ein Punktesystem, das Ihnen Punkte für die Häufigkeit gibt, mit der Sie ein Spiel spielen.
Es verwendet Hashing, um die Integrität der http-Anforderung für die Bewertung zu beweisen, sodass Benutzer nichts ändern können. Wie ich jedoch befürchtet hatte, stellte jemand fest, dass sie es nicht ändern mussten, sondern nur eine hohe Punktzahl erzielen und die duplizieren mussten http Anfrage, Header und alle.
Zuvor war es mir verboten worden, mich vor diesem Angriff zu schützen, da dies als unwahrscheinlich angesehen wurde. Jetzt, wo es passiert ist, kann ich es jedoch. Die http-Anfrage stammt aus einem Flash-Spiel und wird dann von PHP validiert und von PHP in die Datenbank eingegeben.
Ich bin mir ziemlich sicher, dass Nonces das Problem lösen werden, aber ich bin mir nicht ganz sicher, wie ich sie implementieren soll. Was ist eine übliche und sichere Methode zum Einrichten eines Nonce-Systems?
quelle
Antworten:
Es ist eigentlich ganz einfach ... Es gibt einige Bibliotheken, die das für Sie erledigen können:
Oder wenn Sie Ihre eigenen schreiben möchten, ist es ziemlich einfach. Verwenden der WikiPedia-Seite als Ausgangspunkt, Im Pseudocode:
Auf der Serverseite benötigen Sie zwei vom Client aufrufbare Funktionen
getNonce() { $id = Identify Request //(either by username, session, or something) $nonce = hash('sha512', makeRandomString()); storeNonce($id, $nonce); return $nonce to client; } verifyNonce($data, $cnonce, $hash) { $id = Identify Request $nonce = getNonce($id); // Fetch the nonce from the last request removeNonce($id, $nonce); //Remove the nonce from being used again! $testHash = hash('sha512',$nonce . $cnonce . $data); return $testHash == $hash; }
Und auf der Kundenseite:
sendData($data) { $nonce = getNonceFromServer(); $cnonce = hash('sha512', makeRandomString()); $hash = hash('sha512', $nonce . $cnonce . $data); $args = array('data' => $data, 'cnonce' => $cnonce, 'hash' => $hash); sendDataToClient($args); }
Die Funktion muss
makeRandomString
wirklich nur eine Zufallszahl oder Zeichenfolge zurückgeben. Je besser die Zufälligkeit, desto besser die Sicherheit ... Beachten Sie auch, dass die Implementierungsdetails von Anforderung zu Anforderung keine Rolle spielen, da sie direkt in eine Hash-Funktion eingespeist werden. Die Client-Version und die Server-Version müssen nicht übereinstimmen. Tatsächlich ist das einzige Bit, das zu 100% übereinstimmen muss, die Hash-Funktion, die inhash('sha512', $nonce . $cnonce . $data);
... Hier ist ein Beispiel für eine einigermaßen sicheremakeRandomString
Funktion ...function makeRandomString($bits = 256) { $bytes = ceil($bits / 8); $return = ''; for ($i = 0; $i < $bytes; $i++) { $return .= chr(mt_rand(0, 255)); } return $return; }
quelle
$id
? Wenn wir eine Sitzung verwenden, müssen Sie die Sitzungs-ID an den Client übergeben und die Sitzungs-ID des Clients an den Server zurücksenden, um zu erkennen, welche Nonce verwendet wird.Nonces sind eine Dose Würmer.
Nein, eine der Beweggründe für mehrere CAESAR- Einträge war das Entwerfen eines authentifizierten Verschlüsselungsschemas, das vorzugsweise auf einer Stream-Verschlüsselung basiert und gegen die Nicht-Wiederverwendung resistent ist. (Die Wiederverwendung einer Nonce mit AES-CTR zerstört beispielsweise die Vertraulichkeit Ihrer Nachricht in dem Maße, wie ein Programmierstudent im ersten Jahr sie entschlüsseln könnte.)
Es gibt drei Hauptgedankensschulen mit Nonces:
1
).Vor diesem Hintergrund sind folgende Fragen zu stellen:
Nonce generieren
Die Antwort auf Frage 2 für zufällige Nonce ist die Verwendung eines CSPRNG. Für PHP-Projekte bedeutet dies Folgendes:
random_bytes()
für PHP 7+ Projekterandom_bytes()
Diese beiden sind moralisch gleichwertig:
$factory = new RandomLib\Factory; $generator = $factory->getMediumStrengthGenerator(); $_SESSION['nonce'] [] = $generator->generate(32);
und
$_SESSION['nonce'] []= random_bytes(32);
Nonce validieren
Staatsbürgerlich
Stateful Nonces sind einfach und zu empfehlen:
$found = array_search($nonce, $_SESSION['nonces']); if (!$found) { throw new Exception("Nonce not found! Handle this or the app crashes"); } // Yay, now delete it. unset($_SESSION['nonce'][$found]);
Fühlen Sie sich frei, die
array_search()
durch eine Datenbank oder eine zwischengespeicherte Suche usw. zu ersetzen .Staatenlos (hier sind Drachen)
Dies ist ein schwer zu lösendes Problem: Sie benötigen eine Möglichkeit, um Wiederholungsangriffe zu verhindern, aber Ihr Server weist nach jeder HTTP-Anforderung eine vollständige Amnesie auf.
Die einzig vernünftige Lösung wäre die Authentifizierung eines Ablaufdatums / einer Ablaufzeit, um den Nutzen von Wiederholungsangriffen zu minimieren. Zum Beispiel:
// Generating a message bearing a nonce $nonce = random_bytes(32); $expires = new DateTime('now') ->add(new DateInterval('PT01H')); $message = json_encode([ 'nonce' => base64_encode($nonce), 'expires' => $expires->format('Y-m-d\TH:i:s') ]); $publishThis = base64_encode( hash_hmac('sha256', $message, $authenticationKey, true) . $message ); // Validating a message and retrieving the nonce $decoded = base64_decode($input); if ($decoded === false) { throw new Exception("Encoding error"); } $mac = mb_substr($decoded, 0, 32, '8bit'); // stored $message = mb_substr($decoded, 32, null, '8bit'); $calc = hash_hmac('sha256', $message, $authenticationKey, true); // calcuated if (!hash_equals($calc, $mac)) { throw new Exception("Invalid MAC"); } $message = json_decode($message); $currTime = new DateTime('NOW'); $expireTime = new DateTime($message->expires); if ($currTime > $expireTime) { throw new Exception("Expired token"); } $nonce = $message->nonce; // Valid (for one hour)
Ein aufmerksamer Beobachter wird feststellen, dass dies im Grunde eine nicht standardkonforme Variante von JSON-Web-Tokens ist .
quelle
Eine Option (die ich im Kommentar erwähnt habe) ist das Aufzeichnen des Gameplays und das Wiedergeben in einer sicheren Umgebung.
Die andere Sache ist, zufällig oder zu bestimmten Zeiten scheinbar unschuldige Daten aufzuzeichnen, die später verwendet werden können, um sie auf dem Server zu validieren (wie plötzlich geht Live von 1% auf 100% oder Punktzahl von 1 bis 1000, was auf Betrug hinweist ). Mit genügend Daten ist es für Betrüger möglicherweise nicht möglich, zu versuchen, sie zu fälschen. Und dann natürlich schweres Verbot implementieren :).
quelle
Es ist nicht möglich, Betrug zu verhindern. Sie können es nur schwieriger machen.
Wenn jemand hierher gekommen ist, um nach einer PHP Nonce-Bibliothek zu suchen: Ich empfehle, die erste von ircmaxwell nicht zu verwenden .
Der erste Kommentar auf der Website beschreibt einen Designfehler:
Wenn Sie nach einer Möglichkeit suchen, Nonces mit einer genau definierten Lebensdauer zu generieren, schauen Sie sich NonceUtil-PHP an .
Haftungsausschluss: Ich bin der Autor von NonceUtil-PHP
quelle
Diese sehr einfache Nonce ändert sich alle 1000 Sekunden (16 Minuten) und kann verwendet werden, um XSS zu vermeiden, wenn Sie Daten an und von derselben Anwendung senden. (Wenn Sie sich beispielsweise in einer einseitigen Anwendung befinden, in der Sie Daten über Javascript veröffentlichen. Beachten Sie, dass Sie von der Post- und der Empfangsseite aus auf denselben Seed- und Nonce-Generator zugreifen müssen.)
function makeNonce($seed,$i=0){ $timestamp = time(); $q=-3; //The epoch time stamp is truncated by $q chars, //making the algorthim to change evry 1000 seconds //using q=-4; will give 10000 seconds= 2 hours 46 minutes usable time $TimeReduced=substr($timestamp,0,$q)-$i; //the $seed is a constant string added to the string before hashing. $string=$seed.$TimeReduced; $hash=hash('sha1', $string, false); return $hash; }
Wenn Sie jedoch nach der vorherigen Nonce suchen, wird der Benutzer nur dann gestört, wenn er im schlimmsten Fall mehr als 16,6 Minuten und im besten Fall 33 Minuten gewartet hat. Wenn Sie $ q = -4 einstellen, hat der Benutzer mindestens 2,7 Stunden Zeit
function checkNonce($nonce,$seed){ //Note that the previous nonce is also checked giving between // useful interval $t: 1*$qInterval < $t < 2* $qInterval where qInterval is the time deterimined by $q: //$q=-2: 100 seconds, $q=-3 1000 seconds, $q=-4 10000 seconds, etc. if($nonce==$this->makeNonce($seed,0)||$nonce==$this->makeNonce($seed,1)) { //handle data here return true; } else { //reject nonce code return false; } }
Der $ seed kann ein beliebiger Funktionsaufruf, Benutzername usw. sein, der im Prozess verwendet wird.
quelle