Bei einem Array von IDs $galleries = array(1,2,5)
möchte ich eine SQL-Abfrage haben, die die Werte des Arrays in ihrer WHERE-Klausel verwendet, wie:
SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */
Wie kann ich diese Abfragezeichenfolge für MySQL generieren?
Antworten:
quelle
$galleries
die vor dieser Anweisung validiert werden soll! Vorbereitete Anweisungen können keine Arrays AFAIK verarbeiten. Wenn Sie also an gebundene Variablen gewöhnt sind, können Sie hier problemlos die SQL-Injection ermöglichen.$galleries
hätten den folgenden Wert :array('1); SELECT password FROM users;/*')
. Wenn Sie das nicht bereinigen, würde die Abfrage lautenSELECT * FROM galleries WHERE id IN (1); SELECT password FROM users;/*)
. Ändern Sie die Tabellen- und Spaltennamen in etwas, das Sie in Ihrer Datenbank haben, und versuchen Sie diese Abfrage. Überprüfen Sie die Ergebnisse. Als Ergebnis finden Sie eine Liste mit Passwörtern und keine Liste mit Galerien. Abhängig davon, wie die Daten ausgegeben werden oder was das Skript mit einem Array unerwarteter Daten macht, wird dies möglicherweise in die öffentliche Ansicht ausgegeben ... autsch.$galleries
in der Frage angegebenen Code eingerichtet habe und Sie ihn mit der oben genannten "SQL Injection-Schwachstelle" ausnutzen. Wenn Sie nicht können, zahlen Sie mir 200 USD. Wie ist es damit?Verwenden von PDO: [1]
Verwenden von MySQLi [2]
Erläuterung:
Verwenden Sie den SQL-
IN()
Operator, um zu überprüfen, ob in einer bestimmten Liste ein Wert vorhanden ist.Im Allgemeinen sieht es so aus:
Wir können einen Ausdruck erstellen, der innerhalb
()
unseres Arrays platziert wird. Beachten Sie, dass mindestens ein Wert in der Klammer stehen muss. Andernfalls gibt MySQL einen Fehler zurück. Dies entspricht der Sicherstellung, dass unser Eingabearray mindestens einen Wert hat. Um SQL-Injection-Angriffe zu vermeiden, generieren Sie zunächst?
für jedes Eingabeelement ein, um eine parametrisierte Abfrage zu erstellen. Hier gehe ich davon aus, dass das Array mit Ihren IDs heißt$ids
:Bei einem Eingabearray von drei Elementen
$select
sieht es folgendermaßen aus:Beachten Sie erneut, dass es
?
für jedes Element im Eingabearray ein gibt. Dann verwenden wir PDO oder MySQLi, um die Abfrage wie oben beschrieben vorzubereiten und auszuführen.Verwenden des
IN()
Operators mit ZeichenfolgenAufgrund der gebundenen Parameter ist es einfach, zwischen Zeichenfolgen und Ganzzahlen zu wechseln. Für PDO ist keine Änderung erforderlich. für MySQLi ändern Sie
str_repeat('i',
zu,str_repeat('s',
wenn Sie Zeichenfolgen überprüfen müssen.[1]: Ich habe einige Fehlerprüfungen auf Kürze weggelassen. Sie müssen für jede Datenbankmethode nach den üblichen Fehlern suchen (oder Ihren DB-Treiber so einstellen, dass Ausnahmen ausgelöst werden).
[2]: Benötigt PHP 5.6 oder höher. Wieder habe ich einige Fehlerprüfungen auf Kürze weggelassen.
quelle
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
dann die...
ist die ID Erweiterung ist aus einem Array in mehrere Parameter. Wenn Sie sich darauf beziehenexpr IN (value,...)
, bedeutet dies nur, dass es mehr Werte geben kann, zWHERE id IN (1, 3, 4)
. Es muss nur mindestens einen geben....
: wiki.php.net/rfc/argument_unpackingInts:
Zeichenfolgen:
quelle
Vorausgesetzt, Sie bereinigen Ihre Eingaben zuvor ordnungsgemäß ...
Dann passen Sie einfach Ihre Abfrage an:
Geben Sie die Werte entsprechend Ihrem Datensatz entsprechend an.
quelle
Verwenden:
Eine einfache
for each
Schleife wird funktionieren.Der Weg von Flavius / AvatarKava ist besser, aber stellen Sie sicher, dass keiner der Array-Werte Kommas enthält.
quelle
Als Antwort von Flavius Stef können Sie
intval()
sicherstellen, dass alleid
int-Werte sind:quelle
Für MySQLi mit Escape-Funktion:
Für gU mit vorbereiteter Erklärung:
quelle
Wir sollten uns um SQL-Injection- Schwachstellen und einen leeren Zustand kümmern . Ich werde beide wie unten behandeln.
Für ein reines numerisches Array verwenden , um die geeignete Typkonvertierung viz
intval
oderfloatval
oderdoubleval
über jedes Element. Für Zeichenfolgentypen,mysqli_real_escape_string()
die auf Wunsch auch auf numerische Werte angewendet werden können. MySQL erlaubt sowohl Zahlen als auch Datumsvarianten als Zeichenfolge .Erstellen Sie eine Funktion ähnlich der folgenden: Um die Werte vor dem Übergeben an die Abfrage angemessen zu umgehen:
Eine solche Funktion steht Ihnen höchstwahrscheinlich bereits in Ihrer Anwendung zur Verfügung, oder Sie haben bereits eine erstellt.
Bereinigen Sie das String-Array wie folgt:
Ein numerisches Array kann mit
intval
oderfloatval
oderdoubleval
stattdessen nach Bedarf bereinigt werden :Erstellen Sie dann schließlich die Abfragebedingung
oder
Da das Array manchmal auch leer sein kann,
$galleries = array();
sollten wir daher beachten, dassIN ()
keine leere Liste zulässig ist. Man kannOR
stattdessen auch verwenden , aber das Problem bleibt bestehen. Die obige Prüfungcount($values)
soll also das Gleiche sicherstellen.Und fügen Sie es der endgültigen Abfrage hinzu:
quelle
$query = 'SELECT * FROM galleries WHERE ' . (count($gallaries) ? "id IN ('" . implode("', '", array_map('escape', $gallaries)) . "')" : 0);
Sicherer.
quelle
Die SafeMySQL- Bibliothek von Col. Shrapnel für PHP bietet typgesteuerte Platzhalter in den parametrisierten Abfragen sowie einige praktische Platzhalter für die Arbeit mit Arrays. Der
?a
Platzhalter erweitert ein Array zu einer durch Kommas getrennten Liste von maskierten Zeichenfolgen *.Zum Beispiel:
* Da MySQL einen automatischen Typzwang ausführt, spielt es keine Rolle, dass SafeMySQL die oben genannten IDs in Zeichenfolgen konvertiert - Sie erhalten immer noch das richtige Ergebnis.
quelle
Wir können diese "WHERE id IN" -Klausel verwenden, wenn wir das Eingabearray richtig filtern. Etwas wie das:
Wie das folgende Beispiel:
Dh jetzt solltest du sicher benutzen
$query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";
quelle
Sie können Tisch
texts
(T_ID (int), T_TEXT (text))
und Tisch habentest
(id (int), var (varchar(255)))
Im
insert into test values (1, '1,2,3') ;
Folgenden werden Zeilen aus Tabellentexten ausgegeben, in denenT_ID IN (1,2,3)
:Auf diese Weise können Sie eine einfache n2m-Datenbankbeziehung ohne zusätzliche Tabelle verwalten und nur SQL verwenden, ohne PHP oder eine andere Programmiersprache verwenden zu müssen.
quelle
Mehr ein Beispiel:
quelle
Neben der Verwendung der IN-Abfrage haben Sie zwei Möglichkeiten, da bei einer IN-Abfrage das Risiko einer SQL-Injection-Sicherheitsanfälligkeit besteht. Sie können eine Schleife verwenden , um genau die gewünschten Daten abzurufen, oder Sie können die Abfrage mit ODER- Groß- / Kleinschreibung verwenden
quelle
Sicherer Weg ohne gU:
(array)$ids
Gussvariable$ids
Arrayarray_map
Transformieren Sie alle Array-Werte in Ganzzahlenarray_unique
Wiederholte Werte entfernenarray_filter
Nullwerte entfernenimplode
Verbinden Sie alle Werte mit der IN-Auswahlquelle
Da sich die ursprüngliche Frage auf ein Array von Zahlen bezieht und ich ein Array von Zeichenfolgen verwende, konnte ich die angegebenen Beispiele nicht zum Laufen bringen.
Ich fand heraus, dass jede Zeichenfolge in einfache Anführungszeichen eingeschlossen werden musste, um mit der
IN()
Funktion zu arbeiten.Hier ist meine Lösung
Wie Sie sehen können, umschließt die erste Funktion jede Arrayvariable
single quotes (\')
und implodiert dann das Array.HINWEIS:
$status
Die SQL-Anweisung enthält keine einfachen Anführungszeichen.Es gibt wahrscheinlich eine schönere Möglichkeit, die Anführungszeichen hinzuzufügen, aber dies funktioniert.
quelle
$filter = "'" . implode("','",$status) . "'";
'
innerhalb der Zeichenfolge? SQL Injection anfällig. Verwenden Sie PDO :: quote oder mysqli_real_escape_string.Unten ist die Methode aufgeführt, die ich verwendet habe, um PDO mit benannten Platzhaltern für andere Daten zu verwenden. Um die SQL-Injection zu überwinden, filtere ich das Array so, dass nur die Werte akzeptiert werden, die Ganzzahlen sind, und lehne alle anderen ab.
quelle
Grundlegende Methoden zum Verhindern der SQL-Injection sind:
Die Verwendung von vorbereiteten Anweisungen und parametrisierten Abfragen wird als die bessere Vorgehensweise angesehen. Wenn Sie jedoch die Methode der Escapezeichen wählen, können Sie mein Beispiel unten ausprobieren.
Sie können die Abfragen generieren, indem Sie
array_map
jedem der Elemente in$galleries
:Die generierte $ sql-Variable lautet:
quelle