In diesem Leitfaden wird die Methode detailliert beschrieben, die tatsächlich funktioniert: strukturelle Beschränkung auf SELECT, geschlossene Whitelist von Funktionen, obligatorische Zeilenbegrenzung und Sperrung des abgefragten Schemas. Jeder Schritt basiert auf dem Validator, der tatsächlich in der NL2SQL-Engine von Aurabase implementiert ist, einer Funktion der nativen KI , die in das Backendintegriert ist, und nicht auf einem nachträglich zusammengestellten Dienst eines Drittanbieters. Wenn das Thema für Sie neu ist, legt unser Überblick über NL2SQL den Grundstein und das Schritt-für-Schritt-Tutorial zeigt, wie Sie den vollständigen Endpunkt erstellen.
Das Wesentliche
- Prompt Engineering („generiert nur SELECT“) ist keine Sicherheitsüberprüfung: Ein Modell kann halluzinieren, sich von einer mehrdeutigen Frage leiten lassen oder die Anweisungen einfach ignorieren.
- Die durchgeführte Validierung ist strukturell: Ein Parser erstellt den syntaktischen Baum (AST) der Anfrage und lehnt standardmäßig alles ab, was nicht explizit autorisiert ist.
- Vier konkrete Schichten begrenzen das Risiko: striktes SELECT (weder Unterabfrage, noch CTE, noch UNION), geschlossene Whitelist mit zehn Funktionen,
LIMITobligatorisch und begrenzt, blockierter Zugriff auf den Systemkatalog und Nicht-Mandanten-Schemata. - Das abgefragte Schema muss vom Server stammen, niemals aus einem Feld in der Client-Anfrage: Andernfalls hindert nichts einen Aufrufer daran, sein eigenes Schema bereitzustellen, um die Validierung zu umgehen.
- Bei Aurabase wird dieser Validator (Rust-Kiste
sqlparser) mit kontradiktorischen Fällen getestet, die im Code dokumentiert sind: verbotene Funktionen, die inFILTER, in einem Intra-AggregatORDER BYoder inOFFSETversteckt sind.
Warum blockiert eine Anweisung in der Systemaufforderung nichts?
Eine Systemaufforderung mit der Meldung „Generiert nur SELECT-Abfragen“ ist eine Präferenz und kein Hindernis. Das Modell respektiert es meistens, weil es darauf trainiert wurde, den Anweisungen zu folgen, und nicht, weil eine technische Einschränkung es physisch daran hindert, etwas anderes zu schreiben. Zwei Fehlerklassen führen dazu, dass dieses Vertrauen in die Produktion unzureichend ist.
Das erste ergibt sich aus der Frage selbst. Ein Benutzer, der böse Absichten hat oder einfach nur kreativ in seiner Formulierung ist, kann die Frage so richten, dass das Modell in Richtung SQL verschoben wird, das er nicht hätte schreiben sollen: ein Join mit einer sensiblen Tabelle, ein Filter, der die erwartete Logik umgeht, ein Systemfunktionsaufruf. Das Modell unterscheidet nicht zwischen einer legitimen Frage und einer Frage, die darauf abzielt, sie zu manipulieren.
Das zweite erfordert keine Bosheit. Ein Modell kann einen Tabellennamen halluzinieren, den in der Eingabeaufforderung angeforderten LIMIT vergessen oder einen SELECT * ohne Einschränkungen für eine große Tabelle generieren. Das Ergebnis ist in beiden Fällen dasselbe: potenziell teures oder aufdringliches SQL, das den Eingabeaufforderungsfilter passiert hat und kurz vor der Ausführung gegen eine echte Datenbank steht.
Die Systemaufforderung bleibt nützlich, da sie das Modell in den meisten Fällen zum richtigen Ergebnis führt. Aber ein „Zutritt verboten“-Schild hält niemanden davon ab, der nicht lesen kann oder beschließt, es zu ignorieren. Sie brauchen eine geschlossene Tür hinten, nicht nur eine Platte vorne.
Analysieren Sie die generierte SQL in einen Syntaxbaum, niemals in eine Rohzeichenfolge
Die erste Verteidigungslinie besteht darin, das vom Modell erzeugte SQL mit einem echten Parser für den Zieldialekt zu analysieren und dann die resultierende Struktur und nicht den Rohtext zu validieren. Eine Suche nach verbotenen Wörtern in der Zeichenfolge („DROP“, „DELETE“, „;“) wird trivial umgangen: andere Groß-/Kleinschreibung, in der Mitte eines Schlüsselworts eingefügter Kommentar, eingegebene Anführungszeichen. Ein Syntaxbaum beschreibt eindeutig, was die Abfrage tatsächlich tut.
Aurabase implementiert diesen Schritt mit der Rust-Kiste sqlparser und ihrem Dialekt PostgreSqlDialect. Noch vor dem Parsen weist ein erster lexikalischer Filter zwei Konstruktionen zurück, die im Baum nur schwer richtig zu begründen sind: Dollar-Anführungszeichen ($$...$$), die beliebige Inhalte in einer Zeichenfolge verbergen können, und mehrzeilige Kommentare (/* */), die das tatsächliche Ende einer Anweisung verbergen können.
Allein diese Ablehnung von Multi-Anweisungen blockiert die bekannteste Form der SQL-Injection durch Stapeln: SELECT * FROM users; DROP TABLE users;--. Der Parser gibt nur eine umsetzbare Anweisung zurück, die zweite wird einfach nie erreicht, egal wie sie in der ursprünglichen Frage formuliert ist.
Beschränken Sie sich strukturell auf ein einfaches SELECT
Sobald der Baum erhalten ist, besteht die umfassendste Validierung darin, nur einen Typ von Stammknoten, eine Abfrage (Statement::Query), zu akzeptieren und alles andere abzulehnen: INSERT, UPDATE, DELETE, DROP, CREATE, ALTER. Es handelt sich nicht mehr um eine sofortige Anweisung, sondern um eine Bedingung für den Typ des analysierten Objekts, die durch keine geschickte Formulierung der Frage umgangen werden kann.
Selbst innerhalb eines SELECT bleiben mehrere Konstrukte gefährlich und verdienen ihre eigene ausdrückliche Ablehnung:
| Bau abgelehnt | Warum ist es gefährlich? |
|---|---|
| CTE / MIT | Kann zusätzliche unbeabsichtigte Logik vor dem endgültigen SELECT verketten. |
| Unterabfragen, UNION / INTERSECT / EXCEPT | Erweitert die Oberfläche dessen, was eine einzelne Frage in einer einzelnen Abfrage bewirken kann. |
| AUSWÄHLEN...INTO | Erstellt eine Tabelle: Schreiben als Lesen getarnt. |
| ZUR AKTUALISIERUNG / ZUM TEILEN | Installation von Sperren, Gefahr von Konflikten mit dem Produktionsverkehr. |
| Tabellenfunktionen (generate_series, pg_read_file...) | Systemzugriff oder Denial-of-Service über bei Bedarf generierte Leitungen. |
Ein aus dem Repository entnommener Testfall verdeutlicht den letzten Punkt konkret: SELECT * INTO backup FROM users wird abgelehnt, obwohl es weder sichtbares Schreibschlüsselwort noch verdächtige Funktion enthält. Die Form des Antrags reicht aus, um ihn auszuschließen.
Funktion Whitelist, nicht Blacklist
Eine schwarze Liste verbotener Funktionen (pg_sleep, pg_read_file, dblink...) erfordert, jede gefährliche Funktion einzeln zu antizipieren, während Postgres mehrere Hundert davon offenlegt. Eine Whitelist kehrt die Beweislast um: Nur zehn Funktionen sind autorisiert, count, sum, avg, min, max, lower, upper, coalesce, date_trunc, now. Alles andere ist standardmäßig nicht zulässig, einschließlich einer legitimen Funktion, an deren Hinzufügung noch niemand gedacht hat.
Ein einziger Validierungsdurchlauf reicht nicht immer aus. Bei einer strukturellen Durchquerung des Baums werden die Einstiegspunkte nacheinander aufgelistet (Projektion, WHERE, JOIN, GROUP BY...), und einen vergisst man leicht: Eine verbotene Funktion kann in einer FILTER (WHERE pg_sleep(10) IS NOT NULL)-Klausel, in einem aggregatinternen ORDER BY (sum(id ORDER BY pg_sleep(10))), in WITHIN GROUP, DISTINCT ONoder OFFSETversteckt werden.
Der Aurabase-Validator fügt daher einen zweiten umfassenden Durchgang hinzu, der alle Ausdrücke im Baum durchläuft, wo immer sie sich befinden, unabhängig vom Strukturpfad. Es handelt sich um eine angenommene Tiefenverteidigung: Wenn der erste Durchgang einen Fall verfehlt, holt der zweite den Fall auf.
Binden Sie die zurückgegebenen Zeilen: LIMIT obligatorisch und begrenzt
SELECT * bleibt autorisiert, es ist nützlich für das Data Mining. Das Risiko ist nicht der Star, sondern das Fehlen einer Obergrenze für eine von einem Modell geschriebene Abfrage: Eine schlecht formulierte Frage kann eine ganze Tabelle zurückbringen, mit den damit verbundenen Speicherkosten und Antwortzeiten.
Aurabase wendet eine einfache und transparente Regel an. Wenn die generierte SQL kein LIMIThat, fügt der Server eine hinzu (standardmäßig 100 Zeilen, Wert wird dem Modell in der Systemeingabeaufforderung mitgeteilt). Wenn die SQL einen LIMIT über eine feste Obergrenze (standardmäßig 1000 Zeilen) hinaus anfordert, wird die Abfrage explizit abgelehnt und nicht stillschweigend reduziert. Beide Werte sind serverseitig konfigurierbar (AI_NL2SQL_DEFAULT_LIMIT, AI_NL2SQL_MAX_LIMIT), und der Server verweigert sogar den Start, wenn der Fehler die Obergrenze überschreitet.
Eine Ablehnung statt stillschweigender Kürzungen hat ein direktes Interesse: Eine Obergrenze ohne Angabe von Gründen würde beim Anrufer die Illusion erwecken, dass seiner Bitte entsprochen wurde, während das Ergebnis ohne sein Wissen abgeschnitten worden wäre. limit_injected gibt immer an, ob der Wert vom Modell oder vom Server stammt.
Sperren Sie den Zugriff auf das Schema: Systemkatalog und schemaübergreifend
Zwei unterschiedliche Lecks bedrohen eine NL2SQL-Engine, die mit einer echten Datenbank verbunden ist: Zugriff auf den Postgres-Systemkatalog und Zugriff auf ein Schema, das nicht dem Aufrufer gehört. Beide blockieren bei der Validierung, unabhängig von einer nachgeschalteten RLS-Richtlinie.
pg_catalog ist immer Teil von search_path, was bedeutet, dass ein unqualifizierter Name wie pg_authid oder pg_stat_activity direkt und ohne Präfix darauf zugreift. Der Aurabase-Validator blockiert alle Namen, die mit pg_beginnen, sowie information_schema und das interne Schema aura_console, unabhängig davon, ob sie qualifiziert sind oder nicht.
Bei einem zweikomponentigen Namen (schema.table) ist nur das Schema des aufrufenden Projekts zulässig, alle anderen Werte werden abgelehnt. Ein Name mit drei oder mehr Bestandteilen wird automatisch abgelehnt. Diese Grenze auf der Ebene der generierten Abfrage gilt zusätzlich zur Isolation auf Datenbankebene, die in unserem Artikel überMulti-Tenant-Isolationbeschrieben wird: Eine davon verhindert, dass die generierte SQL auf ein anderes Schema abzielt, die andere verhindert, dass die Verbindung selbst eine andere Datenbank erreicht. Keiner ersetzt den anderen.
Lassen Sie niemals zu, dass der Client das abgefragte Schema neu definiert
Eine diskrete Falle wartet auf jede NL2SQL-API, die einen Parameter akzeptiert, der das Schema oder die in der Client-Abfrage zulässigen Tabellen beschreibt. Wenn derselbe Parameter verwendet wird, um die Eingabeaufforderung zu erstellen und die Ausgabe-SQL zu validieren, kann ein Aufrufer darüber lügen, was zulässig ist, und die Validierung validiert dann anhand dieser Lüge und nicht anhand der Realität der Datenbank.
Aurabase überprüft bei jedem Aufruf das tatsächliche Projektbasisschema mit einem kurzen 30-Sekunden-Cache für die Leistung und lehnt alle im Anforderungstext gesendeten Felder schema, allowed_schemaoder schema_context explizit ab (400-Fehler), anstatt sie zu akzeptieren und dann stillschweigend zu überschreiben. Der Unterschied ist wichtig: Ein Feld, das akzeptiert und dann ignoriert wird, vermittelt die Illusion einer Kontrolle, die nicht existiert; Ein abgelehntes Feld sagt es sofort.
Prüfen Sie Ihre eigene NL2SQL-Pipeline vor der Produktion
Unabhängig davon, ob Sie Aurabase verwenden oder Ihre eigene Pipeline auf Basis eines generischen LLM aufbauen, decken die folgenden Punkte ab, was am häufigsten übersehen wird.
Wenn Sie den Validator selbst schreiben
- Analysieren Sie SQL mit einem echten Parser für Ihren genauen Dialekt, niemals mit Mustervergleich in einer Zeichenfolge.
- Übernehmen Sie eine Standardablehnung: Jeder Knotentyp und jede Funktion, die nicht ausdrücklich autorisiert ist, muss abgelehnt werden, nicht nur die bereits identifizierten gefährlichen Fälle.
- Akzeptieren Sie nur eine Anweisung pro Abfrage. Dies ist die einfachste Ablehnung von Stapelabfragen.
- Testen Sie den Validator mit echten kontradiktorischen Fällen (Funktion verboten in FILTER, in einem intra-aggregierten ORDER BY, in OFFSET), nicht nur mit offensichtlichen Fällen.
- Führen Sie trotz allem das validierte SQL mit einer Postgres-Rolle mit reduzierten Berechtigungen für das erwartete Schema aus: Der Validator begrenzt die Form der Abfrage, die Rolle begrenzt, was sie physisch erreichen kann, wenn Ihnen ein Fall entgangen ist.
Wenn Sie ein NL2SQL-Framework eines Drittanbieters evaluieren
- Fragen Sie explizit, ob die Validierung strukturell (AST) oder nur eine Eingabeaufforderung ist: Die Antwort ändert alles.
- Stellen Sie sicher, dass eine Leitungsobergrenze standardmäßig angewendet wird und nicht nur auf Ihre Kosten als Best Practice dokumentiert wird.
- Prüfen Sie, ob das zur Validierung verwendete Schema vom API-Client bereitgestellt werden kann, wodurch genau der oben beschriebene Fehler erneut geöffnet würde.
- Vergleichen Sie mehrere Tools nach diesem spezifischen Kriterium, bevor Sie sich entscheiden: Unser -Vergleich der NL2SQL-Tools beschreibt detailliert, was die im Jahr 2026 verfügbaren Ansätze auszeichnet.
Der Validator reduziert das Risiko, er ersetzt nicht RLS
Ein solider AST-Validator reduziert das Risiko an der Quelle: Das SQL, das Ihre Datenbank erreicht, hat bereits eine bekannte und begrenzte Form. Es ersetzt jedoch nicht die RLS-Richtlinien für Ihre sensiblen Tabellen, die entscheiden, welche Zeilen ein bestimmter Benutzer sehen darf. Die beiden Schichten beantworten unterschiedliche Fragen: Der Validator begrenzt die Form der generierten Abfrage, der RLS begrenzt die Daten, die er für einen bestimmten Benutzer zurückgeben kann. Halten Sie beide aktiv, auch wenn das eine mit dem anderen überflüssig erscheint.
NL2SQL deckt strukturierte Fragen zu Ihren Tabellen ab. Bei Fragen zu unstrukturierten Inhalten, Dokumenten, Notizen und Tickets folgt das native RAG von Aurabase einer vergleichbaren Sicherheitslogik, die in unserem RAG-Pipeline-Tutorial zu pgvectorausführlich beschrieben wird.