sapzero
Goto Top

Sonderzeichen umwandeln HTML injection verhindern

Hi,
ich will meine Seite sicher vor Angriffen machen, da soll man ja für gewöhnlich htmlspecialchars() verwenden.
Jedoch weis ich nicht genau was ich alles beachten muss bei der Versendung eines Formulars und dann bei dem einfügen in eine Datenbank.

Beispiel:
$nachricht=htmlspecialchars($_POST('nachricht'));  
1. Sollte ich das Abspeichern in eine andere Variablen hier $nachricht verhinden und direkt dann z.B. in die Datenbank eintragen oder ist der Gebrauch der $nachricht Variable nicht ganz so tragisch?

2. Würde der Code ausreichen um die Seite sicher zu machen?
3. Muss ich noch etwas beim Einfügen in die Datenbank beachten und auch bei der Ausgabe?
4. Sollte ich auch auch andere Funktionen wie stripslasches(), trim(), usw. benutzen? Wenn ja welche?

Würd mich freuen wenn jemand behilflich sein könnte und mir sagen würde was ich alles bei so etwas beachten sollte.

Gruß

Sapzero

Content-Key: 125913

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

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

Member: Arano
Arano Sep 28, 2009 at 09:48:37 (UTC)
Goto Top
Hallo Sapzero

du solltest dir auf jeden Fall einmal die folgenden beiden Seiten zum Thema SQL-Injection durchlesen:
Im diesem Sinne wird dann auch diese Seite noch einmal interessant:

Zu beachten gilt immer:
Alle Benutzereingaben sind böse !
Und dabei sollte man auch nicht zwischen Besuchern und Administratoren unterscheiden.

Was du auch noch machen kannst ist das Prüfen der Eingaben mit regulären Ausdrücken und den Variablenfunktionen, z.B.:is_numeric().
So kann man anhand dieser Auswertung dem Benutzer zur erneuten Eingabe auffordern, oder es einfach ignorieren so das die bösen Eingaben gar nicht erst in einem SQL-Query genutzt werden.
<code type=php">
$errorfields=array();

/*###########################
eintrag pruefen ######
*/
$newE=array('name' =>isset($_POST['name']) && trim($_POST['name'])!='' ? trim($_POST['name']) : NULL,
'email'=>isset($_POST['email']) && trim($_POST['email'])!='' ? trim($_POST['email']) : NULL,
'home' =>isset($_POST['home']) && trim($_POST['home'])!='' ? trim(str_replace('http://','',$_POST['home'])) : NULL,
'text' =>isset($_POST['text']) && trim($_POST['text'])!='' ? trim($_POST['text']) : NULL,
'cap' =>isset($_POST['cap']) && trim($_POST['cap'])!='' ? trim($_POST['cap']) : NULL,
'zahl' =>isset($_POST['zahl']) && is_numeric($_POST['zahl'])!='' ? (int)$_POST['zahl'] : NULL
);

email und homepage sind optionale eingaben
if(!is_null($newE['email']) && !preg_match('/^[a-z0-9]+?[a-z0-9\-_.]+[a-z0-9]+@[a-z0-9]+?[a-z0-9\-_.]+[a-z0-9]+?\.[a-z]{2,5}$/i',$newE['email'])) $errorfields='E-Mail';
if(!is_null($newE['home']) && !preg_match('/^(http:\/\/|www.|http:\/\/www.)?[a-z0-9\-_.]+\.[a-z]{2,5}([a-z0-9\-_.:\/?&;=%]*)$/i',$newE['home'])) $errorfields='Homepage';
$cap=NULL;

/*#############################
eintrag speichern ######
*/
if(empty($errorfields))
wenn alle felder gueltig sind
{
es gibt wahrscheinlich keine fehleingaben, speicher neuen eintrag
eingaben in SQL-Query integrieren und an db-server schicken
natürlich mysql_real_escpe_string() nicht vergessen
Ich übergebe das $newE-Array an eine Klasse die die Daten dann weiterverarbeitet.
}
else
{
ungueltige eingaben
ungueltige eingaben verwerfen und erneut das formular anzeigen
echo 'Die Eingaben der Felder "'.implode('","',$errorfields).'" wurden nicht akzeptiert !';
}
Edit: Oha, das liest sich aber blöde...


~Arano
Member: Sapzero
Sapzero Sep 28, 2009 at 11:29:19 (UTC)
Goto Top
Hallo Arano,
danke für deinen Beitrag. Ich habe mir die Seiten durchgelesen.
Bei deinem Beispiel blicke ich leider nicht durch, weil es zu Kompliziert für mich ist.
Ich hatte auf eine einfachere Lösung gehofft.

Worauf ich aber bei deinen Seiten gestoßen bin ist das hier:
Ein Beispiel für MySQL: anstatt

$abfrage = "SELECT spalte1  
            FROM tabelle
            WHERE spalte2 = '".$_POST['spalte2Wert']."'";  
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");  

sollte Folgendes verwendet werden:

$abfrage = "SELECT spalte1  
            FROM tabelle
            WHERE spalte2 = '".mysql_real_escape_string($_POST['spalte2Wert'])."'";  
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");  
Dies war auch eigentlich meine Frage, ob es ausreicht die funktion "mysql_real_escape_string" bei einer Datenbankabfrage und bei html die funktion "htmlspecialchars" vor die Variable zu setzen und somit die Benutzereingaben zu entschärfen.

Hier nochmals mein Beispiel:
$nachricht=htmlspecialchars($_POST('nachricht'));  

Und nochmals Danke für deine schnelle Antwort

Gruß

Sapzero
Member: Arano
Arano Sep 28, 2009 at 12:27:23 (UTC)
Goto Top
Mahlzeit

ob es ausreicht die funktion "mysql_real_escape_string" bei einer Datenbankabfrage und bei html die funktion "htmlspecialchars" vor die Variable zu setzen
Naja öhm... so direkt kann ich das leider auch nicht beantworten, auf jeden Fall wird es dadurch sicherer !

Zu kompliziert hm... ich kann es ja einmal versuch zu erklären, belasse es dabei erst mal auf die Eingabe eines Namens:
Vorweg eine alternative Syntax für ein If/else
<?php
if( BEDINGUNG ){
    $var='wert';  
}
else{
    $var=NULL;
}
// ist das selbe wie:
$var = BEDINGUNG ? 'wert1' : NULL;  
?>
Das macht es jetzt vielleicht noch verständlicher.

$name = isset($_POST['name']) && trim($_POST['name'])!='' ? trim($_POST['name']) : NULL;  
Wenn das Formularfeld "name" übertragen wurde und dessen "getrimmter" Inhalt nicht leer ist, schreibe den getrimmten Inhalt in die Variable - andernfalls schreibe NULL in die Variable.
if(is_null($name) ||  !preg_match('/^([a-zA-Z]{3,20})$/',$name)) $error = 'Name;'  
Wenn der Inhalt der Variable $name gleich NULL entspricht oder nicht auf den regulärem Ausdruck passt, füge den Formularfeldtitel dem $error-Array hinzu.
Zu dem regulärem Ausdruck (RegEx = regular expression): Bei dem Namen habe ich in diesem Fall bestimmt, das dieser nur aus kleinen und großen Buchstaben bestehen darf (a-z und A-Z) und eine Länge von mindestens 3 bzw. längstes 20 Zeichen haben darf.
Wird nun ein - oder ' oder ein sonstiges Zeichen in das Feld eingetragen um z.B. eine SQL-Injection zu starten, so führt das zu einem Fehler und das Skript abgebrochen - die Injection verhindert.
if(empty($error))
{
    // keine Fehleingaben / SQL-Injection, speichere...
}
else
{
    // Fehleingaben / SQL-Imjection, abbruch !
}
Wenn das $error-Array leer ist, haben die Eingaben meine oberen Test bestanden und sind vermutlich (hoffentlich) keine SQL-Injectionen, schließlich kann man ja nicht an jede Möglichkeit denken und 100% Sicherheit gibt es ja nicht.
Sollte das $error-Array doch nicht leer sein breche ich die Weiterverarbeitung ab, so habe ich mindestens "ungewollte" Fehleingaben verhindert und stoppe leichte versuche der Injectionen.

Um die Sicherheit noch weiter zu erhöhen, wird dann beim eintragen in die Datenbank wieder die Funktion mysql_real_escape_string() verwendet.

Schwieriger wird dann schon bei solchen Eingabefeldern wie Textareas. Denn hier kann ich wie bei dem Namen nicht einfach bestimmen das nur a-zA-Z erlaubt sind, hier mache ja auch andere Zeichen Sinn: ?!"-'.,;:äü$%Éé und so weiter und sofort. Hier sollte dann auf jeden Fall die Escape-Funktion benutzt werden.
Aber auch die Verwendung von PHP-Manual: htmlspecialchars(ENT_QUOTES) ist sicher ratsam, wenn PHP-Manual htmlentities(ENT_QUOTES) (de2.php.net) nicht vielleicht sogar zu bevorzugen wäre, weil diese alle Sonderzeichen umwandelt.


~Arano
Member: Supermax
Supermax Sep 28, 2009 at 16:54:11 (UTC)
Goto Top
SQL Injection und sonstige EIngabefilterungen sind grundsätzlich mal zwei verschiedene Paar Schuhe...

Bei der SQL Injection geht es darum zu verhindern, daß durch eine Benutzereingabe ungewollte Befehle an den SQL-Server abgesetzt werden, indem z.B. durch ein ' in der Benutzereingabe ein String vorzeitig beendet und der Rest der Eingabe als neuer SQL-Befehl interpretiert wird.

Hier leistet mysql_real_escape_string() gute Dienste, da reservierte Zeichen in (my)SQL durch die entsprechenden Escape-Sequenzen ersetzt werden. Darüber hinaus sollte man, wie bereits hier erwähnt, alle Eingaben auf Korrektheit überprüfen und ggfs. unerwünschte Zeichen oder Zeichenketten ausfiltern, etwa auch CR und LF-Zeichen, wenn die Eingabe an sich nur einzeilige Angaben zuläßt. Es gibt genügend Tricks, um auch in einem an sich einzeiligen Formularfeld Zeilenvorschübe zu verstecken, was u.a. bei Mail-Formularen zu Problemen führen kann, wenn eine eingegebene Adresse ungefiltert an die mail() - Funktion übergeben wird.

htmlspecialchars() sollte vor allem bei der Ausgabe eingesetzt werden, um zu verhindern, daß vom Benutzer eingegebene HTML-Tags (vor allem <script> aber auch z.B. <iframe> im Kontext der eigenen Webseite erscheinen). Zusätzlich zu htmlspecialchars() sollte hier aber auch strip_tags() verwendet werden, um alle oder bestimmte HTML-Tags aus der Usereingabe zu filtern.
Member: Sapzero
Sapzero Sep 28, 2009 at 21:57:12 (UTC)
Goto Top
OK danke jetzt habe ich ein wenig verstanden was der Code bezwegt :D
Auch eine andere Frage hast du mir auch schon beantwortet undzwar was ich benutzen soll htmlspecialchars oder htmlentities.
Member: Sapzero
Sapzero Sep 28, 2009 at 22:17:43 (UTC)
Goto Top
hi,
wo du gerade das Mailformular anspricht ich habe mir da eins zusammen gebastelt und würde mich freuen wenn du drüber schauen würdest.
Könntest du mir sagen wo ich alles was raus Fitern muss und vllt auch den Fehler finden, weil es irgendwie nicht funktioniert und ich weis net wieso.

<?php session_start(); ?>
<?php 
  // Datenbankverbindung
  //---------------------------------------------------				  
  //MIT DEM MySQL SERVER VERBINDEN
  
	$mysqluser = "...";		  
	$mysqlpasswd = "...";			  
	$mysqlhost = "localhost";  
	$db_name = "...";	  

	$connID = @mysql_connect($mysqlhost, $mysqluser, $mysqlpasswd) or die("Verbindungsversuch fehlgeschlagen");  
         mysql_query("USE $db_name");  
           
?>
<?php
$empfaenger = 'test@....de';  
$hidden		= $_POST['hidden'];  
$name   	= $_POST['name'];  
$email      = $_POST['email'];  
$betreff    = $_POST['betreff'];  
$nachricht 	= $_POST['nachricht'];  

if(isset($_POST['abschicken']))  
{
	if($_SESSION["hidden_alt"] != $_POST["hidden"])  
	{
		$_SESSION["hidden_alt"] = $_POST["hidden"];  
		if(strlen($_POST['name'])>=2)  
		{	
				if(strlen($_POST['betreff'])>=4)  
				{
					if(strlen($_POST['nachricht'])>=10)  
					{
                                             mail($empfaenger, $betreff, $nachricht, "From: $name <$email>")  
                                             or die("Die Mail konnte nicht versendet werden.<br>");  
                                             header("Location: kontakt.php");  
                                             exit;	
					}
					else
					{
					$fehler_nachricht = "<font color=red>Sie haben keine Nachricht verfasst.</font><br>";  
					}	
				}
				else
				{
				$fehler_betreff = "<font color=red>Geben sie den Betreff Ihrer Nachricht ein.</font><br>";  
		}
		else
		{
		$fehler_name = "<font color=red>Geben sie ihren Namen ein.</font><br>";  
		}	
	}
}
?>

<form name="kontakt" method="post" action="kontakt.php" />  
<b>Name &nbsp;</b>
<input type="text" name="name" />  
<b>E-mail &nbsp;</b>
<input type="text" name="email" />  
<b>Betreff &nbsp;</b>
<input type="text" name="betreff" />  
<b>Nachricht &nbsp;</b>
<textarea class="textfeldkontakt" name="nachricht" cols="10" rows="5"></textarea>  
<input type="submit" name="abschicken" value="Abschicken" />&nbsp;  
<input type="reset" name="zuruecksetzen" value="Zur&uuml;cksetzen" />  
<input name="hidden" type="hidden" value="<?= uniqid(""); ?>">  
</form>
Member: Sapzero
Sapzero Oct 02, 2009 at 02:11:04 (UTC)
Goto Top
Hi,
was ich noch fragen wollte ist es auch möglich statt htmlspecialchars einfach die Eingaben mit preg_replace zu ersetzen.
Hier ein Beispiel:
$such = array("\","/","<",">",....);    //alle zeichen die in die Eingabe net hingehören  
$ersetzung = "";  
preg_replace($such, $ersetzung, $eingabe);
Oder mit strpos durchsuchen und entscheiden ob es weiterverarbeitet wird oder net
if(strpos($eingabe, "\") || strpos($eingabe, "/") || und so weiter)  
{
  nicht weiterverarbeiten...
}
else
{
  weiterverarbeiten...
}
Also ob man gleich nach den Zeichen suchen soll und sie ersetzen soll statt sie umzuwandeln.
Member: Arano
Arano Oct 02, 2009 at 12:14:29 (UTC)
Goto Top
was ich noch fragen wollte ist es auch möglich statt htmlspecialchars einfach die Eingaben mit preg_replace zu ersetzen.
Möglich ist es - klar !
Aber für solche einfachen ersetzungen sollte dann lieber auf "str_replace" zurückgegriffen werden.

Und bevor du nun nach jedem Zeichen einzeln in dem Text suchst (strpos), dann ersetze sie doch lieber mit "str_replace" durch nichts: str_replace(array, '', $text);


~Arano
Member: Sapzero
Sapzero Oct 02, 2009 at 15:47:38 (UTC)
Goto Top
OK mach ich und danke für deine Hilfe face-wink