Und die von Ihnen entwickelte Funktion würde am wenigsten helfen. PHP: \"Zitate\". Schreiben von MySQL-Abfragen, Schrägstrichen, Escape-Anführungszeichen, Suchen im Code

Anführungszeichenfolge (11)

Ich versuche herauszufinden, wie man Abfragen am besten schreibt. Ich verstehe auch, wie wichtig es ist, konsequent zu sein. Bisher habe ich wahllos einfache Anführungszeichen, doppelte Anführungszeichen und Backticks verwendet, ohne wirklich darüber nachzudenken.

$query = „INSERT INTO table (id, col1, col2) VALUES (NULL, val1, val2)“;

Bedenken Sie im obigen Beispiel außerdem, dass „table“, „col[n]“ und „val[n]“ Variablen sein können.

Was ist der Standard dafür? Was machst du?

Ich habe etwa 20 Minuten lang Antworten auf ähnliche Fragen gelesen, aber es scheint keine endgültige Antwort auf diese Frage zu geben.

Antworten

Angenommen, Sie verwenden eine Direct-Post-Variable in der MySQL-Abfrage, dann verwenden Sie sie wie folgt:

$query = "INSERT INTO `table` (`id`, `name`, `email`) VALUES (" ".$_POST["id"]." ", " ".$_POST["name"]." ", " ".$_POST["email"].." ")";

Dies ist die beste Vorgehensweise für die Verwendung von PHP-Variablen in MySQL.

Hauptsächlich in MySQL werden diese Arten von Bezeichnern in ` , " , " und ()-Abfragen verwendet.

    „ oder „ verwenden, um eine Zeichenfolge als Wert „01/26/2014 00:00:00“ oder „01/26/2014 00:00:00“ einzuschließen. Dieser Bezeichner wird nur für die String-Funktion „26.01.2014 00:00:00“ verwendet, z. B. now() oder sum ,max .

    ` Verwenden Sie diese Option, um eine Tabelle oder Tabellentabelle einzuschließen, z. B. wählen Sie „Spaltenname“ aus „Tabellenname“ aus, wobei id = „2“ ist.

    () werden nur verwendet, um Teile einer Abfrage einfach einzuschließen, zum Beispiel select columns_name from table_name where (id = „2“ and gender = „male“) oder name = „rakesh“.

Abgesehen von all den (gut erklärten) Antworten wurden unten keine aufgeführt und ich komme oft zu dieser Frage-und-Antwort-Runde.

Kurzgesagt; MySQL denkt, dass Sie Mathe machen wollen in Ihrer eigenen Tabelle/Spalte und interpretieren Sie Bindestriche wie „email“ als e mail .

Ablehnung der Verantwortung. Deshalb dachte ich, ich würde dies als „zu Ihrer Information“-Antwort für diejenigen hinzufügen, die völlig neu in der Arbeit mit Datenbanken sind und die bereits beschriebenen Fachbegriffe möglicherweise nicht verstehen.

(Oben gibt es gute Antworten bezüglich der SQL-Natur Ihrer Frage, aber dies kann auch relevant sein, wenn Sie PHP-Neuling sind.)

Es kann wichtig sein zu beachten, dass PHP einfache und doppelte Anführungszeichen unterschiedlich behandelt ...

Zeichenfolgen in einfachen Anführungszeichen sind „Literale“ und eine ganze Reihe von WYSIWYG-Zeichenfolgen. In doppelte Anführungszeichen gesetzte Zeichenfolgen werden von PHP als mögliche Variablenersetzung interpretiert (Rückverweise in PHP sind keine genauen Zeichenfolgen, sie führen den Befehl in der Shell aus und geben das Ergebnis zurück).

$foo = "bar"; echo „da ist ein $foo“; // Es gibt ein $foo echo "there is a $foo"; // Es gibt einen Balken echo `ls -l`; // ... eine Verzeichnisliste

Wenn die Spaltentabellen und -werte Variablen sind, gibt es zwei Möglichkeiten:

Mit doppelten Anführungszeichen „“ lautet die vollständige Abfrage:

$query = „INSERT INTO $table_name (id, $col1, $col2) VALUES (NULL, „$val1“, „$val2“)“;

$query = „INSERT INTO „.$table_name.“ (id, „.$col1.“, „.$col2.“) VALUES (NULL, „“.$val1.“, „“.$val2.““ ) ";

Mit einfachen Anführungszeichen „“ :

$query = „INSERT INTO „.$table_name.“ (id, „.$col1.“, „.$col2.“) VALUES (NULL, „.$val1.“, „.$val2.“)“;

Verwenden Sie Backticks „, wenn der Spalten-/Wertname einem reservierten MySQL-Schlüsselwort ähnelt.

Notiz. Wenn Sie einen Spaltennamen mit einem Tabellennamen angeben, verwenden Sie Backticks wie diese:

`table_name` . „Spaltenname“.<- Примечание: исключить. из задних клещей.

Backticks sollten für Tabellen- und Spaltenbezeichner verwendet werden, werden jedoch nur benötigt, wenn der Bezeichner ein von MySQL reserviertes Schlüsselwort ist oder wenn der Bezeichner Leerzeichen oder Zeichen außerhalb des begrenzten Satzes enthält (siehe unten). Es wird häufig empfohlen, die Verwendung reservierter Schlüsselwörter als Spalten- oder Tabellenbezeichner nach Möglichkeit zu vermeiden, um das Anführungszeichenproblem zu vermeiden.

Für Zeichenfolgenwerte sollten einfache Anführungszeichen verwendet werden, beispielsweise in der VALUES()-Liste. Doppelte Anführungszeichen werden von MySQL auch für Zeichenfolgenwerte unterstützt, einfache Anführungszeichen werden jedoch von anderen RDBMS häufiger akzeptiert, daher ist es eine gute Idee, einfache Anführungszeichen anstelle von doppelten Anführungszeichen zu verwenden.

MySQL erwartet außerdem, dass die Literalwerte DATE und DATETIME als Zeichenfolgen in einfache Anführungszeichen gesetzt werden, z. B. „2001-01-01 00:00:00“. Weitere Informationen finden Sie in der Literaturdokumentation zu Datum und Uhrzeit, insbesondere zu Alternativen zur Verwendung des Bindestrichs – als Segmenttrennzeichen in Datumszeichenfolgen.

In Ihrem Beispiel würde ich also den PHP-String doppelt umwandeln und einfache Anführungszeichen für die Werte „val1“, „val2“ verwenden. NULL ist ein MySQL-Schlüsselwort und kein Wert und wird daher nicht verwendet.

Keine dieser Tabellen- oder Spaltenbezeichner sind reservierte Wörter oder verwenden Zeichen, die in Anführungszeichen gesetzt werden müssen, aber ich habe sie trotzdem rückwärts in Anführungszeichen gesetzt (mehr dazu später ...).

RDBMS-bezogene Funktionen (z. B. NOW() in MySQL) sollten nicht in Anführungszeichen gesetzt werden, obwohl ihre Argumente denselben Regeln oder Anführungszeichenregeln unterliegen, die bereits erwähnt wurden.

Backtick(`) Tabelle und Spalte ┬──── ┬──┬───────┐ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ $query = " INSERT INTO `table` (`id`, `col1`, `col2`, `date`, `updated`) VALUES (NULL, „val1“, „val2“, „2001-01-01“, NOW())"; Schlüsselwort ohne Anführungszeichen ─────┴┴┴┘ │ │ │ │ │ │ │││││ Zeichenfolgen in einfachen Anführungszeichen (") ───────────┴─ ───┴── ┴────┘ │ │ │││││ Einfaches Anführungszeichen (") DATUM ──────────────────────── ───┴── Funktion ohne Anführungszeichen ───────────────────────── ───────── ───── ──┴┴┴┴┘

Variable Interpolation

Anführungszeichenmuster für Variablen ändern sich nicht. Wenn Sie jedoch beabsichtigen, Variablen direkt in einem String zu interpolieren, muss dieser in PHP in doppelte Anführungszeichen gesetzt werden. Stellen Sie einfach sicher, dass Sie Variablen für die Verwendung in SQL richtig maskieren. (Es wird empfohlen, stattdessen eine API zu verwenden, die vorbereitete Anweisungen unterstützt, um sich gegen SQL-Injection zu schützen.)

// Dasselbe gilt für einige Variablenersetzungen // Hier wird ein Variablentabellenname $table in Backtick-Anführungszeichen gesetzt und Variablen // in der VALUES-Liste werden in einfache Anführungszeichen gesetzt $query = "INSERT INTO „$table“.(`id`, `col1`, `col2`, `date`) VALUES (NULL, „$val1“, „$val2“, „$date“)";

Vorbereitete Stellungnahmen

Wenn Sie mit vorbereiteten Kontoauszügen arbeiten, lesen Sie in der Dokumentation nach, ob die Kontoauszüge einbezogen werden sollten. Zu den beliebtesten APIs, die in PHP, PDO und MySQLi verfügbar sind, gehören nicht autorisiert Platzhalter, wie die meisten vorbereiteten Anweisungs-APIs in anderen Sprachen:

// PDO-Beispiel mit benannten Parametern, ohne Anführungszeichen $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (:id, :col1, :col2, :date)" ; // MySQLi-Beispiel mit ? Parameter, ohne Anführungszeichen $query = "INSERT INTO `table` (`id`, `col1`, `col2`, `date`) VALUES (?, ?, ?, ?)";

Symbole, die in Bezeichnern eine Rückreferenz zurückgeben:

Zum Beispiel:

Dasselbe kann für Tabellennamen und Feldnamen durchgeführt werden. Das ist sehr gute Angewohnheit wenn Sie Ihre Datenbank-ID mit hinteren Fenstern verknüpfen.

Sehen Sie sich diese Antwort an, um mehr über umgekehrte Schlussfolgerungen zu erfahren.

Nun zu den doppelten und einfachen Anführungszeichen (Michael hat dies bereits erwähnt).

Um den Wert zu definieren, müssen Sie jedoch einfache oder doppelte Anführungszeichen verwenden. Sehen wir uns ein weiteres Beispiel an.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, title1);

Hier habe ich absichtlich vergessen, Titel1 in Anführungszeichen zu setzen. Der Server akzeptiert nun title1 als Spaltennamen (d. h. Bezeichner). Um anzuzeigen, dass es sich hierbei um einen Wert handelt, müssen Sie doppelte oder einfache Anführungszeichen verwenden.

INSERT INTO `tablename` (`id, `title`) VALUES (NULL, „title1“);

In Kombination mit PHP machen doppelte und einfache Anführungszeichen das Schreiben von Abfragen jetzt viel einfacher. Schauen wir uns die geänderte Version der Abfrage in Ihrer Frage an.

$query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, „$val1“, „$val2““);

Mithilfe doppelter Anführungszeichen in PHP sorgen Sie nun dafür, dass die Variablen $val1 und $val2 ihre Werte verwenden und so eine gültige Abfrage erstellen. wie

$val1 = „mein Wert 1“; $val2 = „mein Wert 2“; $query = "INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, „$val1“, „$val2““);

INSERT INTO `table` (`id`, `col1`, `col2`) VALUES (NULL, „mein Wert 1“, „mein Wert 2“)

Hier gab es viele hilfreiche Antworten, die im Allgemeinen in zwei Punkten gipfelten.

  1. BACKTICKS (`) werden um Bezeichnernamen herum verwendet.
  2. EINZELNE ANführungszeichen (") werden um Werte herum verwendet.

Und wie @MichaelBerkowski sagte

Backticks sollten für Tabellen- und Spaltenbezeichner verwendet werden, werden jedoch nur benötigt, wenn der Bezeichner ein von MySQL reserviertes Schlüsselwort ist oder wenn der Bezeichner Leerzeichen oder Zeichen außerhalb des begrenzten Satzes enthält (siehe unten). Es wird häufig empfohlen, die Verwendung reservierter Schlüsselwörter als Spalten- oder Tabellenbezeichner nach Möglichkeit zu vermeiden, um das Anführungszeichenproblem zu vermeiden.

Es gibt einen Fall, in dem die Kennung nicht vorhanden sein kann reserviertes Schlüsselwort oder enthalten Leerzeichen oder Zeichen außerhalb des begrenzten Satzes erfordern aber auf jeden Fall Backlinks um sie herum.

123E10 ist ein gültiger Bezeichnername, aber auch ein gültiges INTEGER-Literal.

[Ohne näher darauf einzugehen, wie Sie einen solchen ID-Namen erhalten würden] Nehmen wir an, ich möchte eine temporäre Tabelle mit dem Namen 123456e6 erstellen.

Kein FEHLER bei Backticks.

DB > temporäre Tabelle „123456e6“ erstellen (`id` char (8)); Abfrage OK, 0 Zeilen betroffen (0,03 Sek.)

FEHLER, wenn Sie keine Rückrufe verwenden.

DB > temporäre Tabelle 123451e6 erstellen (`id` char (8)); FEHLER 1064 (42000): Sie haben einen Fehler in Ihrer SQL-Syntax; Überprüfen Sie im Handbuch Ihrer MariaDB-Serverversion die richtige Syntax für die Verwendung in der Nähe von „123451e6 (`id` char (8))“ in Zeile 1

Allerdings ist 123451a6 ein guter ID-Name (ohne Backticks).

DB > temporäre Tabelle 123451a6 erstellen (`id` char (8)); Abfrage OK, 0 Zeilen betroffen (0,03 Sek.)

Dies liegt ausschließlich daran, dass 1234156e6 auch eine Exponentialzahl ist.

Für Zeichenfolgenwerte sollten einfache Anführungszeichen verwendet werden, beispielsweise in der VALUES()-Liste.

Backticks werden normalerweise zur Angabe einer Kennung verwendet und können aufgrund der gelegentlichen Verwendung reservierter Schlüsselwörter auch sicher sein.

In Kombination mit PHP und MySQL vereinfachen doppelte und einfache Anführungszeichen die Zeit für das Schreiben von Abfragen erheblich.

In MySQL gibt es zwei Arten von Anführungszeichen:

  1. " um String-Literale einzuschließen
  2. ` um Bezeichner wie Tabellen- und Spaltennamen einzuschließen

Und dann ist da noch „Das ist ein Sonderfall. Es kann dafür verwendet werden.“ eins der oben genannten Ziele gleichzeitig, abhängig vom sql_mode des Servers:

  1. Default„character“ kann zum Verschachteln von String-Literalen verwendet werden.
  2. Im ANSI_QUOTES-Modus kann das Symbol verwendet werden, um Bezeichner ANSI_QUOTES einzuschließen

Die folgende Abfrage führt je nach SQL-Modus zu unterschiedlichen Ergebnissen (oder Fehlern):

SELECT „column“ FROM table WHERE foo = „bar“

ANSI_QUOTES deaktiviert

Die Abfrage wählt das Zeichenfolgenliteral „column“ aus, wobei Spalte foo gleich der Zeichenfolge „bar“ ist.

ANSI_QUOTES aktiviert

Die Abfrage wählt die Spalte „Spalte“ aus, wobei „Spalte foo“ gleich „Spalte“ ist

Wann zu verwenden

  • Ich empfehle Ihnen, die Verwendung von „ zu vermeiden, damit Ihr Code nicht von SQL-Modi abhängt
  • Geben Sie immer Bezeichner an, da dies eine bewährte Vorgehensweise ist (eine ganze Reihe von Fragen zu SO diskutieren dies).

Es gibt einen deutlichen Unterschied zwischen der Verwendung von „“ und „“.

Wenn „ “ durchgehend verwendet wird, gibt es keine „Transformation oder Übersetzung“. Es wird so gedruckt, wie es ist.

Mit „ “ wird alles, was es umgibt, in seinen Wert „übersetzt oder transformiert“.

Was ich mit Übersetzung/Konvertierung meine, ist Folgendes: Alles, was in einfachen Anführungszeichen steht, wird nicht in seine Werte „übersetzt“. Sie werden akzeptiert, da sie in Anführungszeichen stehen. Beispiel: a=23 , dann generiert echo „$a“ $a in der Standardausgabe. Während echo „$a“ in der Standardausgabe 23 erzeugt.

(PHP 4 >= 4.3.0, PHP 5)

mysql_real_escape_string — Escapezeichen für Sonderzeichen in einer Zeichenfolge zur Verwendung in einer SQL-Anweisung

Beschreibung

mysql_real_escape_string (Zeichenfolge $unescaped_string [, Ressource $link_identifier = NULL]): Zeichenfolge

Escaped-Sonderzeichen im unescaped_string unter Berücksichtigung des aktuellen Zeichensatzes der Verbindung, damit es sicher in a platziert werden kann mysql_query(). Sollen Binärdaten eingefügt werden, muss diese Funktion verwendet werden.

mysql_real_escape_string() ruft die Bibliotheksfunktion mysql_real_escape_string von MySQL auf, die den folgenden Zeichen Backslashes voranstellt: \x00, \N, \R, \ , " , " Und \x1a.

Diese Funktion muss immer (mit wenigen Ausnahmen) verwendet werden, um Daten sicher zu machen, bevor eine Abfrage an MySQL gesendet wird.

Vorsicht

Sicherheit: der Standardzeichensatz

Der Zeichensatz muss entweder auf Serverebene oder mit der API-Funktion festgelegt werden mysql_set_charset() damit es wirkt mysql_real_escape_string() . Weitere Informationen finden Sie im Abschnitt „Konzepte“ zu Zeichensätzen.

Parameter

unescaped_string

Die Zeichenfolge, die maskiert werden soll.

Link_identifier

Die MySQL-Verbindung. Wenn die Link-ID nicht angegeben ist, der letzte Link, der von geöffnet wurde mysql_connect() wird angenommen. Wenn kein solcher Link gefunden wird, wird versucht, einen solchen zu erstellen mysql_connect() wurde ohne Argumente angerufen. Wenn keine Verbindung gefunden oder hergestellt wird, wird ein E_WARNUNG Es wird ein Pegelfehler generiert.

Rückgabewerte

Gibt die maskierte Zeichenfolge zurück, oder FALSCH auf Fehler.

Fehler/Ausnahmen

Das Ausführen dieser Funktion ohne vorhandene MySQL-Verbindung führt ebenfalls zu einer Ausgabe E_WARNUNG Level PHP-Fehler. Führen Sie diese Funktion nur aus, wenn eine gültige MySQL-Verbindung vorhanden ist.

Beispiele

Beispiel Nr. 1 Einfach mysql_real_escape_string() Beispiel

//Verbinden
$link = mysql_connect("mysql_host" , "mysql_user" , "mysql_password" )
ODER die(mysql_error());

//Abfrage
$query = sprintf ( „SELECT * FROM users WHERE user="%s" AND password="%s"",
mysql_real_escape_string($user),
mysql_real_escape_string($password));
?>

Beispiel #2 mysql_real_escape_string() erfordert ein Anschlussbeispiel

Dieses Beispiel zeigt, was passiert, wenn beim Aufruf dieser Funktion keine MySQL-Verbindung vorhanden ist.

Das obige Beispiel gibt etwas Ähnliches aus:

Warnung: mysql_real_escape_string(): Keine solche Datei oder kein solches Verzeichnis in /this/test/script.php in Zeile 5 Warnung: mysql_real_escape_string(): In /this/test/script.php in Zeile 5 konnte keine Verbindung zum Server hergestellt werden bool(false) string(41) „SELECT * FROM Actors WHERE last_name = „““

Beispiel #3 Ein Beispiel für einen SQL-Injection-Angriff

// Wir haben $_POST["password"] nicht überprüft, es könnte alles sein, was der Benutzer wollte! Zum Beispiel:
$_POST [ "Benutzername" ] = "aidan" ;
$_POST [ "password" ] = "" OR ""="" ;

// Datenbank abfragen, um zu prüfen, ob es passende Benutzer gibt
$query = ( $_POST [ "Benutzername" ]) " UND Passwort=" ( $_POST [ "Passwort" ]) "" ;
mysql_query($query);

// Dies bedeutet, dass die an MySQL gesendete Abfrage wie folgt aussehen würde:
echo $query ;
?>

Die an MySQL gesendete Abfrage:

Dies würde es jedem ermöglichen, sich ohne gültiges Passwort anzumelden.

Anmerkungen

Vor der Verwendung ist eine MySQL-Verbindung erforderlich mysql_real_escape_string() andernfalls ein Levelfehler E_WARNUNG erzeugt wird, und FALSCH ist zurück gekommen. Wenn link_identifier nicht definiert ist, wird die letzte MySQL-Verbindung verwendet.

Notiz: mysql_real_escape_string() entkommt nicht % Und _ . Dies sind Platzhalter in MySQL, wenn sie mit kombiniert werden WIE, GEWÄHREN, oder WIDERRUFEN.

Vor 8 Jahren

Nur eine kleine Funktion, die den ursprünglichen mysql_real_escape_string nachahmt, aber keine aktive MySQL-Verbindung benötigt. Könnte als statische Funktion in einer Datenbankklasse implementiert werden. Ich hoffe, es hilft jemandem.

Funktion mysql_escape_mimic ($inp) (
if(is_array($inp))
return array_map (__METHOD__, $inp);

If(!empty($inp ) && is_string ($inp )) (
return str_replace (array("\\" , "\0" , "\n" , "\r" , """ , """ , "\x1a" ), array("\\\\" , "\ \0" , "\\n" , "\\r" , "\\"" , "\\"" , "\\Z" ), $inp );
}

Rückgabe $inp ;
}
?>

vor 13 Jahren

Beachten Sie, dass mysql_real_escape_string keine Backslashes an \x00, \n, \r und und \x1a voranstellt, wie in der Dokumentation erwähnt, sondern das Zeichen tatsächlich durch eine MySQL-akzeptable Darstellung für Abfragen ersetzt (z. B. wird \n durch „\“ ersetzt. n“-Wurf). (\, „, und „ werden wie dokumentiert mit Escapezeichen versehen) Dies ändert nichts daran, wie Sie diese Funktion verwenden sollten, aber ich denke, es ist gut zu wissen.

vor 6 Jahren

Keine Diskussion über das Escapen ist vollständig, ohne allen zu sagen, dass Sie grundsätzlich niemals externe Eingaben verwenden sollten, um interpretierten Code zu generieren. Dies gilt für SQL-Anweisungen oder alles, was Sie als „eval“-Funktion aufrufen würden.

Anstatt diese furchtbar kaputte Funktion zu verwenden, verwenden Sie stattdessen parametrische vorbereitete Anweisungen.

Ehrlich gesagt sollte die Verwendung von vom Benutzer bereitgestellten Daten zum Verfassen von SQL-Anweisungen als berufliche Fahrlässigkeit betrachtet werden und Sie sollten von Ihrem Arbeitgeber oder Kunden zur Verantwortung gezogen werden, wenn Sie keine parametrisch vorbereiteten Anweisungen verwenden.

Was bedeutet das?

Das bedeutet, anstatt eine SQL-Anweisung wie diese zu erstellen:

„INSERT INTO X (A) VALUES(".$_POST["a"].)"

Sie sollten die Funktion „prepare()“ von mysqli verwenden, um eine Anweisung auszuführen, die wie folgt aussieht:

„INSERT INTO X (A) VALUES(?)“

Hinweis: Dies bedeutet nicht, dass Sie niemals dynamische SQL-Anweisungen generieren sollten. Das bedeutet, dass Sie niemals vom Benutzer bereitgestellte Daten zum Generieren dieser Anweisungen verwenden sollten. Alle vom Benutzer bereitgestellten Daten sollten nach der Anweisung als Parameter an die Anweisung übergeben werden vorbereitet worden.

Wenn Sie beispielsweise ein kleines Framework aufbauen und eine Einfügung in eine Tabelle basierend auf dem Anforderungs-URI durchführen möchten, ist es in Ihrem besten Interesse, nicht den Wert $_SERVER["REQUEST_URI"] (oder einen anderen) zu verwenden Teil davon) und verketten Sie diesen direkt mit Ihrer Abfrage. Stattdessen sollten Sie den Teil des $_SERVER["REQUEST_URI"]-Werts auswerten, den Sie möchten, und ihn über eine Art Funktion oder ein assoziatives Array einem Nichtbenutzer zuordnen bereitgestellter Wert. Wenn die Zuordnung keinen Wert erzeugt, wissen Sie, dass mit den vom Benutzer bereitgestellten Daten etwas nicht stimmt.

Die Nichtbeachtung dieser Vorgaben war die Ursache für eine Reihe von SQL-Injection-Problemen im Ruby On Rails-Framework, obwohl es parametrische vorbereitete Anweisungen verwendet. So wurde GitHub einmal gehackt. Daher ist keine Sprache vor diesem Problem immun. Aus diesem Grund handelt es sich hierbei um eine allgemeine Best Practice und nicht um etwas PHP-spezifisches, und Sie sollten es WIRKLICH übernehmen.

Außerdem sollten Sie dennoch eine gewisse Validierung der von den Benutzern bereitgestellten Daten durchführen, selbst wenn Sie parametrische vorbereitete Anweisungen verwenden. Dies liegt daran, dass vom Benutzer bereitgestellte Daten häufig Teil eines generierten HTML-Codes werden und Sie sicherstellen möchten, dass die vom Benutzer bereitgestellten Daten keine Sicherheitsprobleme im Browser verursachen.

Vor 9 Jahren

Im Beispiel Nr. 2 zur SQL-Injection gibt es eine interessante Besonderheit: AND hat Vorrang vor OR, sodass die injizierte Abfrage tatsächlich als WHERE (user="aidan" AND password="") OR ""="" ausgeführt wird, also stattdessen Wenn ein Datenbankeintrag zurückgegeben wird, der einem beliebigen Benutzernamen entspricht (in diesem Fall „aidan“), werden tatsächlich ALLE Datenbankeinträge zurückgegeben. In keiner bestimmten Reihenfolge. Ein Angreifer kann sich also möglicherweise mit einem beliebigen Konto anmelden, jedoch nicht unbedingt mit einem beliebigen Kontrolle darüber, um welches Konto es sich handelt.

Natürlich könnte ein potenzieller Angreifer einfach seine Parameter ändern, um bestimmte Benutzer von Interesse anzusprechen:

//Z.B. Werte des Angreifers
$_POST [ "Benutzername" ] = "" ;
$_POST["password"] = „“ ODER user = „administrator“ UND „“ = „“;

// Fehlerhafte Abfrage
$query = „SELECT * FROM users WHERE user="$_POST [Benutzername] "AND Passwort=" $_POST [Passwort] "";

echo $query ;

// Die an MySQL gesendete Abfrage würde lauten:
// SELECT * FROM users WHERE user="" AND password="" OR user="administrator" AND ""="";
// was jedem Zugriff auf das Konto mit dem Namen „administrator“ ermöglichen würde

?>

vor 1 Jahr

@feedr
Ich habe seine Notiz wie folgt ausgearbeitet:
$string = "asda\0sd\x1aas\\\\\\\\dasd\"asdasd\na\"\"sdasdad";
$array1 = array("\\\\\\\\", "\0", "\n", "\r", """, """, "\x1a");
$array2 = array("\\\\\\\\\\\\\\\\\", "\\\0", "\\\n", "\\\r", "\\\ " ", "\\\"", "\\\Z");
echo($string);
echo(PHP_EOL);
for($i=0; $i if ($i==0)
$p = "/(?anders
$p = "/(?echo($i);
echo($p);
echo($array2[$i]);
$string = preg_replace($p, $array2[$i], $string);
echo("\t");
echo($string);
echo(PHP_EOL);
}
echo(PHP_EOL);
echo($string);

vor 2 Jahren

Um Sam bei Numb Safari zu zitieren

[ „Keine Diskussion über das Escapen ist vollständig, ohne allen zu sagen, dass Sie grundsätzlich niemals externe Eingaben verwenden sollten, um interpretierten Code zu generieren. Dies gilt für SQL-Anweisungen oder alles, wofür Sie irgendeine Art von „eval“-Funktion aufrufen würden.

Anstatt diese furchtbar kaputte Funktion zu verwenden, verwenden Sie stattdessen parametrische vorbereitete Anweisungen.

Ehrlich gesagt sollte die Verwendung von vom Benutzer bereitgestellten Daten zum Verfassen von SQL-Anweisungen als berufliche Fahrlässigkeit angesehen werden und Sie sollten von Ihrem Arbeitgeber oder Kunden zur Verantwortung gezogen werden, wenn Sie keine parametrisch vorbereiteten Anweisungen verwenden.

Sam hat recht........

Allerdings halte ich es nicht für sinnvoll, mit der Bereinigung aufzuhören und die Aufgabe einfach parametrisch vorbereiteten Anweisungen zu überlassen.

Ein bestimmter Entwickler, der in einer bestimmten Situation arbeitet, weiß immer mehr über gültige Eingaben (spezifisch für diesen Kontext).

Wenn Sie einen Benutzer auffordern, einen Wert einzugeben, haben Sie ihn bereits angegeben und wissen, dass alle derartigen Werte mit AB****** beginnen und die Zeichenfolge eine Länge von 7 oder 11 haben sollte, jedoch niemals eine andere Länge als Sie die Grundlage eines guten Vordesinfektionsmittels – unterschiedliche zulässige Längen einer Schnur können auf veraltete Daten hinweisen.

Ich möchte den Müll, den ein böswilliger Benutzer möglicherweise über ein Formular übermittelt hat, niemals einfach an die parametrisch vorbereiteten Anweisungen weitergeben. Ich möchte immer zuerst meine eigenen Plausibilitätsprüfungen durchführen, und in einigen Fällen kann es sein, dass diese auf der sicheren Seite sind Entscheiden Sie sich einfach dafür, den Datenbankvorgang vollständig abzubrechen.

Auf diese Weise wird meine Datenbank nicht durch unsichere, sicher gemachte Anweisungen verstopft – sie wird einfach nicht verstopft, was besser ist.

Sicherheit in Schichten – Bereinigung und Validierung sollten dennoch in jeder Situation in Betracht gezogen werden, BEVOR vorbereitete Anweisungen verwendet werden.

Darüber hinaus, soweit ich das offizielle Dokument lesen kann
==============================================

„Escape und SQL-Injection

Gebundene Variablen werden getrennt von der Abfrage an den Server gesendet und können diese daher nicht beeinträchtigen. Der Server verwendet diese Werte direkt zum Zeitpunkt der Ausführung, nachdem die Anweisungsvorlage analysiert wurde. Gebundene Parameter müssen nicht maskiert werden, da sie niemals direkt in die Abfragezeichenfolge eingesetzt werden.

Das deutet für mich darauf hin, dass Gefahren im Inneren durch alternative Handhabung und nicht durch Aufhebung vermieden werden.

Dies bedeutet, dass ein großes Projekt mit unvollständiger Konvertierung in vorbereitete Anweisungen, Legacy-Code in verschiedenen Teilen einer Organisation oder miteinander kommunizierenden Servern die schlechten Nachrichten von einem immunisierten Ort oder einer immunisierten Situation an einen Ort oder eine Situation weitergeben könnte, die nicht immun ist.

Solange die Desinfektion fachgerecht und ohne zusätzliche Risiken durchgeführt wird, würde ich persönlich bei bestimmten Ebenen der Desinfektion bleiben und dann die vorbereiteten Aussagen nennen.


Zunächst ein wenig darüber, warum diese Schrägstriche im Allgemeinen benötigt werden.
Wenn wir in einer Abfrage Daten ersetzen, müssen diese Daten zur Unterscheidung von SQL-Befehlen in Anführungszeichen gesetzt werden.
Zum Beispiel, wenn Sie schreiben
SELECT * FROM table WHERE name = Bill
Dann entscheidet die Datenbank, dass Bill der Name eines anderen Felds ist, findet es nicht und gibt einen Fehler aus. Daher müssen die ersetzten Daten (in diesem Fall der Name Bill) in Anführungszeichen gesetzt werden – dann betrachtet die Datenbank sie als Zeichenfolge, deren Wert dem Namensfeld zugewiesen werden muss:
SELECT * FROM table WHERE name = „Bill“
Anführungszeichen können jedoch auch in den Daten selbst vorkommen. Z.B,
SELECT * FROM table WHERE name = "D"Artagnan"
Hier entscheidet die Datenbank, dass es sich bei „D“ um Daten handelt und Artagnan ein Befehl ist, den sie nicht kennt, und gibt ebenfalls einen Fehler aus. Daher ist es notwendig, alle Daten zu verfolgen, um der Datenbank zu erklären, dass sich die darin enthaltenen Anführungszeichen (und einige andere Sonderzeichen) auf die Daten beziehen.
Als Ergebnis erhalten wir eine korrekte Anfrage, die keine Fehler verursacht:
SELECT * FROM table WHERE name = "D\"Artagnan"

So haben wir herausgefunden, dass beim Ersetzen von Zeichenfolgendaten in einer Abfrage zwei Regeln befolgt werden sollten:
- Alle eingefügten String-Daten müssen in Anführungszeichen eingeschlossen werden (einfache oder doppelte, aber einfache Anführungszeichen sind praktischer und werden häufiger verwendet).
- Sonderzeichen müssen mit Schrägstrichen maskiert werden.

Es ist besonders zu beachten: Hinzugefügte Schrägstriche gehen NICHT in die Datenbank ein. Sie werden nur in der Anfrage benötigt. Beim Auftreffen auf die Basis werden Hiebe verworfen. Dementsprechend besteht ein häufiger Fehler darin, beim Abrufen von Daten aus der Datenbank Stripslashes zu verwenden.

Alle oben genannten Punkte gelten für Zeichenfolgendaten und Datumsangaben. Zahlen können ohne Anführungszeichen oder Anführungszeichen eingefügt werden. Wenn Sie dies tun, dann NOTWENDIG! Erzwingen Sie, dass die Daten den gewünschten Typ erhalten, bevor Sie sie in die Abfrage einfügen, zum Beispiel:
$id = intval ($id);
Der Einfachheit (und Zuverlässigkeit) halber können Sie jedoch mit Zahlen wie mit Zeichenfolgen arbeiten (da MySQL sie immer noch in den gewünschten Typ konvertiert). Dementsprechend werden wir alle in die Anfrage eingegebenen Daten nachvollziehen und in Anführungszeichen setzen.

Außerdem gibt es noch eine weitere Regel – optional, die jedoch befolgt werden sollte, um Fehler zu vermeiden:
Die Namen von Feldern und Tabellen sollten in einfache Anführungszeichen gesetzt werden – „`“ (die Taste mit diesem Symbol befindet sich auf einer Standardtastatur links von der Taste „1“). Schließlich kann der Feldname mit mysql übereinstimmen Schlüsselwörter, aber wenn wir ein Anführungszeichen verwenden, erkennt MySQL, dass alles korrekt ist:
SELECT * FROM `table` WHERE `date` = "2006-04-04"
Sie sollten zwischen diesen Anführungszeichen unterscheiden und sie nicht miteinander verwechseln. Sie sollten auch bedenken, dass Backticks nicht durch Schrägstriche maskiert werden.

Wir haben also gelernt, wie man Daten korrekt in eine Anfrage einsetzt.
ABER! Die dynamische Abfragekonstruktion ist nicht auf die Datenersetzung beschränkt. Oft müssen wir SQL-Befehle und Feldnamen in einer Abfrage ersetzen. Und hier kommen wir zum Thema Sicherheit:

SQL-Injection ist eine Hackerangriffsmethode, bei der die an ein Skript übertragenen Daten so verändert werden, dass die in diesem Skript generierte Abfrage beginnt, etwas völlig anderes auszuführen, als sie beabsichtigt war.
Die Regeln zum Schutz vor solchen Angriffen lassen sich in zwei Punkte unterteilen:
1. Mit Daten arbeiten.
2. Arbeiten mit Abfragesteuerelementen.

Den ersten Punkt haben wir oben ausführlich besprochen. Man kann sagen, dass es sich tatsächlich nicht um eine Verteidigung handelt. Die Einhaltung der Regeln zum Hinzufügen von Daten zu einer Abfrage wird in erster Linie durch die Anforderungen von SQL SYNTAX bestimmt. Und als Nebeneffekt haben wir auch einen Schutz vor Hacking.

Der zweite Punkt ist viel schwieriger, da es für Daten keine allgemeingültige Regel gibt – ein Backtick schützt den Feldnamen nicht vor der Änderung durch einen Hacker. Es ist nicht möglich, Anführungszeichen zum Schutz von Tabellennamen, SQL-Anweisungen, LIMIT-Befehlsparametern und anderen Anweisungen zu verwenden.
Daher gilt beim Ersetzen von Steuerelementen in einer Abfrage folgende Grundregel:
Wenn Sie SQL-Anweisungen oder Namen von Feldern, Datenbanken oder Tabellen dynamisch in eine Abfrage einfügen müssen, sollten Sie diese unter keinen Umständen direkt in die Abfrage einfügen.
Alle Optionen für solche Ergänzungen müssen VORAUS in Ihr Skript geschrieben und basierend auf den Benutzereingaben ausgewählt werden.
Wenn Sie beispielsweise einen Feldnamen an den Operator „Order by“ übergeben müssen, sollten Sie ihn unter keinen Umständen direkt ersetzen. Wir müssen es zuerst überprüfen. Erstellen Sie beispielsweise ein Array mit gültigen Werten und ersetzen Sie es nur dann in der Anfrage, wenn der übergebene Parameter in diesem Array vorhanden ist:
$orders =array("name" , "price" , "qty" );
$key = array_search($_GET["sort"], $orders));
$orderby = $orders [ $key ];
$query = „SELECT * FROM `table` ORDER BY$orderby ";

Wir durchsuchen das Array der vorab beschriebenen Optionen nach dem vom Benutzer eingegebenen Wort und wählen, wenn wir es finden, das entsprechende Element des Arrays aus. Wenn keine Übereinstimmung gefunden wird, wird das erste Element des Arrays ausgewählt.
Somit wird in der Anfrage nicht das ersetzt, was der Benutzer eingegeben hat, sondern das, was in unserem Skript geschrieben wurde.
In allen anderen Fällen ist das Gleiche zu tun.
Wenn beispielsweise die WHERE-Klausel dynamisch generiert wird:
if (!empty($_GET [ "price" ])) $where .= "price="" . mysql_real_escape_string ($_GET [ "price" ]). """ ;
$query = "SELECT * FROM `table` WHERE $where " ;

Ich kann mir kaum vorstellen, dass ein Tabellenname dynamisch in eine Abfrage eingefügt werden kann. Wenn dies jedoch geschieht, muss der Name auch nur aus einem im Skript vordefinierten Satz eingefügt werden.
Die Parameter des LIMIT-Operators sollten mithilfe arithmetischer Operationen oder der Funktion intval() auf einen ganzzahligen Typ gezwungen werden.
Denken Sie nicht, dass die hier aufgeführten Beispiele alle Optionen für die dynamische Abfrageerstellung ausschöpfen. Sie müssen lediglich das Prinzip verstehen und es in allen solchen Fällen anwenden.

Aufgrund der Art meiner Arbeit muss ich Sicherheitsüberprüfungen des Quellcodes von Webanwendungen durchführen.
Viele Webanwendungen und viel Code ...

Es ist kein Geheimnis, dass SQL-Injection-Schwachstellen die häufigste Schwachstelle bei serverseitigen Webanwendungen sind. Es gibt Plattformen und Frameworks, bei denen solche Dinge fast vollständig ausgeschlossen sind, zum Beispiel ORM und so weiter. Statistiken belegen jedoch immer wieder, dass Webanwendungen mit einfachen verketteten SQL-Abfragen im Internet absolut vorherrschen. Darüber hinaus gibt es Fälle, in denen ORM vorhanden ist Allgemein anwendbar Dies kann beispielsweise nicht der Fall sein, wenn nicht nur die Parameter von Ausdrücken, sondern auch die Abfragelogik selbst auf der Operatorebene von Benutzerdaten abhängen muss.

Also, fangen wir an.

Nutzloser Charakter, der entkommt
Kommt in 83 % der PHP-Webanwendungen vor, die anfällig für SQL-Injections sind
Verwendung der Escape-Funktion für Zeichen wie
mysql_escape_string
mysql_real_escape_string
fügt Schrägstriche hinzu
ohne Anführungszeichen. Am häufigsten manifestiert es sich in numerischen Parametern (alle Arten von *_id).
Beispiel
$sql = "Benutzer aus Benutzerliste auswählen WHERE userid=".mysql_real_escape_string($_GET["uid"]);

Es scheint ein sicherer Code zu sein, aber nur an der Oberfläche. Das in meiner Praxis am häufigsten vorkommende Muster von SQL-Injections in PHP hat sich hier eingeschlichen. Um diese Schwachstelle anzugreifen, muss ein Angreifer lediglich die Verwendung der Zeichen „ “ \x00 \r \n \x1a im Angriffsvektor vermeiden.
Zum Beispiel:
/index.php?uid=-777 UNION SELECT Passwort AUS Benutzerliste

Suche im Code
Kompliziert durch die Semantik der Sprache. Für eine einfache Suche können Sie egrep verwenden:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]"

Die Logik des Suchausdrucks ist wie folgt: Finden Sie alle Zeilen, in denen links von den Filterfunktionen keine Anführungszeichenfolge ("", "", "", "") vorhanden ist. Die Methode ist natürlich weit von 100 % entfernt, aber es ist unmöglich, einen regulären Ausdruck für die Durchführung einer semantischen Analyse zu benötigen.
Um die Anzeige von Informationen zu erleichtern, können Sie die Funktion in der Konsole farblich hervorheben:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\""]["\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|addslashes)"

Um sich vor dieser Wildcard-Schwachstelle zu schützen, verwenden Sie am besten die Typumwandlung.
Dies funktioniert immer schneller und zuverlässiger als alle Arten von Filtern und Sieben.
Für das obige Beispiel könnte der Patch so aussehen:
$sql = "Benutzer aus Benutzerliste auswählen WHERE userid=".intval($_GET["uid"]);

Damit ist der kurze Aufsatz abgeschlossen. Ich fordere alle Webentwickler auf, ihre Quellen auf solche Designs zu überprüfen. Noch besser: Erweitern Sie das angegebene Suchskript für Personen.

Im Grunde habe ich mich also eingehend mit den Bereichen MySQL und PHP befasst ... insbesondere mit den Sicherheitsmaßnahmen, die ich beim Umgang mit der Datenbank und Formulareingaben ergreifen sollte. Folgendes habe ich bisher als sehr empfehlenswert empfunden:

  1. Vorbereitete Stellungnahmen
  2. Verwendung von _real_escape_string()
  3. Verwenden Sie KEINE magischen Anführungszeichen, da dies die Datenbanken verwirrt und Ihnen am Ende Dinge wie „Sie haben es nicht genannt...“ anzeigt.

Das ist alles großartig und ich behalte es im Auge. Allerdings habe ich mich gefragt, ob ich Zeichen wie Dollarzeichen [$], Prozentzeichen [%] und vielleicht auch andere maskieren sollte. Könnte die Abfrage das Dollarzeichen vielleicht als PHP-Variable interpretiert haben? Was ist mit der LIKE-Syntax, von der ich gehört habe, dass sie das %-Symbol oder sogar einen Platzhalter verwendet? Vorbereitete Abrechnungen sollten technisch gesehen all dies regeln, aber ich wollte nur auf der sicheren Seite sein und sicherstellen, dass ich alles richtig abgedeckt habe. In Fällen, in denen ich vergesse, vorbereitete Aussagen zu verwenden oder sie einfach vernachlässige, hoffte ich, dass diese zweite Verteidigungslinie mir sagen könnte, dass ich das Schwindelgefühl loswerden könnte.

Folgendes verwende ich derzeit zum Entkommen:

Funktion escape($connection, $data)( $new_data = trim($data); $new_data = i_real_escape_string($connection, $new_data); $new_data = addcslashes($new_data, "%_$"); $new_data = htmlspecialchars ($new_data, ENT_NOQUOTES); return $new_data; )

Ist das also richtig? Mache ich etwas furchtbar falsch? Bitte beachten Sie, dass ich bei der Rückgabe der Datenbankdaten die Backslashes vor den Zeichen $, % und _ entfernen muss.

Mache ich etwas furchtbar falsch?

Zunächst zu Ihrer Recherche.

Vorbereitete Stellungnahmen – der Einzige Wunderbar, was du gefunden hast.

Obwohl die Verwendung von mysqli_real_escape_string (vorausgesetzt, Sie verwenden vorbereitete Anweisungen) sinnvoll wäre nutzlos und schädlich(Erstellen eines Ergebnisses, das Sie selbst notiert haben: „Sie haben isn\t angerufen ...“).

Und Magic Quotes sind längst aus der Sprache entfernt – also eigentlich nichts mehr wert.

Selbst die meisten Ihrer ursprünglichen Prämissen sind also eindeutig falsch.

Nun zu deiner Frage.

Könnte die Abfrage das Dollarzeichen vielleicht als PHP-Variable interpretiert haben?

Was ist mit der LIKE-Syntax, von der ich gehört habe, dass sie das %-Symbol oder sogar einen Platzhalter verwendet?

Ja, das hast du richtig gehört. Der genaue Zweck des LIKE-Operators besteht darin, eine Mustersuche durchzuführen. Das Deaktivieren dieser Zeichen in LIKE würde nicht den geringsten Sinn ergeben.

Jedes Mal, wenn Sie den LIKE-Operator verwenden, müssen Sie entscheiden, welches bestimmte Zeichen Sie verwenden und welches nicht. Sie können keine einmalige Lösung verwenden. Ganz zu schweigen davon, dass das %-Zeichen in allen anderen MySQL-Interaktionen keine besondere Bedeutung hat.

Vorbereitete Stellungnahmen sollten technisch gesehen all dies berücksichtigen

Vorbereitete Anweisungen haben nichts mit $- oder %-Zeichen zu tun. Vorbereitete Anweisungen beziehen sich auf die SQL-Injection, aber kein Zeichen kann sie verursachen (Sie könnten „Injection“ doch nicht als ordnungsgemäß verwendeten LIKE-Operator bezeichnen, oder?).

Zum Schluss noch das Schlimmste.

Falls Sie vergessen, vorbereitete Aussagen zu verwenden oder diese einfach nicht befolgen,

nichts wird dich retten.

Und die von Ihnen entwickelte Funktion würde am wenigsten helfen.

Zusammenfassen.

  1. Entfernen Sie diese Funktion.
  2. Verwenden Füllstoffe * um jede einzelne Variable in der Abfrage darzustellen.
  3. Escapezeichen % und _ in der Eingabe nur dann, wenn sie im LIKE-Operator verwendet werden und Sie nicht möchten, dass sie interpretiert werden.
  4. Verwenden Sie htmlspecialchars() für die Ausgabe, nicht für die MySQL-Eingabe.

*Lesen Sie vorbereitete Aussagen, wenn Ihnen dieser Begriff nicht bekannt ist.

Sie müssen das Dollarzeichen nicht meiden. MySQL betrachtet dieses Zeichen nicht speziell und PHP erkennt es nur im Quellcode, nicht in String-Werten (es sei denn, Sie rufen eval für den String auf, aber das ist ein ganz anderer Wurm von Würmern).

Sie müssten % und _ nur dann maskieren, wenn Sie Benutzereingaben als LIKE-Argument verwenden und nicht möchten, dass der Benutzer Platzhalter verwenden kann. Dies kann auftreten, wenn Sie ein Suchformular bearbeiten. Sie müssen es nicht verwenden, wenn Sie es in einer Datenbank speichern.

Sie müssen beim Zugriff auf die Datenbank keine htmlspecialchars verwenden. Dies sollte nur verwendet werden, wenn dem Benutzer Daten auf einer HTML-Seite angezeigt werden, um eine XSS-Injection zu verhindern.

Je nachdem, welche Daten und wofür sie verwendet werden.

Wenn Sie feststellen, dass die standardmäßigen Standardanweisungen von PHP zu groß und komplex sind, empfehle ich Ihnen, einen Blick auf einige der auf Github verfügbaren Klassen zu werfen, um Ihnen eine Vorstellung von vereinfachten Abfragen zu geben.

Ein Beispiel für das Einfügen von Abfragen mit dieser Klasse

$data = Array ("login" => "admin", "active" => true, "firstName" => "John", "lastName" => "Doe", "password" => $db->func( "SHA1(?)",Array ("secretpassword+salt")), // password = SHA1("secretpassword+salt") "createdAt" => $db->now(), // erstelltAt = NOW() " Expires" => $db->now("+1Y") // Expires = NOW() + Intervall 1 Jahr // Unterstützte Intervalle [s]econd, [m]inute, [h]hour, [d]day, [Monat Jahr); $id = $db->insert("users", $data); if ($id) echo "Benutzer wurde erstellt. Id=" . $id; sonst echo "insert failed: " . $db->getLastError();