SQL-Injection in Prisma – Praktischer Leitfaden zur Härtung von Datenbanken

Schritt für Schritt zeigen wir, wie man Prisma und TypeScript vor SQL-Injection schützt und die Anforderungen von OWASP Top 10 erfüllt.

SQL injection w Prisma – praktyczny przewodnik hardeningu baz danych

SQL‑Injection in Prisma ist eine der häufigsten Schwachstellen, die die Datenintegrität und Vertraulichkeit einer Anwendung gefährden können. In diesem Artikel stellen wir ein kurzes Bedrohungsmodell, die Funktionsweise von Prisma, einen Vergleich von anfälligem und verbessertem Code, eine Checkliste zur Minderung sowie Verweise auf anerkannte Standards wie OWASP Top 10, CWE und das Prinzip der geringsten Rechte vor.

Bedrohungsmodell – wie SQL‑Injection entsteht

Ein Angreifer injiziert eigenen SQL‑Code anstelle von Eingabedaten, die die Anwendung ohne angemessene Validierung oder Parametrisierung an die Datenbank übergibt. Im Kontext von Prisma geschieht dies meist über die Methoden queryRaw oder executeRaw, die das manuelle Einfügen von Query‑Fragmenten erlauben. Wenn wir ihnen nicht verifizierte Zeichenketten übergeben, öffnen wir die Tür für Manipulationen der Abfrage.

Grundlegendes Szenario:

  • Ein Benutzer gibt einen Wert in ein Formular ein (z. B. Produktname).
  • Die Anwendung erstellt eine SQL‑Abfrage und fügt diesen Wert ohne Parametrisierung ein.
  • Der Angreifer fügt die Anweisung OR 1=1 oder DROP TABLE hinzu, was zu unautorisiertem Zugriff oder Datenzerstörung führt.

Schutzmechanismus in Prisma – Parametrisierung und Typisierung

Prisma ORM generiert standardmäßig Abfragen mittels vorbereiteter Anweisungen (prepared statements). Dadurch werden Werte als Parameter übergeben und nicht direkt in den SQL‑Text eingefügt. In TypeScript nutzen wir zusätzlich Typen, die die Möglichkeit einer unerwünschten Code‑Injection einschränken.

Wesentliche Mechanismen:

  • Query Builder – Methoden wie findMany, create oder update erzeugen Abfragen sicher.
  • Parametrisierte RAW – prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}` verwendet tag‑basierte Interpolation, die die Variable automatisch bereinigt.
  • Prisma‑Typen – definieren die Datenstruktur und erzwingen das korrekte Eingabeformat.

Beispiel: anfälliger Code vs. verbesserter Code

Unten vergleichen wir zwei Code‑Snippets – zuerst das gefährliche, dann das sichere.

// --- Anfälliger Code ---
const userInput = req.body.username; // Daten aus dem Formular
const raw = `SELECT * FROM "User" WHERE username = '${userInput}'`;
const result = await prisma.$queryRaw(raw);

Im obigen Beispiel wird userInput direkt in die Zeichenkette eingefügt, was eine beliebige SQL‑Injection ermöglicht.

// --- Verbesserter Code ---
const userInput = req.body.username;
// Tag‑basierte Interpolation sorgt für Parametrisierung
const result = await prisma.$queryRaw`SELECT * FROM "User" WHERE username = ${userInput}`;

Tag‑basierte Interpolation (prisma.$queryRaw`...`) wandelt ${userInput} in einen gebundenen Parameter um und eliminiert das Risiko einer Injection.

Checkliste zur Minderung – was im Projekt umzusetzen ist

  • Verwende ausschließlich Prisma‑API‑Methoden (findUnique, create usw.) statt manueller RAW‑Abfragen.
  • Falls RAW unvermeidlich ist, nutze tag‑basierte Interpolation oder übergebe Parameter als zweites Argument (prisma.$queryRaw(sql, params)).
  • Aktiviere die Validierung des Eingabeschchemas (z. B. zod oder class-validator) bevor Daten an die Datenbank‑Zugriffsschicht übergeben werden.
  • Begrenze die Berechtigungen des von Prisma genutzten DB‑Kontos – Prinzip der geringsten Rechte.
  • Überwache SQL‑Logs und erkenne unerwartete Muster (z. B. plötzliches Auftreten von DROP).

Verweise auf Standards – OWASP, CWE und least‑privilege

OWASP Top 10 listet A03:2021 – Injection als eine der gravierendsten Kategorien. Im CWE‑Katalog ist das zugehörige Problem CWE‑89: SQL Injection. Durch die Umsetzung der genannten Praktiken erfüllen wir die Anforderungen beider Standards.

Das Prinzip der geringsten Rechte verlangt, dass das von Prisma genutzte Datenbankkonto nur die unbedingt notwendigen Berechtigungen (SELECT, INSERT, UPDATE, DELETE für die erforderlichen Tabellen) besitzt. Vermeide die Vergabe der Rolle SUPERUSER oder DBA an die Produktionsanwendung.

„Sichere Abfragen sind kein Add‑On, sie sind das Fundament – Code, der nicht injiziert werden kann, erfordert keine nachträglichen Korrekturen.“

Typische Fehler und Kompromisse in der Praxis

Häufige Fallen:

  • Verwendung von prisma.$executeRaw ohne Parametrisierung – leicht zu übersehen, besonders bei Migrationen.
  • Dynamisches Erzeugen von Tabellen‑ oder Spaltennamen – Prisma erlaubt keine Parametrisierung von Identifikatoren, daher müssen diese in einer Whitelist validiert werden.
  • Verzicht auf Eingabevalidierung zugunsten von „Vertrauen“ in das Frontend – führt zu unvorhergesehenen Angriffsvektoren.

Kompro­mise:

  • In manchen Fällen ist es notwendig, RAW für komplexe Berichte zu verwenden. Dann sollte diese Ebene in einen separaten Service ausgelagert und mit einer zusätzlichen Sanitisationsebene umschlossen werden.
  • Wenn die Anwendung Ad‑hoc‑Abfragen unterstützen muss, sollte anstelle von freiem Texteinfügen eine Whitelist zulässiger Felder und Operatoren in Betracht gezogen werden.

Praktisches Beispiel – Implementierungs‑Checkliste

// checklista.ts – Beispielimplementierung in TypeScript
import { PrismaClient } from '@prisma/client';
import { z } from 'zod';

const prisma = new PrismaClient();

// 1. Eingabe‑Validierungsschema
const userSchema = z.object({
  username: z.string().min(3).max(30),
  email: z.string().email(),
});

export async function createUser(payload: unknown) {
  // 2. Validierung
  const data = userSchema.parse(payload);

  // 3. Sicherer Einsatz der Prisma‑API – kein RAW
  return await prisma.user.create({
    data: {
      username: data.username,
      email: data.email,
    },
  });
}

// 4. Beispiel für RAW mit Parametrisierung
export async function findUsersByDomain(domain: string) {
  const safeDomain = domain.replace(/[^a-zA-Z0-9.-]/g, ''); // zusätzliche Sanitisation
  return await prisma.$queryRaw`
    SELECT * FROM "User" WHERE email LIKE ${'%@' + safeDomain}`;
}

Der obige Code zeigt, wie man Schema‑Validierung, die Nutzung einer sicheren API und parametrisiertes RAW in den Situationen kombiniert, die es erfordern.

Fazit und Einladung zur Zusammenarbeit

Durch die Anwendung der beschriebenen Praktiken – Parametrisierung, Typisierung, Validierung und Rechte‑Beschränkung – eliminierst du das Risiko von SQL‑Injection in Projekten, die auf Prisma und TypeScript basieren, und erfüllst gleichzeitig die Anforderungen von OWASP Top 10 sowie CWE‑89. Wenn du eine Sicherheits‑Audit, Unterstützung beim Hardening der Datenbank oder Hilfe bei der Implementierung von Best Practices benötigst, kontaktiere Coderia.it – unser Expertenteam hilft dir, eine robuste und sichere Backend‑Architektur aufzubauen.

Loslegen

Ein Projekt im Kopf?

Beschreiben Sie es in wenigen Sätzen. Ich antworte innerhalb von 24 Stunden mit Angebot und Stack-Vorschlag.