Frage

Der Hintergrund: Ok, ich laufe auf ninjawars.net ein Vermächtnis BBG über. Es gibt einen „Angriff“, dass die Spieler auf andere Spieler machen kann, die über Form Post initialisiert wird. Im Wesentlichen können wir die Situation vereinfachen, so zu tun, dass eine Seite gibt es, es läßt nennen attack.php, mit einer riesigen „ATTACK“ Form Post, die zu einer anderen PHP-Seite vorträgt, nennt sie es accept_attack.php, und die zweite Seite führt den Angriff Funktionalität, kann sagen, das töten anderen Spieler 1, 2 oder 3. Der Server läuft PHP5, PostgreSQL, Apache

Die Probleme:

  • Wenn ich die groß „ATTACK“ Knopf drücken, und es bringt mich zum accept_attack.php, kann ich dann traf dreimal aktualisieren, jedes Mal erneut einreichen, zum Angriff wieder dreimal hintereinander.
  • Wenn ich drei Registerkarten auf der ersten Seite zu öffnen, und drücken Sie Angriff auf jeder Seite, habe ich am Ende mit drei momentanen Angriffen auf den Spieler 1, 2 und 3 auf einmal zu töten, und ich kann nur immer wieder zu wiederholen, aktualisieren.
  • Trotz meiner Versuche, eine „letzte Angriff“ Timer zu haben, die in der Datenbank gespeichert wird, scheinen Spieler in der Lage zu sein, um ihn zu arbeiten, vielleicht nur durch drei kopiert Registerkarten in einer synchronisierten genug Weise erfrischend, so dass sie alle abrufen den gleichen Timer (zB 10: 00: 00: 0000 Uhr). und damit die resultierenden Verarbeitung fortfahren

Die Lösung benötigt:

So wie ich die gleiche Verarbeitung eines bestimmten Skript verhindern, dass auf einmal in dreifacher Ausfertigung vorgeformten werden?

Php, Social Engineering und / oder JavaScript / jQuery Lösungen bevorzugt (wahrscheinlich in etwa dieser Reihenfolge).

Edit: Basierend auf den Antworten, hier ist was ich getan habe, um (möglicherweise vor Stresstests) löst es: Die Session Antwort schien einfachste / verständlichste zu implementieren, so dass ich verwenden, die Daten speichern. Ich habe es getestet und es scheint zu funktionieren, aber es kann Möglichkeiten geben, um es, dass ich bin mir nicht bewusst.

$recent_attack = null;
$start_of_attack = microtime(true);
$attack_spacing = 0.2; // fraction of a second
if(SESSION::is_set('recent_attack')){
    $recent_attack = SESSION::get('recent_attack');
}

if($recent_attack && $recent_attack>($start_of_attack-$attack_spacing)){
    echo "<p>Even the best of ninjas cannot attack that quickly.</p>";
    echo "<a href='attack_player.php'>Return to combat</a>";
    SESSION::set('recent_attack', $start_of_attack);
    die();
} else {
    SESSION::set('recent_attack', $start_of_attack);
}

Wenn Im moment gibt es Möglichkeiten, um auf dem, oder Möglichkeiten zu verbessern, dass das ausnutzbar ist (über die man mir klar, dass Sachen Echo ist keine gute Trennung von Logik, würde ich gerne wissen. In diese Richtung, Community- wiki-ed.

War es hilfreich?

Lösung

Ähnlich wie Godeke Lösungen. Könnten Sie nicht ein Token mit einem versteckten Bereich auf der „Attack“ Knopfform erzeugen und dass in einer Sitzung speichern? Dann auf der accept-attack.php Seite würden Sie überprüfen, ob die $ _POST [ 'token'] == $ _SESSION [ 'token'].

so würden Sie so etwas wie dies auf der accept-attack.php Seite haben

if($_POST['token'] == $_SESSION['token']){

       echo 'no cheating!';
            // or redirect to the attach page
   }else{
         $_SESSION['token'] = $_POST['token'];
         // then perform the attack
   } 

Andere Tipps

Obwohl womp der Post-Redirect-Get-Muster wird einige Probleme lösen, wenn sie absichtlich den Einreichungsprozess Gaming werden dann bezweifle ich, dass es das Problem, außer gegen die faulen verhindern (wie im verlinkten Artikel erwähnt, Eingaben vor die 302 Antwort mehrere sein wird, wie die Umleitung noch nicht geschehen ist).

Stattdessen werden besser Sie wahrscheinlich einige Informationen Token auf den Angriff Seite setzen, die nicht leicht reproduziert wird. Wenn Sie den Angriff übernehmen, drücken Sie den Angriff in eine Datenbank Warteschlangentabelle. Insbesondere speichert die Informationen Token an die Angriffsseite gesendet, wenn Warteschlangen und überprüft, um zu sehen, ob das Token schon vor Warteschlangen den Angriff verwendet wurde.

Eine einfache Quelle von Token wäre die Ergebnisse einen Zufallszahlengenerator läuft und in einen Tisch. Ziehen Sie die nächste Nummer für jede Attacke Laden der Seite und stellen Sie sicher, dass diese Zahl vor kurzem verteilt worden war. Sie können die Zeichen auf Angriff Seite geladen besiedeln und alle „nicht verwendet“ Token für auf der Grundlage Ihrer Politik verfallen, wie lange eine Seite soll, bevor er als „abgestanden“ zur Verfügung.

Auf diese Weise können Sie eine endliche Menge von „gültig“ Token generieren, veröffentlichen Sie diese Token auf den Angriff Seite (eine pro Seite) und Sie überprüfen, dass sie Token wurde auf der Angriff Verarbeitung Seite nicht bereits verwendet wird. So erstellen Sie wiederholen Angriffe würde der Spieler zu bestimmen, welche Token gültig sind ... die gleiche Post Wiederholung fehl, weil das Token verbraucht wurde. Verwenden Sie einen BigInt und einen anständigen Pseudo-Zufallszahlengenerator und der Suchraum macht es unwahrscheinlich, leicht zu umgehen sein. (Beachten Sie, müssen Sie eine Transaktion um die Token-Validierung und Updates Erfolg mit dieser Methode zu gewährleisten.)

Wenn Sie Benutzerkonten haben, die eine Anmeldung erforderlich ist, können Sie generieren und speichern diese Token für die Benutzertabelle (wieder eine Datenbanktransaktion, um diese Schritte gewickelt verwenden). Dann wird jeder Benutzer würde zu einem Zeitpunkt ein einziges gültiges Token haben und mehrere Anträge auf eine ähnliche Art und Weise gefangen werden würde.

Sie können die meisten Form Wiedervorlage vermeiden, indem Sie die Post-Redirect-Get Muster für Form Beiträge.

Auf den Punkt gebracht, anstatt attack_accept.php aus der ursprünglichen Nachricht zurückzukehren, geben eine 302 Antwort der Browser umgeleitet attack_accept.php. Nun, wenn der Benutzer die Seite neu geladen, sie neu zu laden nur die 302 Anforderung und es gibt keine doppelte Formulareinreichung.

Eine weitere Lösung wäre die Post-Daten serialisieren (i JSon wie ich) und dann Hash das Ergebnis in der DB gespeichert werden.

, wenn der Benutzer die gleiche Information trägt zweimal die Raute in der Datenbank vorhanden ist.

Sie sollten auch einen Zeitstempel auf derselben Tabelle hinzuzufügen, so dass die Hash-Werte können nach X Stunden gelöscht / aktualisiert werden

Beispiel PHP-Pseudo-Code:

$hash = sha1(json_encode($_POST));
$results = $db->exec('SELECT timestamp FROM user_posts WHERE user_id=? AND hash=?', $user_id, $hash);

if ($results != null) {
    // check timestamp, allow if over 24 hours ago
    $ok = ($results['timestamp']+3600*24) < now();
} else {
    // no results, allow
    $ok = true;
}

if ($ok) {
    $db->exec('INSERT INTO user_posts (hash, timestamp) VALUES (?, ?)', $hash, now() );
} else {
    // show error page
    echo "your request has been denied!";
}

Hinweis: Das wird noch die Einreichung von verschiedenen POST-Daten auf einem kurzen Zeitraum ermöglichen, aber das ist auch ganz einfach zu überprüfen

.

sollte diese Lösung unmöglich zu umgehen:

1) hinzufügen ‚NextAttackToken CHAR(32)‘ Spalte zu Ihrer Spieler-Tabelle und gibt jeweils einen Spieler einen zufällig generierte MD5-Wert.

2) Auf der attack.php Seite ein verstecktes Feld ‚current_token‘ mit dem aktuellen Token des Spielers hinzu.

3) In der accept_attack.php Seite, verwenden Sie die folgende Logik, um zu bestimmen, ob der Spieler tatsächlich zum Angriff erlaubt ist:

// generate a new random token
$newToken = md5(microtime(true).rand());

// player is spamming if he has attacked less than 30 seconds ago
$maxTimer = date('Y-m-d H:i:s', strtotime('-30 seconds'));

// this update will only work if the player is allowed to attack
$query = "UPDATE player SET NextAttackToken = '$newToken'
               WHERE PlayerID = $_SESSION[PlayerID]
               AND PlayerLastAttack < '$maxTimer'
               AND NextAttackToken = '$_GET[current_token])'
         ";
$result = mysql_query($query);
if(mysql_affected_rows($result)) {
    echo "Player is allowed to attack\n";
}
else {
    echo "Player is spamming! Invalid token or submitted too soon.\n";
}

Diese Lösung funktioniert, weil mysql nur zu einem Zeitpunkt ein UPDATE auf dem Tisch durchführen kann, und auch wenn es 100 spammed Anfragen an genau die gleiche Zeit, das erste Update von mysql wird das Token ändern und das andere 99 Updates stoppen Auswirkungen auf alle Zeilen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top