Wie entkomme ich Sonderzeichen in MySQL?

77

Zum Beispiel:

select * from tablename where fields like "%string "hi"  %";

Error:

Sie haben einen Fehler in Ihrer SQL-Syntax. Überprüfen Sie das Handbuch, das Ihrer MySQL-Serverversion entspricht, auf die richtige Syntax für die Verwendung in der Nähe von 'hi "" in Zeile 1

Wie erstelle ich diese Abfrage?

Peter Mortensen
quelle
Dies kann betrogen werden. Wie kann ich die SQL-Injection in PHP verhindern? ... (Ich sage nicht, dass es richtig sein sollte oder ist - genau das, was passieren kann.)
Peter Mortensen

Antworten:

113

Die in dieser Antwort enthaltenen Informationen können zu unsicheren Programmierpraktiken führen.

Die hier bereitgestellten Informationen hängen stark von der MySQL-Konfiguration ab, einschließlich (aber nicht beschränkt auf) der Programmversion, des Datenbankclients und der verwendeten Zeichenkodierung.

Siehe http://dev.mysql.com/doc/refman/5.0/en/string-literals.html

MySQL erkennt die folgenden Escape-Sequenzen.
\ 0 Ein ASCII NUL (0x00) Zeichen.
\ 'Ein einfaches Anführungszeichen ("'").
\ "Ein doppeltes Anführungszeichen (" ").
\ b Ein Rücktastezeichen.
\ n Ein Zeilenumbruchzeichen.
\ r Ein Wagenrücklaufzeichen.
\ t Ein Tabulatorzeichen.
\ Z ASCII 26 (Control-Z). Siehe Hinweis nach der Tabelle.
\\ Ein Backslash-Zeichen ("\").
\% Ein Charakter. Siehe Hinweis nach der Tabelle.
\_ Ein Charakter. Siehe Hinweis nach der Tabelle.

Also brauchst du

select * from tablename where fields like "%string \"hi\" %";

Obwohl, wie Bill Karwin weiter unten bemerkt , die Verwendung von doppelten Anführungszeichen für Zeichenfolgenbegrenzer kein Standard-SQL ist, empfiehlt es sich, einfache Anführungszeichen zu verwenden. Dies vereinfacht die Dinge:

select * from tablename where fields like '%string "hi" %';
Paul Dixon
quelle
3
Warum ist es unsicher, einem Charakter zu entkommen?
Peter Mortensen
@PeterMortensen Weil Sie sich nicht vollständig darauf verlassen können, um nicht vertrauenswürdige Eingaben zu bereinigen. Das hängt davon ab, dass Sie alles entkommen, was der Server anders interpretiert, und wie die Bemerkung besagt, hängt dies von der Konfiguration, den verwendeten Versionen und Codierungen ab. Eine neue Version kann leicht etwas Neues einführen, das Sie nicht berücksichtigt haben, oder Sie können leicht einige Charaktere vergessen oder Angreifer können einige Randfälle finden. Schließlich führt Escapeng Sie von der bewährten Methode ab: Verwenden Sie Parameter für alles, was nicht vertrauenswürdig ist und die garantiert von der DB-Engine wie erwartet funktionieren.
Alejandro
35

Ich habe meine eigene MySQL-Escape-Methode in Java entwickelt (falls für irgendjemanden nützlich).

Siehe Klassencode unten.

Warnung: falsch, wenn der SQL-Modus NO_BACKSLASH_ESCAPES aktiviert ist.

private static final HashMap<String,String> sqlTokens;
private static Pattern sqlTokenPattern;

static
{           
    //MySQL escape sequences: http://dev.mysql.com/doc/refman/5.1/en/string-syntax.html
    String[][] search_regex_replacement = new String[][]
    {
                //search string     search regex        sql replacement regex
            {   "\u0000"    ,       "\\x00"     ,       "\\\\0"     },
            {   "'"         ,       "'"         ,       "\\\\'"     },
            {   "\""        ,       "\""        ,       "\\\\\""    },
            {   "\b"        ,       "\\x08"     ,       "\\\\b"     },
            {   "\n"        ,       "\\n"       ,       "\\\\n"     },
            {   "\r"        ,       "\\r"       ,       "\\\\r"     },
            {   "\t"        ,       "\\t"       ,       "\\\\t"     },
            {   "\u001A"    ,       "\\x1A"     ,       "\\\\Z"     },
            {   "\\"        ,       "\\\\"      ,       "\\\\\\\\"  }
    };

    sqlTokens = new HashMap<String,String>();
    String patternStr = "";
    for (String[] srr : search_regex_replacement)
    {
        sqlTokens.put(srr[0], srr[2]);
        patternStr += (patternStr.isEmpty() ? "" : "|") + srr[1];            
    }
    sqlTokenPattern = Pattern.compile('(' + patternStr + ')');
}


public static String escape(String s)
{
    Matcher matcher = sqlTokenPattern.matcher(s);
    StringBuffer sb = new StringBuffer();
    while(matcher.find())
    {
        matcher.appendReplacement(sb, sqlTokens.get(matcher.group(1)));
    }
    matcher.appendTail(sb);
    return sb.toString();
}
Walid
quelle
Verwendete Ihre Suchersetzungstabelle in einer MySQL-Prozedur, in der ich ein Tabulatortrennzeichen maskieren muss, um korrekt in die Datenbank eingefügt zu werden, wie '\ t'. thx
Erik Čerpnjak
Sehr nützlich für mich! Grüße!
Paul Vargas
Haben Sie eine C # -Version?
Hien Nguyen
28

Sie sollten einfache Anführungszeichen für Zeichenfolgenbegrenzer verwenden. Das einfache Anführungszeichen ist das Standard-SQL-Zeichenfolgenbegrenzer, und doppelte Anführungszeichen sind Bezeichnerbegrenzer (Sie können also spezielle Wörter oder Zeichen in den Namen von Tabellen oder Spalten verwenden).

In MySQL funktionieren doppelte Anführungszeichen (nicht standardmäßig) standardmäßig als Zeichenfolgenbegrenzer (es sei denn, Sie legen den ANSISQL-Modus fest). Wenn Sie jemals eine andere Marke von SQL-Datenbanken verwenden, können Sie sich angewöhnen, Anführungszeichen standardmäßig zu verwenden.

Ein weiterer praktischer Vorteil der Verwendung von einfachen Anführungszeichen besteht darin, dass die wörtlichen doppelten Anführungszeichen in Ihrer Zeichenfolge nicht maskiert werden müssen:

select * from tablename where fields like '%string "hi" %';
Bill Karwin
quelle
Ich stimme der Idee mit einfachen Anführungszeichen zu, denn wenn Sie beispielsweise zu PostgresSQL wechseln, werden Ihre Abfragen hartnäckig abgelehnt, und Sie müssen einfache Anführungszeichen verwenden. Es ist eine gute Praxis.
Kovacsbv
Das behandelt das Beispiel, aber was ist mit dem allgemeineren Fall? ZB für einen Backslash, `\`.
Peter Mortensen
@PeterMortensen Verwenden Sie einen doppelten Backslash, um ein wörtliches Backslash-Zeichen zu erhalten. Dies ist das gleiche wie in praktisch jeder Programmiersprache. Siehe auch: dev.mysql.com/doc/refman/8.0/en/string-literals.html
Bill Karwin
12

MySQL hat die String-Funktion QUOTE und sollte dieses Problem lösen:

Hadi Sadeqi
quelle
1
Außer es zitiert nicht LIKEden %Charakter, also ist es ziemlich nutzlos
Peter V. Mørch
QUOTEAchten Sie auch darauf, dass umgebende einzelne Qoutes für Zeichenfolgenwerte
hinzugefügt
8

Für solche Zeichenfolgen ist es für mich am bequemsten, das 'oder "zu verdoppeln, wie im MySQL-Handbuch erläutert:

Es gibt verschiedene Möglichkeiten, Anführungszeichen in eine Zeichenfolge aufzunehmen:

A “'” inside a string quoted with'” may be written as “''”.

A “"” inside a string quoted with “"” may be written as “""”.

Precede the quote character by an escape character (“\”).

A “'” inside a string quoted with"” needs no special treatment and need not be doubled or escaped. In the same way, “"” inside a

Mit "'" zitierte Saiten benötigen keine besondere Behandlung.

Es ist von http://dev.mysql.com/doc/refman/5.0/en/string-literals.html .

Raúl Moreno
quelle
1

Um zu testen, wie die doppelten Anführungszeichen mithilfe des Terminals in MySQL eingefügt werden, können Sie Folgendes verwenden:

TableName (Name, DString) -> Schema
in TableName-Werte einfügen ("Name", "My QQDoubleQuotedStringQQ")

Nach dem Einfügen des Werts können Sie den Wert in der Datenbank mit doppelten oder einfachen Anführungszeichen aktualisieren:

update table TableName replace(Dstring, "QQ", "\"")
Vishnu Prasanth G.
quelle
0

Wenn Sie beim Suchen in einer Zeichenfolge eine Variable verwenden, mysql_real_escape_string()ist dies gut für Sie. Nur mein Vorschlag:

$char = "and way's 'hihi'";
$myvar = mysql_real_escape_string($char);

select * from tablename where fields like "%string $myvar  %";
Ye Htun Z.
quelle
5
Diese Funktion wird in PHP 5.5 abgeschrieben und von 7.0
Phil M