sapzero
Goto Top

Mehrfaches Absenden eines Formulars verhindern

Hallo,
ich hab eine Lösung gesucht um ein mehrfaches Abschicken eines Formulas durch Aktualisieren des Browsers oder Backtaste zu verhindern.
Dies habe ich so gelöst und es funktioniert:

Datenbank verbunden -->
Tabelle erstellt mit ID,Text,Datum -->

<form name="formular" action="#" method="post">  
<textarea name="text" cols="50" rows="4"></textarea>  
<input name="send" style="margin-left: 10px" type="submit" value="Send" />  
<input name="hidden" type="hidden" value="<?= uniqid(""); ?>">  
</form>

$text = $_POST['text'];  
$hidden = $_POST['hidden'];  

if(isset($_POST['send']))  
{
	if($_SESSION["hidden"] != $_POST["hidden"])  
	{
		$_SESSION["hidden"] = $_POST["hidden"];  
		if(strlen($_POST['text']) > 0)  
		{	
			$news = "INSERT INTO tblTest VALUES ('','$text',now())";  
			mysql_query($news) OR DIE ("Fehler beim Einfügen in die Tabelle:<br/ >".mysql_error());  
			echo "Text erfolgreich eingefügt!!!<br><br>";  
		}
		else
		{
			echo "Ihr Text ist zu kurz!!!<br><br>";  
		}
	}
	else
	{
		echo "Mehrfaches einfügen verhindert!!!<br>";  
	}
}

Jedoch habe ich gelsen man sollte die ID in eine Datenbank speichern und dazu noch die aktuelle Zeit mit speichern.
Jetzt zu meiner Frage ist dies notwendig oder reicht auch meine Version?
Sollte ich noch was zu meinem Code ergänzen?
Oder gibt es noch besser/sichere Lösungen?

Ich würde mich auf eine schnelle Antwort freuen

Gruß

Sapzero

Content-Key: 117214

Url: https://administrator.de/contentid/117214

Printed on: April 19, 2024 at 02:04 o'clock

Member: dog
dog Jun 01, 2009 at 01:47:20 (UTC)
Goto Top
Was möchtest du denn nun verhindern?
Dass dein Formular mehrfach abgesendet wird, oder dass es mehrere identische Datensätze gibt?
Das sind zwei verschiedene Paar Schuhe.

Ich gehe mal aus, dass es bei deiner Lösung mit der uniqid() noch mehr Code gibt, als du uns hier zeigst - dann wäre das als CSRF-Schutz und gegen mehrfaches Absenden durchaus ausreichend (Zusätzlich sollte man dem Benutzer aber auch visuell zeigen, dass sein Formular abgesendet wurde).

Gegen Datenbankduplikate helfen aber nur Gegenprüfungen und UNIQUE-Constraints...

Und dann gibt es in deinem Code noch eine klassische SQL-Injection-Lücke...

Grüße

Max
Member: Sapzero
Sapzero Jun 01, 2009 at 22:13:23 (UTC)
Goto Top
Hallo,
danke für deine Antwort.
Also ich wollte eigentlich nur verhindern das es nicht mehrere identische Datensätze gibt.
Das war auch der ganze Code ich hab euch nichts vorenthalten nur halt noch die Datenbank verbindung und die Erstellung der Tabelle.

Du sagtest, dass es ein Unterschied sei ein mehrfaches Absenden zu verhinden und doppelte Einträge zu verhindern.
Wo ist der Unterschied und wieso verhindert man mehrfaches Absenden eines Formulars?

Und könntest du mir noch sagen wo die SQL-Injection-Lücke ist?
Ich würde jetzt sagen bei $_POST['text'] oder?

Gruß

Sapzero
Member: dog
dog Jun 02, 2009 at 00:12:22 (UTC)
Goto Top
Also ich wollte eigentlich nur verhindern das es nicht mehrere identische Datensätze gibt.

Dann musst du dein Datenbank-Schema entsprechend anpassen und evtl. noch einmal mit PHP kontrollieren, dass keine Duplikate entstehen.

Wo ist der Unterschied und wieso verhindert man mehrfaches Absenden eines Formulars?

Das hast du doch schon selbst geschrieben:

durch Aktualisieren des Browsers oder Backtaste zu verhindern.

Abgesehen davon gibt es auch durchaus noch sicherheitsrelevante Gründe. Siehe dazu: CSRF

Und könntest du mir noch sagen wo die SQL-Injection-Lücke ist?

Hier:
 $news = "INSERT INTO tblTest VALUES ('','$text',now())";   


Das war auch der ganze Code

Das passt so aber nicht.
Der Ablauf mit uniqid() muss folgender sein:

  • uniqid() erzeugen und in SESSION-Variable speichern
  • erzeugte Variable in Formular einbauen
  • Nach dem Absenden die alte uniqid auf Gültigkeit prüfen und danach gleich eine neue erzeugen

Hier ist mal beispielhaft eine kurze Implementation:
<?php

	/** Allgemeine Funktionen zu uniqid()s
	 * ====================================
	 * create_new_key() -> erzeugt eine neue uniqid() und sichert die alte <bei jedem seitenaufruf>
	 * check_key() -> prüft die alte uniqid() <für abgesendete formulare>
	 * current_key() -> die aktuelle uniqid() <beim erzeugen von formularen>
	 */
	
	function create_new_key()
	{
		$_SESSION['_oldkey'] = @$_SESSION['_newkey'];  
		$_SESSION['_newkey'] = uniqid();  
	}
	
	function check_key($key)
	{
		return ($key === @$_SESSION['_oldkey']);  
	}
	
	function current_key()
	{
		return $_SESSION['_newkey'];  
	}

	//Um $_SESSION zu benutzen muss es eine aktive Session geben
	session_start(); 
	//Die Funktion erzeugt erstmal die uniqids();
	create_new_key();
	//folgender Code wird nur ausgeführt, wenn das Formular abgesendet wurde
	if (isset($_POST['frm_sent'])) {  
		//Den alten Key gegen den gesendeten (=der alte) prüfen
		if(!check_key($_POST['frm_sent']))  
			die("Das Formular ist nicht mehr gültig!");  
	}
?>
<html><body>
	<form action="#" method="post">  
		<p>
			<input type="hidden" name="actionkey" value="<?php echo current_key() ?>" />  
			<input type="submit" value="Absenden" name="frm_sent" />  
		</p>
	</form>
</body></html>

Grüße

Max
Member: Pyradur
Pyradur May 07, 2011 at 21:51:06 (UTC)
Goto Top
Hallo Max,
vielen Dank für Dein ausführliches Beispiel das sehr hilfreich für mich war.

Wenn ich nicht irre hat sich in Zeile 33 ein Fehler eingeschlichen.

Zeile 33 sollte lauten: if(!check_key($_POST['actionkey']))

An Stelle von Zeile 34 habe ich folgenden Code eingefügt, durch den
der Aufruf des aktuellen Formulares ohne Übergabeparameter wie POST oder GET erfolgt:

header("Location: ".$_SERVER[PHP_SELF]);

In meinem Fall war dies sinnvoll da es sich um eine Tabelle mit Eingabemöglichkeiten handelte.
So wurde die Tabelle einfach erneut angezeigt ohne dass ungewollte Änderungen stattfanden.

Gruß
Reinhold

(Besser spät als nie)