Zum Inhalt springen

DuckDB absichern

DuckDB ist eine leistungsfähige analytische Datenbank-Engine. Sie kann Dateien lesen und schreiben, auf das Netzwerk zugreifen, Erweiterungen laden und Systemressourcen nutzen. Wie bei jedem leistungsfähigen Werkzeug erfordern diese Fähigkeiten eine angemessene Konfiguration, wenn Sie mit sensiblen Daten oder in gemeinsam genutzten Umgebungen arbeiten.

Diese Seite beschreibt DuckDBs Sicherheitsmodell und sicherheitsrelevante Einstellungen. Die richtige Konfiguration hängt von Ihrem Anwendungsfall, Ihrer Umgebung und Ihrem Bedrohungsmodell ab. Wenn Sie DuckDB in Ihre Anwendung einbetten möchten, lesen Sie auch die Seite „DuckDB einbetten“.

Nicht vertrauenswürdige Eingaben

Nicht vertrauenswürdige SQL-Eingaben

Warnung Behandeln Sie SQL in DuckDB wie Code in Bash oder Python. Führen Sie SQL aus nicht vertrauenswürdigen Quellen nicht ohne geeignetes Sandboxing aus.

DuckDB führt SQL mit den vollen Rechten des ausführenden Benutzers aus, ähnlich einer Shell oder eines Skriptinterpreters (etwa bash oder Python). So wie Sie ein nicht vertrauenswürdiges Shell-Skript oder Python-Programm nicht ohne Sandboxing ausführen würden, sollten Sie bei SQL in DuckDB dieselbe Vorsicht walten lassen.

Wenn Ihre Anwendung SQL aus nicht vertrauenswürdigen Quellen ausführen muss, nutzen Sie zusätzliche Schutzmaßnahmen wie bei nicht vertrauenswürdigem Code, zum Beispiel:

  • duckdb-wasm zum Sandboxing
  • DuckDB in einem isolierten Container ausführen (z. B. Docker mit eingeschränkten Capabilities)
  • Eine virtuelle Maschine oder einen separaten Prozess mit minimalen Rechten nutzen
  • Sandboxing auf Betriebssystemebene anwenden
  • Netzwerkisolation, um Datenexfiltration zu verhindern
  • Strikte Query-Timeouts auf Anwendungsebene implementieren

Die auf dieser Seite beschriebenen Einstellungen bieten Defense-in-Depth und können bestimmte Fähigkeiten einschränken, ersetzen aber kein geeignetes Sandboxing. Beachten Sie außerdem, dass Sandboxing nicht nur aus Sicherheitsgründen sinnvoll ist, sondern auch, um Denial-of-Service-(DoS-)Angriffe zu verhindern: Bösartige Eingaben können DuckDB leicht dazu bringen, übermäßig viele Ressourcen wie Speicher, Festplatte, CPU oder Netzwerk zu verbrauchen.

Nicht vertrauenswürdige Nicht-SQL-Eingaben

Warnung Auch Nicht-SQL-Eingaben in DuckDB können leicht unbeabsichtigte Folgen haben. Wenn Sie sicherheitskritische Anwendungen mit DuckDB bauen, müssen Sie die Auswirkungen nicht vertrauenswürdiger Eingaben in DuckDB genau verstehen.

Neben SQL bietet DuckDB mehrere Nicht-SQL-APIs zur Interaktion mit der Datenbank. In Python gibt es beispielsweise eine relationale API, mit der sich Abfragen programmatisch aufbauen lassen.

Diese APIs akzeptieren Benutzereingaben wie Dateipfade, Tabellennamen, Spaltennamen und Filterausdrücke. Sie führen keine rohen SQL-Zeichenketten aus, lösen aber dennoch DuckDB-Operationen aus, die Dateien lesen, auf das Netzwerk zugreifen und Systemressourcen nutzen können.

Beispielhafte Überlegungen zu Nicht-SQL-APIs:

  • Dateipfade: Funktionen wie duckdb.read_csv(path) oder duckdb.read_parquet(path) akzeptieren Dateipfade. Ein vom Angreifer gesteuerter Pfad könnte sensible Dateien lesen (z. B. /etc/passwd) oder Remote-URLs ansprechen.
  • Tabellen- und Spaltennamen: Diese sind in der Regel Identifikatoren und kein ausführbarer Code; unbereinigte Eingaben können aber zu unerwartetem Verhalten oder zur Offenlegung von Informationen führen.
  • Filterausdrücke: Manche APIs akzeptieren Filterausdrücke, die in DuckDB-Ausdrücke kompiliert werden und oft Unterabfragen mit beliebigem SQL unterstützen. Behandeln Sie diese mit derselben Vorsicht wie SQL.

Empfehlungen:

  • Validieren und bereinigen Sie alle vom Benutzer gelieferten Eingaben, bevor Sie sie an DuckDB-APIs übergeben.
  • Wenden Sie dieselben Sandboxing-Prinzipien wie bei nicht vertrauenswürdigem SQL an, wenn Sie Eingaben aus nicht vertrauenswürdigen Quellen akzeptieren.
  • Lesen Sie die Dokumentation aller verwendeten Funktionen sorgfältig, um zu verstehen, ob eine Funktion in Ihrem konkreten Anwendungsfall mit nicht vertrauenswürdigen Eingaben sicher ist.

Erweiterungen

DuckDB hat einen flexiblen Erweiterungsmechanismus, der Funktionen wie neue Dateiformate, Funktionen und Remote-Dateisystemzugriff hinzufügt. Erweiterungen laufen mit denselben Rechten wie der DuckDB-Prozess selbst und verdienen daher in sicherheitskritischen Umgebungen besondere Aufmerksamkeit.

Automatisches Laden

DuckDB kann Kern-Erweiterungen automatisch laden, wenn bestimmte SQL-Anweisungen sie benötigen. Um die volle Kontrolle darüber zu behalten, welche Erweiterungen geladen werden, können Sie das automatische Laden deaktivieren:

SET autoload_known_extensions = false;
SET autoinstall_known_extensions = false;

Kern- vs. Community-Erweiterungen

DuckDB-Erweiterungen fallen in zwei Kategorien:

  • Kern-Erweiterungen: Werden vom DuckDB-Team gepflegt und vollständig unterstützt. Dazu gehören Erweiterungen wie parquet, json und httpfs.
  • Community-Erweiterungen: Werden von Dritten beigesteuert und über INSTALL extension_name FROM community installiert. Sie werden nicht vom DuckDB-Team gepflegt; installieren Sie Community-Erweiterungen daher nur aus Quellen, denen Sie vertrauen.

Um Community-Erweiterungen vollständig zu deaktivieren:

SET allow_community_extensions = false;

Schwachstellen melden

Wenn Sie eine mögliche Schwachstelle entdecken, melden Sie sie vertraulich über GitHub.

Einstellungen zur Einschränkung der DuckDB-Funktionen

Die in diesem Abschnitt dokumentierten Einstellungen bieten zusätzliche Härtung für DuckDB-Deployments. Sie sollten jedoch nicht in allen Konfigurationen als umfassende Sicherheitsmechanismen verstanden werden. Diese Einstellungen sind als Defense-in-Depth-Maßnahmen gedacht, um die Auswirkungen möglicher Sicherheitsprobleme zu begrenzen. Sie können keinen vollständigen Schutz gegen alle Angriffsvektoren bieten, insbesondere beim Ausführen von nicht vertrauenswürdigem SQL. Für robuste Sicherheit bei nicht vertrauenswürdigen Eingaben kombinieren Sie diese Einstellungen mit geeignetem Sandboxing auf Betriebssystem- oder Containerebene, wie im Abschnitt „Nicht vertrauenswürdige SQL-Eingaben“ beschrieben.

Safe Mode (CLI)

Der CLI-Client von DuckDB unterstützt den „Safe Mode“, der DuckDB den Zugriff auf externe Dateien außer der Datenbankdatei untersagt. Er lässt sich über ein Kommandozeilenargument oder einen Dot-Befehl aktivieren:

Terminal window
duckdb -safe ...
.safe_mode

Dateizugriff einschränken

DuckDB kann Verzeichnisse auflisten und beliebige Dateien über die read_csv-Funktion des CSV-Parsers lesen oder Text über die read_text-Funktion einlesen. Dadurch ist das Lesen aus dem lokalen Dateisystem möglich, zum Beispiel:

SELECT *
FROM read_csv('/etc/passwd', sep = ':');

Dateizugriff deaktivieren

Dateizugriff lässt sich auf zwei Arten deaktivieren. Erstens können Sie einzelne Dateisysteme deaktivieren. Zum Beispiel:

SET disabled_filesystems = 'LocalFileSystem';

Zweitens können Sie den externen Zugriff vollständig deaktivieren, indem Sie die Option enable_external_access auf false setzen.

SET enable_external_access = false;

Diese Einstellung bedeutet:

  • ATTACH kann keine Datenbank in einer Datei anhängen.
  • COPY kann nicht aus Dateien lesen oder in Dateien schreiben.
  • Funktionen wie read_csv, read_parquet, read_json usw. können nicht aus einer externen Quelle lesen.

Die Optionen allowed_directories und allowed_paths

Sie können DuckDBs Zugriff auf bestimmte Verzeichnisse oder Dateien mit den Optionen allowed_directories bzw. allowed_paths einschränken. Diese Optionen ermöglichen eine feingranulare Zugriffskontrolle für das Dateisystem. Sie können DuckDB beispielsweise so setzen, dass nur das Verzeichnis /tmp genutzt wird.

SET allowed_directories = ['/tmp'];
SET enable_external_access = false;
FROM read_csv('test.csv');

Mit dieser Einstellung verweigert DuckDB das Lesen von Dateien im aktuellen Arbeitsverzeichnis:

Terminal window
Permission Error:
Cannot access file "test.csv" - file system operations are disabled by configuration

Konfigurationen sperren

Sicherheitsrelevante Konfigurationseinstellungen sperren sich in der Regel aus Sicherheitsgründen selbst. Wir können beispielsweise Community-Erweiterungen mit SET allow_community_extensions = false deaktivieren, sie aber danach nicht wieder aktivieren, ohne die Datenbank neu zu starten. Der Versuch führt zu einem Fehler:

Terminal window
Invalid Input Error:
Cannot upgrade allow_community_extensions setting while database is running

So wird verhindert, dass explizit deaktivierte Einstellungen wieder aktiviert werden.

Viele Konfigurationseinstellungen sperren sich jedoch nicht selbst, etwa Ressourcenbeschränkungen. Wenn Sie Benutzer unbeschränkt SQL auf Ihrer Hardware ausführen lassen, sollten Sie die Konfiguration nach Abschluss Ihrer eigenen Einstellungen mit folgendem Befehl sperren:

SET lock_configuration = true;

Ab diesem Zeitpunkt können keine Konfigurationseinstellungen mehr geändert werden.

Damit bestimmte Einstellungen auch bei aktiviertem lock_configuration konfigurierbar bleiben, nutzen Sie die Option allowed_configs:

SET allowed_configs = ['memory_limit', 'threads'];
SET lock_configuration = true;

Mit dieser Konfiguration können memory_limit und threads weiterhin geändert werden, alle anderen Einstellungen sind gesperrt.

Secrets

Secrets verwalten Anmeldedaten für Drittanbieterdienste wie AWS oder Azure. DuckDB kann eine Liste der Secrets mit der Tabellenfunktion duckdb_secrets() anzeigen. Sensible Informationen wie Sicherheitsschlüssel werden dabei standardmäßig geschwärzt. Die Option allow_unredacted_secrets kann gesetzt werden, um alle in einem Sicherheitsschlüssel enthaltenen Informationen anzuzeigen. Es wird empfohlen, diese Option nicht zu aktivieren, wenn Sie nicht vertrauenswürdiges SQL ausführen.

Abfragen können auf die im Secrets Manager definierten Secrets zugreifen. Ist beispielsweise ein Secret definiert, das einen Benutzer authentifiziert, der Schreibrechte auf einen bestimmten AWS-S3-Bucket hat, können Abfragen in diesen Bucket schreiben. Das gilt sowohl für persistente als auch für temporäre Secrets.

Persistente Secrets werden unverschlüsselt im Binärformat auf der Festplatte gespeichert. Sie haben dieselben Berechtigungen wie SSH-Schlüssel, 600, d. h. nur der Benutzer, der den DuckDB-(Eltern-)Prozess ausführt, kann sie lesen und schreiben.

Prepared Statements gegen SQL-Injection

Wie bei anderen SQL-Datenbanken wird empfohlen, in DuckDB Prepared Statements zu verwenden, um SQL-Injection zu verhindern.

Wichtig Prepared Statements schützen vor SQL-Injection, wenn Sie die Abfragestruktur kontrollieren, aber nicht vertrauenswürdige Datenwerte akzeptieren (z. B. vom Benutzer gelieferte Suchbegriffe oder IDs). Können Benutzer die SQL-Abfrage selbst liefern, entspricht das der Erlaubnis, beliebigen Code auszuführen – siehe „Nicht vertrauenswürdige SQL-Eingaben“.

Vermeiden Sie daher das Konkatenieren von Zeichenketten für Abfragen:

import duckdb
duckdb.execute("SELECT * FROM (VALUES (32, 'a'), (42, 'b')) t(x) WHERE x = " + str(42)).fetchall()

Nutzen Sie stattdessen Prepared Statements:

import duckdb
duckdb.execute("SELECT * FROM (VALUES (32, 'a'), (42, 'b')) t(x) WHERE x = ?", [42]).fetchall()

Ressourcennutzung begrenzen

DuckDB kann beträchtlich viel CPU, RAM und Festplattenspeicher nutzen. Diese Ressourcen lassen sich begrenzen, um die Nutzung der DuckDB-Instanz zu steuern.

Die Anzahl der CPU-Threads, die DuckDB nutzen darf, setzen Sie beispielsweise so:

SET threads = 4;

Dabei ist 4 die Anzahl der erlaubten Threads.

Auch der maximale Speicher (RAM) lässt sich begrenzen, zum Beispiel:

SET memory_limit = '4GB';

Die Größe des temporären Dateiverzeichnisses begrenzen Sie mit:

SET max_temp_directory_size = '4GB';

Berechtigungen

Führen Sie DuckDB nicht als Root-Benutzer aus (z. B. mit sudo). Es gibt keinen guten Grund, DuckDB als Root auszuführen.