Entwickler-Ecke
Off Topic - [PHP]Einen String entschärfen
Marco D. - Mi 27.12.06 21:58
Titel: [PHP]Einen String entschärfen
Ich möchte eine PHP-Funktion schreiben, die einen string 'entschärft', sodass er gefahrlos in die DB eingetragen werden kann. So will ich Angriffen wie z.B. XSS vorbeugen.
Kann man das so machen? Was fehlt noch?
C#-Quelltext
1: 2: 3: 4: 5: 6: 7:
| function DefuseString($string) { $string = mysql_real_escape_string($string); $string = html_special_chars($string); ... return $string; } |
jakobwenzel - Mi 27.12.06 21:59
Wenn du den String nur gefahrlos in ne Datenbank eintragen willst, kannste des html_special_chars auch weglassen. Nur für die HTML-Ausgabe is das muss.
Marco D. - Mi 27.12.06 22:04
jakobwenzel hat folgendes geschrieben: |
Wenn du den String nur gefahrlos in ne Datenbank eintragen willst, kannste des html_special_chars auch weglassen. Nur für die HTML-Ausgabe is das muss. |
Ok, gibt es dann noch mehr Funktionen, die man braucht? Dann kann ich ja auch gleich mysql_real_escape_string nehmen, wenn es bloß die eine wäre. ;)
Arne K. - Mi 27.12.06 22:56
Wenn du den String in die Datenbank speicherst: mysql_escape_string().
Wenn du ihn anzeigen willst:
htmlentities(); bzw. html_entities(); (bin mir gerade nicht so sicher).
Ändere niemals den String, bevor du ihn in die DB einträgst (außer Escapen)! Nach dem Auslesen kannst du mit ihm machen, was du willst! Wenn du ihn aber schon vorformatiert aus der DB bekommst, ist jede nachträgliche Korrektur unmöglich bzw. äußerst aufwändig!
GTA-Place - Do 28.12.06 11:54
Zitat: |
The String has been defused. Anti-Hacker wins. |
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| if (!empty($_GET)) extract($_GET); if (!empty($_POST)) extract($_POST);
function kill_tags_deep($value) { $value = is_array($value) ? array_map('kill_tags_deep', $value) : trim(strip_tags(stripslashes($value)));
$bad = array ('@<script[^>]*?>.*?</script>@si', '@<[\/\!]*?[^<>]*?>@si', '@&(quot|#34);@i', '@&(amp|#38);@i', '@&(lt|#60);@i', '@&(gt|#62);@i', '@&(nbsp|#160);@i', '@&(iexcl|#161);@i', '@&(cent|#162);@i', '@&(pound|#163);@i', '@&(copy|#169);@i', '@(\d+);@e');
$good = array ('', '', '"', '&', '<', '>', ' ', chr(161), chr(162), chr(169), 'chr(\1)');
return preg_replace($bad, $good, $value); return $value; }
$_POST = kill_tags_deep($_POST); $_GET = kill_tags_deep($_GET); |
alcaeus - Do 28.12.06 22:23
Reyx hat folgendes geschrieben: |
Ändere niemals den String, bevor du ihn in die DB einträgst (außer Escapen)! Nach dem Auslesen kannst du mit ihm machen, was du willst! |
Falsch. Es kommt auf die Verwendung drauf an. Wenn ich mich so einschraenken will, dass ich niemals HTML erlaube, dann kann ich Zeit sparen indem ich das htmlspecialchars() vor dem Eintragen in die DB erledige, anstatt es bei jedem Seitenaufruf zu erledigen. Ich mache bei jedem String folgendes:
Quelltext
1: 2:
| $str = (string) $str; $str = htmlspecialchars(trim($str)); |
Falls der String in die DB wandert, laeuft dann noch mysql_real_escape_string() drueber. Und wenn magic_quotes_gpc an ist, wird vor dem trim() noch ein stripslashes() ausgefuehrt.
XSS hat damit ueberhaupt keine Chance.
@GTA-Place: was genau soll die Funktion erledigen?
Greetz
alcaeus
GTA-Place - Do 28.12.06 22:37
Das ist ne Mischung aus Example 2 (
http://de2.php.net/stripslashes) und noch PregReplace dazu. Auf gut deutsch: Doppelt hält besser.
Arne K. - Fr 29.12.06 00:08
alcaeus hat folgendes geschrieben: |
Falsch. Es kommt auf die Verwendung drauf an. Wenn ich mich so einschraenken will, dass ich niemals HTML erlaube, dann kann ich Zeit sparen indem ich das htmlspecialchars() vor dem Eintragen in die DB erledige, anstatt es bei jedem Seitenaufruf zu erledigen. |
Und du kannst mit gewissheit sagen, dass du niemals deinen Parser ändern wirst? Dass du niemals Technologien anwenden wirst, die vielleicht ein Umdenken nötig machen? Und auch, dass du niemals deine eigene Meinung ändern wirst?
Für derlei Performanceprobleme sind Cacher übrigens geradezu prädestiniert ;)
freak4fun - Fr 29.12.06 13:07
Und wie macht man das mysql_real_escape_string(); bei der Ausgabe wieder rückgängig? :gruebel:
MfG
freak
Marco D. - Fr 29.12.06 13:09
freak4fun hat folgendes geschrieben: |
Und wie macht man das mysql_real_escape_string(); bei der Ausgabe wieder rückgängig? :gruebel: |
Würde mich auch mal interessieren...
wulfskin - Fr 29.12.06 13:57
Übrigens, auf PHP.net gibt es noch einen interessanten Kommentar dazu:
Zitat: |
Note that this function will NOT escape _ (underscore) and % (percent) signs, which have special meanings in LIKE clauses.
As far as I know there is no function to do this, so you have to escape them yourself by adding a backslash in front of them. |
Das würde ich mal lieber _nicht_ vergessen!
Zum Auslesen: Ich denke da ist keine Umwandlung mehr erforderlich, er wird "unescaped" ausgegeben.
Marco D. - Fr 29.12.06 14:08
wulfskin hat folgendes geschrieben: |
Übrigens, auf PHP.net gibt es noch einen interessanten Kommentar dazu: Zitat: | Note that this function will NOT escape _ (underscore) and % (percent) signs, which have special meanings in LIKE clauses.
As far as I know there is no function to do this, so you have to escape them yourself by adding a backslash in front of them. | Das würde ich mal lieber _nicht_ vergessen!
Zum Auslesen: Ich denke da ist keine Umwandlung mehr erforderlich, er wird "unescaped" ausgegeben. |
Danke für den Hinweis!
Marco D. - Fr 29.12.06 14:16
Habe das jetzt so:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| //'entschärft' einen String für das Eintragen in die DB function DefuseString($string) { $string = mysql_real_escape_string($string);
//setzt ein Backslash vor _ (underscore= und % (percent) $string = str_replace('_','/_',$string); $string = str_replace('%','/%',$string);
$string = htmlspecialchars($string); return $string; } |
alcaeus - Fr 29.12.06 17:08
Quelltext
1: 2: 3:
| //setzt ein Backslash vor _ (underscore= und % (percent) $string = str_replace('_','/_',$string); $string = str_replace('%','/%',$string); |
Backslash, nicht Slash:
Quelltext
1: 2: 3:
| //setzt ein Backslash vor _ (underscore= und % (percent) $string = str_replace('_','\_',$string); $string = str_replace('%','\%',$string); |
Ausserdem: lass es weg. Diese Zeichen haben bei einem INSERT oder UPDATE oder auch SELECT ohne LIKE keine besondere Bedeutung und muessen nicht escaped werden. Nur bei einer SELECT-Abfrage mit LIKE-Klausel musst du sie escapen, da % und _ in dem Fall als Wildcards gelten. _ matcht ein einzelnes Zeichen, % einen beliebigen String (also wie ? und * unter Windows). Ich wuerde die Funktion so machen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31:
| /* * Bereitet einen String zum Eintragen in die DB vor * @param string $string Der String zum Escapen * @param bool $multibyte True wenn multibyte-Zeichen (Ӓ) auch akzeptiert werden sollen * @param bool $like Wenn True, werden auch _ und % escaped * @return string Der fertige String */ function escape_db_string($string, $like = False) { // Siehe Kommentar [1] if (get_magic_quotes_gpc()) { $string = stripslashes($string); } // Siehe Kommentar [2] $string = htmlspecialchars(trim(str_replace(array("\r\n", "\r"), array("\n", "\n"), $string))); // Siehe Kommentar [3] // Multibyte-Zeichen? if ($multibyte && strpos($result, '&#') !== False) { $string = preg_replace('#&(\#[0-9]+;)#', '&\1', $string); } // Siehe Kommentar [4] if ($like) { //setzt einen Backslash vor _ (underscore= und % (percent) $string = str_replace(array('_', '%'), array('\_', '\%'), $string); }
return $string; } |
Hier die Kommentare:
1. Wenn magic quotes aktiviert sind, wurde vor dem Uebergeben der Daten an das Script bereits ein addslashes() ausgefuehrt. In dem Fall musst du es rueckgaengig machen, um den String nicht doppelt zu escapen.
2. Was macht das Monster? Erstmal setzt es konsequent \n fuer Zeilenumbrueche durch; verschiedene Betriebssysteme haben da unterschiedliche Auffassungen. Anschliessend ein trim() um Speicherplatz zu sparen, und ganz am Ende noch ein htmlspecialchars().
3. Was sind Multibyte-Zeichen? Dinge wie z.B. Ӓ. Diese koennen als Zeichen dargestelt werden, werden durch das htmlspecialchars() aber zersemmelt. Wenn der Parameter also auf true ist, und solche Zeichen vorkommen, wandeln wir sie wieder zurueck.
4. Die Sache mit dem LIKE habe ich von einem Parameter abhaengig gemacht. Wie erwaehnt muss das Escapen von _ und % nicht immer geschehen; mit dem Parameter kannst du das jetzt steuern. Wenn du denkst, dass du das nicht brauchen wirst, kannst du den Teil inkl. Parameter gleich rauswerfen :)
Greetz
alcaeus
Marco D. - Fr 29.12.06 17:14
Danke.
delfiphan - Fr 29.12.06 20:16
Ich stimme Reyx voll zu: Daten soll man so roh wie möglich speichern. Was machst du, wenn du auf eine andere HTML-Version umsteigen willst oder deine Daten in einem Delphi-Programm darstellen willst, oder du die Daten bearbeiten willst?
Wenn du nur Text zulässt und kein HTML, dann kannst du den String mit mysql_real_escape_string escapen und die dann so in deine mysql-Query einfügen. Was du eventuell vorher noch tun kannst ist eine Ersetzung von "\r\n" zu "\n" und anschliessend "\r" zu "\n".
@Multibyte-Character: Definiere deine HTML-Seite als UTF-8 und verwende diesen Charset. Du gehst damit vielen Charset-Albträumen aus dem Weg. Wenn deine Seite UTF-8 ist, dann achte darauf, dass die Felder der SQL-Tabelle ebenfalls UTF-8 sind und du die Daten und SQL-Connection auch als UTF-8 definierst ("set character set utf8", "set character_set_connection=utf8"). Beim Darstellen als HTML kannst du dann den String aus der Datenbank mit htmlentities($str, ENT_COMPAT, 'UTF-8') "entschärfen". Was du noch tun kannst ist dann noch die Ersetzung "\n" zu "<br>" bzw. "<br/>".
@Like: Wenn du wegen dem "Like" alle Prozentzeichen im Text ersetzst hast du das Problem am falschen Ort gepackt. Du musst wenn schon deinen Suchstring korrekt escapen, doch aber nicht die Daten!
@stripslashes: Die Magicquotes wurden gegen einen häufigen Anfängerfehler geschaffen. Ich finde die Sache äusserst unsauber. Nicht jeder gepostete String landet automatisch auf einer Datenbank! Schalte die aus und verwende stattdessen mysql_real_escape_string!
Htmlentities sollte definitiv keine Performanceschwierigkeiten bringen. Wenn du Performanceprobleme hast gibt es dafür direktere Lösungen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!