2011-01-06 8 views
12

Mi è venuta in mente una tecnica per impedire l'invio di moduli duplicati andando avanti/indietro o aggiornando la pagina. E ho pensato di metterlo in discussione qui, ho già testato un campione non in ambiente di produzione, quali sono i difetti che puoi identificare?Prevenire invii duplicati di moduli

Si noti che sono a conoscenza dell'utilizzo dei token modulo, che ti difenderanno dagli attacchi CSRF e che non è stato aggiunto nei passaggi seguenti.

Generi i Modulo ID per ciascun modulo, e usarlo come campo nascosto nella forma:

$formid = microtime(true)*10000; 

- On Form Submit:

  • Convalida dai dati

  • Calcola l'hash dei dati dei campi modulo

    $allvals = ''; 
    foreach($_POST as $k=>$v){ 
        $allvals .= $v; 
    } 
    $formHash = sha1($allvals); 
    
  • Convalida l'hash del modulo confrontando con gli hash precedentemente salvati. il valore della sessione viene associato a ogni modulo dalla variabile $ formid.

    $allowAction = true; 
    if(isset($_SESSION['formHash'][$_POST['formid']]) && ($_SESSION['formHash'][$_POST['formid']] == $formHash)){ 
        $allowAction = false; 
    } 
    
  • se sotto forma di hash non è stato trovato, significa che questa è la prima forma volta presentata o i dati del modulo è cambiato.
  • Se i dati salvati (a base di dati, per esempio), salvare sotto forma di hash per sessione:

    $_SESSION['formHash'][$_POST['formid']] = $formHash; 
    

La versione completa del codice: http://thebusy.me/2011/01/06/preventing-duplicate-form-submissions/

+0

consideri il benchmarking snippet di hash contro '$ formHash = sha1 (serializzare ($ _ POST));'. Avrà anche le chiavi di hash, che potrebbero essere o meno vantaggiose. – Dan

+0

Probabilmente collegato/DUP, http://stackoverflow.com/questions/4614052/how-to-prevent-multiple-form-submission-on-multiple-clicks-in-php/4614310#4614310 – user562374

+0

Eventuali duplicati di http://stackoverflow.com/questions/218907/how-to-handle-multiple-submissions-server-side –

risposta

7

Un modo più semplice per ottenere ciò che si voglio usare il reindirizzamento su submit. Dopo aver elaborato una richiesta POST, il reindirizzamento, eventualmente anche alla stessa pagina. Questo è un modello comune chiamato "Redirect after POST" o POST/Redirect/GET.

Ad esempio:

<?php 
if($_POST) { 
    // do something 

    // now redirect 
    header("Location: " . $_SERVER["REQUEST_URI"]); 
    exit; 
} 
?> 

<html> ... 
<form method="post" action=""> ... </form> 

Impostando l'azione "" allora presenteranno a se stesso, a questo punto il if ($ _ POST) blocco di codice convaliderà true ed elaborare la forma, poi redirect di nuovo a se stesso.

Ovviamente probabilmente si desidera reindirizzare a una pagina diversa che mostra una risposta "il modulo è stato inviato" oppure posizionare il modulo su una pagina diversa e avere come risposta il codice HTML di questa pagina.

Il vantaggio di questo metodo è che quando si preme il pulsante Indietro fa una richiesta GET in modo che il modulo non venga inviato nuovamente.

Su Firefox, in realtà si sottrae la cronologia del browser alla cronologia del browser, quindi quando gli utenti navigano sul Web e poi si richiamano, anziché visualizzare la pagina di ringraziamento, visualizzano la pagina del modulo.

+0

sì, ho letto su questo, e lo userò per progetti futuri. il problema riguarda i miei attuali siti Web, utilizzo i token di moduli e non desidero modificare la struttura del codice reindirizzando ad altre pagine. Grazie @ newz2000 – isogashii

+1

potresti anche fare un ulteriore passo avanti per abilitare un messaggio di ringraziamento. Impostazione 2 div, una con il modulo e una con il messaggio di ringraziamento. Quindi imposta il ringraziamento div per visualizzare: none in css. ? Hanno il reindirizzamento tornare a formpage.php thankyou = 1 if ($ _GET [ 'Grazie'] == 1) {css per rendere il display none modulo div, e impostare il grazie a display: block} – MSD

+5

Questa deve essere combinato con i token di forma per essere infallibile. Se l'utente si aggiorna o si reinvia mentre la richiesta POST è in corso, si ottiene una richiesta duplicata. – bcoughlan

1

Sembra che tu ti stia complicando troppo.Il mio modo preferito, perché impedisce anche qualche sessione jacking hack, allo stesso tempo, è descritto qui:

http://www.spotlesswebdesign.com/blog.php?id=11

E 'semplice e facile da implementare in qualsiasi forma. Utilizza un id di istanza di pagina generata in modo casuale per verificare che l'invio del modulo ricevuto sia identico all'ultima pagina offerta a quell'utente specifico.

+2

grazie per la risposta, ma, stati post: "E 'importante avere la logica di elaborazione dei moduli si verificano prima di impostare la nuova pagina di sessione ID istanza per questo al lavoro , anche se ci sono modi per aggirare questo. " Prova ad aprire due pagine contemporaneamente, l'invio del primo non funzionerà, perché quando viene aperta la seconda pagina viene generato un nuovo id della pagina, questa è la debolezza di questa tecnica. Ma puoi usare una matrice di ID di pagina generati, confrontarli e rimuovere quello che corrisponde dall'array. – isogashii

+0

Buon punto. L'array è una grande idea. – dqhendricks

+0

@isogashii Ho modificato l'articolo per riflettere il metodo basato su array. – dqhendricks

-1

Entrambe le soluzioni sopra sono buone ma un po 'corte.

come circa l'arresto di ulteriori inserimenti nei prossimi minuti dallo stesso utente con cambiamenti forse minori nei dati?

questo può essere fatto inserendo un hash md5 in un cookie sul computer degli utenti e memorizzandone una copia nel database - in questo modo qualsiasi ulteriore tentativo dalla stessa macchina in un determinato periodo di tempo può essere ignorato e interrotto dall'inserimento in il database.

forse qualcuno può commentare la validità e l'efficacia del mio suggerimento o sono io ad abbaiare contro l'albero sbagliato ???

Problemi correlati