So wie ich das sehe, können SQL-Injection-Angriffe verhindert werden durch:
- Sorgfältiges Prüfen, Filtern und Codieren von Eingaben (vor dem Einfügen in SQL)
- Verwendung von vorbereiteten Anweisungen / parametrisierten Abfragen
Ich nehme an, dass es für jeden das Für und Wider gibt, aber warum hat sich # 2 durchgesetzt und wurde mehr oder weniger als der tatsächliche Weg zur Verhinderung von Injektionsangriffen angesehen? Ist es nur sicherer und weniger fehleranfällig oder gab es andere Faktoren?
Soweit ich weiß, kann # 1 genauso effektiv sein wie # 2, wenn man es richtig anwendet und alle Vorbehalte beachtet.
Bereinigen, Filtern und Codieren
Ich war verwirrt darüber, was Bereinigen , Filtern und Codieren bedeutete. Ich werde sagen , dass für meine Zwecke, die alle der oben für Option 1. In diesem Fall in Betracht gezogen wird Ich verstehe , dass Hygienisierung und Filterung das Potenzial hat , zu ändern oder zu verwerfen Eingangsdaten, während Codierung erhalten Daten , wie sie ist , sondern kodiert sie richtig, um Injektionsangriffe zu vermeiden. Ich glaube, dass das Entkommen von Daten als eine Art der Verschlüsselung angesehen werden kann.
Parametrisierte Abfragen vs. Codierungsbibliothek
Es gibt Antworten, bei denen Konzepte von parameterized queries
und encoding libraries
die austauschbar behandelt werden. Korrigieren Sie mich, wenn ich falsch liege, aber ich habe den Eindruck, dass sie unterschiedlich sind.
Mein Verständnis ist, dass sie encoding libraries
, egal wie gut sie sind, immer das Potenzial haben , SQL "Program" zu ändern, weil sie Änderungen an SQL selbst vornehmen, bevor es an das RDBMS gesendet wird.
Parameterized queries
Senden Sie andererseits das SQL-Programm an das RDBMS, das dann die Abfrage optimiert, den Abfrageausführungsplan definiert, die zu verwendenden Indizes usw. auswählt und dann die Daten als letzten Schritt im RDBMS einfügt selbst.
Codierungsbibliothek
data -> (encoding library)
|
v
SQL -> (SQL + encoded data) -> RDBMS (execution plan defined) -> execute statement
Parametrisierte Abfrage
data
|
v
SQL -> RDBMS (query execution plan defined) -> data -> execute statement
Historische Bedeutung
In einigen Antworten wird erwähnt, dass in der Vergangenheit aus Leistungsgründen parametrisierte Abfragen (PQ) erstellt wurden und bevor Injection-Angriffe, die auf Codierungsprobleme abzielten, populär wurden. Irgendwann stellte sich heraus, dass PQ auch gegen Injektionsattacken ziemlich wirksam war. Um dem Geist meiner Frage gerecht zu werden, warum blieb PQ die Methode der Wahl und warum entwickelte es sich besser als die meisten anderen Methoden, wenn es darum geht, SQL-Injection-Angriffe zu verhindern?
Antworten:
Das Problem ist, dass Sie bei Nummer 1 die gesamte SQL-Variante, gegen die Sie arbeiten, analysieren und interpretieren müssen, damit Sie wissen, ob sie etwas tut, was sie nicht tun sollte. Halten Sie diesen Code auf dem neuesten Stand, wenn Sie Ihre Datenbank aktualisieren. Überall akzeptieren Sie Eingaben für Ihre Abfragen. Und nicht vermasseln.
Ja, so etwas würde SQL-Injection-Angriffe stoppen, aber die Implementierung ist absurderweise teurer.
quelle
null
eine Zeichenfolge oder eine Zahl gemeint ist , und dementsprechend handeln. Dies ist sehr gut für die Sicherheit. Und selbst wenn Sie die Abfrage einmal ausführen, hat sie die DB-Engine bereits für Sie optimiert. Besser noch, wenn es zwischengespeichert ist!Weil Option 1 keine Lösung ist. Durchsuchen und Filtern bedeutet, ungültige Eingaben zurückzuweisen oder zu entfernen. Aber jede Eingabe kann gültig sein. Zum Beispiel ist Apostroph ein gültiges Zeichen im Namen "O'Malley". Es muss nur korrekt codiert werden, bevor es in SQL verwendet wird, wie es vorbereitete Anweisungen tun.
Nachdem Sie die Notiz hinzugefügt haben, scheinen Sie im Grunde zu fragen, warum Sie eine Standardbibliotheksfunktion verwenden sollen, anstatt Ihren eigenen funktionsähnlichen Code von Grund auf zu schreiben. Sie sollten immer Standardbibliothekslösungen dem Schreiben Ihres eigenen Codes vorziehen. Es ist weniger Arbeit und mehr wartbar. Dies gilt für alle Funktionen, aber insbesondere für sicherheitsrelevante Dinge ist es absolut sinnlos, das Rad selbst neu zu erfinden.
quelle
O\'Malley
verwendet den Schrägstrich, um das Anführungszeichen für das ordnungsgemäße Einfügen zu umgehen (zumindest in einigen Datenbanken). In MS SQL oder Access kann es mit einem zusätzlichen Anführungszeichen maskiert werdenO''Malley
. Nicht sehr tragbar, wenn Sie es selbst tun müssen.Wenn Sie versuchen, Zeichenfolgen zu verarbeiten, wird keine SQL-Abfrage generiert. Sie generieren eine Zeichenfolge, die eine SQL-Abfrage erzeugen kann. Es gibt eine Indirektionsebene, die viel Raum für Fehler und Bugs eröffnet. Es ist wirklich etwas überraschend, da wir in den meisten Kontexten gerne programmatisch mit etwas interagieren. Wenn wir beispielsweise eine Listenstruktur haben und ein Element hinzufügen möchten, tun wir dies normalerweise nicht:
Wenn jemand vorschlägt, das zu tun, würden Sie zu Recht antworten, dass es ziemlich lächerlich ist, und dass man einfach tun sollte:
Das interagiert mit der Datenstruktur auf konzeptioneller Ebene. Es wird keine Abhängigkeit davon eingeführt, wie diese Struktur gedruckt oder analysiert werden könnte. Das sind völlig orthogonale Entscheidungen.
Ihr erster Ansatz ähnelt dem ersten Beispiel (nur ein bisschen schlechter): Sie gehen davon aus, dass Sie programmgesteuert die Zeichenfolge erstellen können, die korrekt als die von Ihnen gewünschte Abfrage analysiert wird. Das hängt vom Parser und einer ganzen Reihe von Zeichenfolgenverarbeitungslogiken ab.
Der zweite Ansatz für die Verwendung vorbereiteter Abfragen ähnelt dem zweiten Beispiel. Wenn Sie eine vorbereitete Abfrage verwenden, analysieren Sie im Wesentlichen eine Pseudoabfrage, die legal ist, aber einige Platzhalter enthält, und verwenden dann eine API, um einige Werte dort korrekt zu ersetzen. Der Parsing-Prozess entfällt, und Sie müssen sich keine Gedanken mehr über die Verarbeitung von Zeichenfolgen machen.
Im Allgemeinen ist es viel einfacher und weniger fehleranfällig, mit Dingen auf konzeptioneller Ebene zu interagieren. Eine Abfrage ist keine Zeichenfolge. Sie erhalten eine Abfrage, wenn Sie eine Zeichenfolge analysieren oder programmgesteuert erstellen (oder mit einer anderen Methode können Sie eine erstellen).
Hier gibt es eine gute Analogie zwischen Makros im C-Stil, die einfachen Text ersetzen, und Makros im Lisp-Stil, die beliebigen Code generieren. Mit Makros im C-Stil können Sie Text im Quellcode ersetzen. Dies bedeutet, dass Sie syntaktische Fehler oder irreführendes Verhalten einführen können. Mit Lisp-Makros generieren Sie Code in der Form, in der der Compiler ihn verarbeitet (dh Sie geben die tatsächlichen Datenstrukturen zurück, die der Compiler verarbeitet, und nicht Text, den der Leser verarbeiten muss, bevor der Compiler darauf zugreifen kann). . Mit einem Lisp-Makro können Sie jedoch keinen Parser-Fehler generieren. Sie können zB nicht generieren (let ((ab) a .
Selbst mit Lisp-Makros können Sie immer noch fehlerhaften Code generieren, da Sie sich nicht unbedingt der Struktur bewusst sind, die vorhanden sein soll. In Lisp bedeutet (let ((ab)) a) beispielsweise "eine neue lexikalische Bindung der Variablen a an den Wert der Variablen b herstellen und dann den Wert von a zurückgeben", und (let (ab) a) bedeutet "Stellen Sie neue lexikalische Bindungen der Variablen a und b her, initialisieren Sie beide auf null und geben Sie dann den Wert von a zurück." Diese sind beide syntaktisch korrekt, aber sie bedeuten verschiedene Dinge. Um dieses Problem zu vermeiden, können Sie semantischere Funktionen verwenden und folgende Aktionen ausführen:
Mit so etwas ist es unmöglich , etwas zurückzugeben, das syntaktisch ungültig ist, und es ist viel schwieriger , etwas zurückzugeben, das versehentlich nicht Ihren Wünschen entspricht.
quelle
Es ist hilfreich, dass Option 2 im Allgemeinen als bewährte Methode angesehen wird, da die Datenbank die nicht parametrisierte Version der Abfrage zwischenspeichern kann. Parametrisierte Abfragen liegen mehrere Jahre vor dem Problem der SQL-Injection (glaube ich). Es kommt also vor, dass Sie zwei Fliegen mit einer Klappe schlagen können.
quelle
Einfach gesagt: Das haben sie nicht. Deine Meinung:
ist grundsätzlich fehlerhaft. Parametrisierte Abfragen existieren schon viel länger als SQL Injection zumindest allgemein bekannt ist. Sie wurden im Allgemeinen entwickelt, um die Konzentration von Zeichenfolgen in der üblichen "Form for Search" -Funktionalität zu vermeiden, die LOB-Anwendungen (Line of Business) haben. Viele - VIELE - Jahre später stellte jemand eine Sicherheitslücke bei der Manipulation der Zeichenfolgen fest.
Ich erinnere mich an SQL vor 25 Jahren (als das Internet noch nicht so verbreitet war - es fing gerade erst an) und an SQL im Vergleich zu IBM DB5 IIRC Version 5 - und das hatte bereits parametrisierte Abfragen.
quelle
Neben all den anderen guten Antworten:
Der Grund, warum # 2 besser ist, ist, dass es Ihre Daten von Ihrem Code trennt. In der Nummer 1 sind Ihre Daten Teil Ihres Codes und daher kommen all die schlechten Dinge. Mit # 1 erhalten Sie Ihre Abfrage und müssen zusätzliche Schritte ausführen, um sicherzustellen, dass Ihre Abfrage Ihre Daten als Daten versteht, während Sie mit # 2 Ihren Code und seinen Code erhalten und Ihre Daten Daten sind.
quelle
Parametrisierte Abfragen bieten neben der SQL-Injection-Abwehr häufig den zusätzlichen Vorteil, dass sie nur einmal kompiliert und dann mehrmals mit unterschiedlichen Parametern ausgeführt werden.
Aus der SQL - Datenbank Sicht
select * from employees where last_name = 'Smith'
undselect * from employees where last_name = 'Fisher'
sind deutlich unterschiedlich und erfordern daher getrennte Analyse, Erstellung und Optimierung. Sie belegen auch separate Slots im Speicherbereich, in denen kompilierte Anweisungen gespeichert werden. In einem stark ausgelasteten System mit einer großen Anzahl ähnlicher Abfragen, die unterschiedliche Parameter aufweisen, können die Berechnung und der Speicheraufwand erheblich sein.Anschließend bietet die Verwendung parametrisierter Abfragen häufig erhebliche Leistungsvorteile.
quelle
prepare
sich oft stark von einem tatsächlichen SQL-Levelprepare
.SELECT * FROM employees WHERE last_name IN (?, ?)
undSELECT * FROM employees WHERE last_name IN (?, ?, ?, ?, ?, ?)
.Warte aber warum?
Option 1 bedeutet, dass Sie für jede Art von Eingabe Desinfektionsroutinen schreiben müssen, während Option 2 weniger fehleranfällig ist und Sie weniger Code schreiben / testen / warten müssen.
Mit ziemlicher Sicherheit kann das "Aufpassen aller Vorbehalte" komplexer sein, als Sie denken, und Ihre Sprache (z. B. Java PreparedStatement) enthält mehr Informationen als Sie denken.
Vorbereitete Anweisungen oder parametrisierte Abfragen werden auf dem Datenbankserver vorkompiliert. Wenn also Parameter festgelegt werden, erfolgt keine SQL-Verkettung, da die Abfrage keine SQL-Zeichenfolge mehr ist. Ein zusätzlicher Vorteil ist, dass das RDBMS die Abfrage zwischenspeichert und nachfolgende Aufrufe als dieselbe SQL betrachtet werden, auch wenn die Parameterwerte variieren, während bei verkettetem SQL jedes Mal, wenn die Abfrage mit unterschiedlichen Werten ausgeführt wird, die Abfrage unterschiedlich ist und das RDBMS sie analysieren muss , erstellen Sie den Ausführungsplan erneut usw.
quelle
Stellen wir uns vor, wie ein idealer "Desinfizieren, Filtern und Codieren" -Ansatz aussehen würde.
Bereinigung und Filterung sind möglicherweise im Kontext einer bestimmten Anwendung sinnvoll, aber letztendlich bedeuten beide, dass Sie diese Daten nicht in die Datenbank stellen können. Für Ihre Anwendung mag das eine gute Idee sein, aber es ist nichts, was Sie als allgemeine Lösung empfehlen können, da es Anwendungen geben wird, die beliebige Zeichen in der Datenbank speichern können müssen.
So bleibt die Codierung. Sie könnten mit einer Funktion beginnen, die Zeichenfolgen durch Hinzufügen von Escape-Zeichen codiert, damit Sie diese in sich selbst ersetzen können. Da unterschiedliche Datenbanken unterschiedliche Escape- Zeichen benötigen (in einigen Datenbanken beide
\'
und''
gültige Escape-Sequenzen für'
, in anderen jedoch nicht), muss diese Funktion vom Datenbankanbieter bereitgestellt werden.Aber nicht alle Variablen sind Zeichenfolgen. Manchmal müssen Sie eine ganze Zahl oder ein Datum eingeben. Diese Zeichenfolgen werden anders dargestellt als Zeichenfolgen. Sie benötigen daher unterschiedliche Codierungsmethoden (diese müssten wiederum für den Datenbankanbieter spezifisch sein), und Sie müssen sie auf unterschiedliche Weise in die Abfrage einsetzen.
Vielleicht wäre es einfacher, wenn die Datenbank auch die Ersetzung für Sie übernehmen würde - sie weiß bereits, welche Typen die Abfrage erwartet, wie Daten sicher verschlüsselt und wie sie sicher in Ihre Abfrage eingefügt werden, sodass Sie sich keine Sorgen machen müssen es in Ihrem Code.
Zu diesem Zeitpunkt haben wir parametrisierte Abfragen neu erfunden.
Einmal parametrisierte Abfragen eröffnen neue Möglichkeiten wie Leistungsoptimierungen und eine vereinfachte Überwachung.
Das Codieren ist schwierig und das Codieren ist nicht von der Parametrierung zu unterscheiden.
Wenn Sie die Zeichenfolgeninterpolation als Methode zum Erstellen von Abfragen wirklich mögen, fallen Ihnen einige Sprachen (Scala und ES2015) ein, die über eine steckbare Zeichenfolgeninterpolation verfügen. Daher gibt es Bibliotheken , mit denen Sie parametrisierte Abfragen schreiben können, die wie Zeichenfolgeninterpolation aussehen sind vor SQL-Injection sicher - so in der ES2015-Syntax:
quelle
In Option 1 arbeiten Sie mit einer Eingabemenge von size = infinity, die Sie einer sehr großen Ausgabegröße zuordnen möchten. In Option 2 haben Sie Ihre Eingabe auf das beschränkt, was Sie auswählen. Mit anderen Worten:
Anderen Antworten zufolge scheint es auch einige Leistungsvorteile zu geben, wenn Sie Ihren Bereich von unendlich auf etwas Verwaltbares beschränken.
quelle
Ein nützliches mentales Modell für SQL (insbesondere moderne Dialekte) ist, dass jede SQL-Anweisung oder -Abfrage ein Programm ist. In einem nativen ausführbaren Binärprogramm sind die gefährlichsten Sicherheitslücken Überläufe, bei denen ein Angreifer den Programmcode mit verschiedenen Anweisungen überschreiben oder ändern kann.
Eine SQL-Injection-Sicherheitsanfälligkeit ist isomorph zu einem Pufferüberlauf in einer Sprache wie C. Die Vergangenheit hat gezeigt, dass Pufferüberläufe äußerst schwer zu verhindern sind - selbst extrem kritischer Code, der einer offenen Überprüfung unterzogen wurde, enthielt häufig solche Sicherheitsanfälligkeiten.
Ein wichtiger Aspekt des modernen Ansatzes zur Behebung von Sicherheitslücken durch Überlauf ist die Verwendung von Hardware- und Betriebssystemmechanismen, um bestimmte Teile des Speichers als nicht ausführbar und andere Teile des Speichers als schreibgeschützt zu kennzeichnen. (Siehe beispielsweise den Wikipedia-Artikel zum Schutz des ausführbaren Speicherplatzes .) Auf diese Weise kann der Angreifer selbst dann, wenn ein Angreifer Daten ändern könnte, nicht bewirken, dass die eingespeisten Daten als Code behandelt werden.
Wenn eine SQL-Injection-Sicherheitsanfälligkeit einem Pufferüberlauf entspricht, wie lautet dann die SQL-Entsprechung für ein NX-Bit oder für schreibgeschützte Speicherseiten? Die Antwort lautet: vorbereitete Anweisungen , die parametrisierte Abfragen und ähnliche Mechanismen für Nicht-Abfrageanfragen enthalten. Die vorbereitete Anweisung wird mit bestimmten Teilen kompiliert, die als schreibgeschützt gekennzeichnet sind, sodass ein Angreifer diese Teile des Programms und andere Teile, die als nicht ausführbare Daten gekennzeichnet sind (die Parameter der vorbereiteten Anweisung), nicht ändern kann, in die der Angreifer jedoch Daten einfügen könnte Dies wird niemals als Programmcode behandelt, wodurch das meiste Missbrauchspotenzial beseitigt wird.
Sicherlich ist es gut, Benutzereingaben zu bereinigen, aber um wirklich sicher zu sein, müssen Sie paranoid sein (oder entsprechend wie ein Angreifer denken). Eine Steueroberfläche außerhalb des Programmtexts ist der Weg, dies zu tun, und vorbereitete Anweisungen stellen diese Steueroberfläche für SQL bereit. Kein Wunder also, dass vorbereitete Anweisungen und damit parametrisierte Abfragen der Ansatz sind, den die überwiegende Mehrheit der Sicherheitsexperten empfiehlt.
quelle
Ich schreibe bereits hier darüber: https://stackoverflow.com/questions/6786034/can-parameterized-statement-stop-all-sql-injection/33033576#33033576
Aber um es einfach zu halten:
Die Art und Weise, wie parametrisierte Abfragen funktionieren, besteht darin, dass die sqlQuery als Abfrage gesendet wird und die Datenbank genau weiß, was diese Abfrage bewirkt. Erst dann werden der Benutzername und die Kennwörter lediglich als Werte eingefügt. Dies bedeutet, dass sie die Abfrage nicht ausführen können, da die Datenbank bereits weiß, wie die Abfrage ausgeführt wird. In diesem Fall würde es nach einem Benutzernamen von "Niemand ODER 1 = 1 '-" und einem leeren Passwort suchen, das falsch sein sollte.
Dies ist jedoch keine vollständige Lösung, und die Eingabevalidierung muss noch durchgeführt werden, da dies keine Auswirkungen auf andere Probleme wie XSS-Angriffe hat, da Sie immer noch JavaScript in die Datenbank einfügen können. Wenn dies dann auf einer Seite ausgelesen wird, wird es abhängig von einer Ausgabeüberprüfung als normales Javascript angezeigt. Das Beste ist also, die Eingabevalidierung zu verwenden, aber parametrisierte Abfragen oder gespeicherte Prozeduren zu verwenden, um SQL-Angriffe zu stoppen
quelle
Ich habe noch nie SQL verwendet. Aber offensichtlich hört man, welche Probleme die Leute haben und SQL-Entwickler hatten Probleme mit dieser "SQL-Injection" -Sache. Lange konnte ich es nicht herausfinden. Und dann wurde mir klar, dass Leute SQL-Anweisungen erstellen, echte SQL-Quellanweisungen, indem sie Zeichenfolgen verketten, von denen einige von einem Benutzer eingegeben wurden. Und mein erster Gedanke an diese Erkenntnis war Schock. Totaler Schock. Ich dachte: Wie kann man so lächerlich dumm sein und in einer solchen Programmiersprache Aussagen machen? Für einen C- oder C ++ - oder Java- oder Swift-Entwickler ist dies völliger Wahnsinn.
Das heißt, es ist nicht sehr schwierig, eine C-Funktion zu schreiben, die eine C-Zeichenfolge als Argument verwendet und eine andere Zeichenfolge erzeugt, die genau wie ein Zeichenfolgenliteral im C-Quellcode aussieht, das dieselbe Zeichenfolge darstellt. Beispielsweise würde diese Funktion abc in "abc" und "abc" in "abc" und "abc" in "\" \\ "abc \\" \ "" übersetzen. (Nun, wenn das für Sie falsch aussieht, ist das HTML. Es war richtig, als ich es eingetippt habe, aber nicht, als es angezeigt wurde.) Und wenn diese C-Funktion erst einmal geschrieben ist, ist es überhaupt nicht schwierig, C-Quellcode zu generieren Der vom Benutzer bereitgestellte Text aus einem Eingabefeld wird in ein C-String-Literal umgewandelt. Das ist nicht schwer sicher zu machen. Warum SQL-Entwickler diesen Ansatz nicht verwenden würden, um SQL-Injektionen zu vermeiden, ist mir ein Rätsel.
"Desinfizieren" ist ein völlig fehlerhafter Ansatz. Der schwerwiegende Fehler besteht darin, dass bestimmte Benutzereingaben illegal sind. Am Ende haben Sie eine Datenbank, in der ein generisches Textfeld keinen Text wie den folgenden enthalten kann. Drop Table oder was auch immer Sie in einer SQL-Injection verwenden würden, um Schaden zu verursachen. Ich finde das ziemlich inakzeptabel. Wenn eine Datenbank Text speichert, sollte sie in der Lage sein, beliebigen Text zu speichern . Und der praktische Fehler ist, dass Desinfektionsmittel es nicht richtig zu machen scheinen :-(
Parametrisierte Abfragen sind natürlich das, was jeder Programmierer erwarten würde, der eine kompilierte Sprache verwendet. Das macht das Leben so viel einfacher: Sie haben eine Zeichenfolge eingegeben, und Sie müssen sie nicht einmal in eine SQL-Zeichenfolge übersetzen, sondern übergeben sie einfach als Parameter, ohne dass die Wahrscheinlichkeit besteht, dass Zeichen in dieser Zeichenfolge Schaden anrichten.
Aus der Sicht eines Entwicklers, der kompilierte Sprachen verwendet, ist das Desinfizieren etwas, das mir niemals einfällt. Das Bedürfnis nach Desinfektion ist verrückt. Parametrisierte Abfragen sind die offensichtliche Lösung des Problems.
(Ich fand Josips Antwort interessant. Er sagt im Grunde, dass Sie mit parametrisierten Abfragen jeden Angriff auf SQL stoppen können, aber dann können Sie Text in Ihrer Datenbank haben, der zum Erstellen einer JavaScript-Injektion verwendet wird :-( Nun, wir haben wieder das gleiche Problem , und ich weiß nicht, ob Javascript eine Lösung dafür hat.
quelle
Das Hauptproblem besteht darin, dass Hacker Möglichkeiten gefunden haben, die Hygiene zu umgehen, während die parametrisierten Abfragen ein vorhandenes Verfahren waren, das perfekt mit den zusätzlichen Vorteilen von Leistung und Speicher zusammenarbeitet.
Einige Leute vereinfachen das Problem, da "es sich nur um einfache und doppelte Anführungszeichen handelt". Hacker haben jedoch intelligente Methoden gefunden, um eine Erkennung zu vermeiden, wie z. B. die Verwendung unterschiedlicher Codierungen oder die Verwendung von Datenbankfunktionen.
Wie auch immer, Sie mussten nur eine einzige Zeichenfolge vergessen, um eine katastrophale Datenverletzung zu verursachen. Hacker konnten Skripte automatisieren, um die gesamte Datenbank mit einer Reihe von Abfragen herunterzuladen. Wenn die Software als Open-Source-Suite oder als berühmte Business-Suite bekannt ist, können Sie einfach die Benutzer- und Kennworttabelle aufrufen.
Auf der anderen Seite war es nur eine Frage des Lernens, verkettete Abfragen zu verwenden und sich daran zu gewöhnen.
quelle