SQL injection in Prisma – guida pratica per l'hardening dei database

Passo dopo passo mostreremo come proteggere Prisma e TypeScript da SQL injection e soddisfare i requisiti OWASP Top 10.

SQL injection w Prisma – praktyczny przewodnik hardeningu baz danych

SQL injection in Prisma è una delle vulnerabilità più comuni, che può compromettere l'integrità dei dati e la riservatezza dell'applicazione. In questo articolo presentiamo un breve modello di minaccia, i meccanismi di funzionamento di Prisma, il confronto tra codice vulnerabile e corretto, una checklist di mitigazione e riferimenti a standard riconosciuti, come OWASP Top 10, CWE e il principio del least‑privilege.

Modello di minaccia – come si genera SQL injection

L'attaccante inietta codice SQL proprio nei dati di input che l'applicazione passa al database senza una corretta validazione o parametrizzazione. Nel contesto di Prisma ciò avviene più spesso usando i metodi queryRaw o executeRaw, che consentono di inserire manualmente frammenti di query. Se vi passiamo stringhe non verificate, apriamo la porta alla manipolazione della query.

Scenario di base:

  • L'utente fornisce un valore in un modulo (ad esempio il nome del prodotto).
  • L'applicazione costruisce una query SQL inserendo questo valore senza parametrizzazione.
  • L'attaccante aggiunge l'istruzione OR 1=1 o DROP TABLE, provocando accesso non autorizzato o distruzione dei dati.

Meccanismo di protezione in Prisma – parametrizzazione e tipizzazione

Prisma ORM genera di default le query utilizzando prepared statements. In questo modo i valori vengono passati come parametri, anziché inseriti direttamente nel testo SQL. In TypeScript, inoltre, utilizziamo i tipi, che limitano la possibilità di iniettare codice indesiderato.

Meccanismi chiave:

  • Query Builder – metodi come findMany, create o update costruiscono le query in modo sicuro.
  • RAW parametrizzato – prisma.$queryRaw`SELECT * FROM User WHERE email = ${email}` usa l'interpolazione taggata, che sanitizza automaticamente la variabile.
  • Tipi Prisma – definiscono la struttura dei dati e impongono il formato corretto dell'input.

Esempio: codice vulnerabile vs codice corretto

Di seguito confrontiamo due frammenti – prima quello pericoloso, poi quello sicuro.

// --- Codice vulnerabile ---
const userInput = req.body.username; // dati dal modulo
const raw = `SELECT * FROM "User" WHERE username = '${userInput}'`;
const result = await prisma.$queryRaw(raw);

Nel esempio sopra userInput viene inserito direttamente nella stringa, consentendo l'iniezione di qualsiasi SQL.

// --- Codice corretto ---
const userInput = req.body.username;
// l'interpolazione taggata garantisce la parametrizzazione
const result = await prisma.$queryRaw`SELECT * FROM "User" WHERE username = ${userInput}`;

L'interpolazione taggata (prisma.$queryRaw`...`) trasforma ${userInput} in un parametro bindato, eliminando il rischio di injection.

Checklist di mitigazione – cosa implementare nel progetto

  • Utilizza esclusivamente i metodi dell'API Prisma (findUnique, create ecc.) invece di query RAW manuali.
  • Se RAW è indispensabile, usa l'interpolazione taggata o passa i parametri come secondo argomento (prisma.$queryRaw(sql, params)).
  • Abilita la validazione dello schema di input (ad esempio zod o class-validator) prima di inviare i dati al livello di accesso al database.
  • Limita i privilegi dell'account DB usato dall'applicazione – principio del least‑privilege.
  • Monitora i log SQL e rileva pattern inattesi (ad esempio l'uso improvviso di DROP).

Riferimenti agli standard – OWASP, CWE e least‑privilege

OWASP Top 10 elenca A03:2021 – Injection come una delle categorie più gravi. Nel catalogo CWE, il problema corrispondente è CWE‑89: SQL Injection. Implementando le pratiche sopra, soddisfiamo i requisiti di entrambi gli standard.

Il principio del least‑privilege richiede che l'account del database utilizzato da Prisma possieda solo i permessi necessari (SELECT, INSERT, UPDATE, DELETE sulle tabelle richieste). Evita di concedere il ruolo SUPERUSER o DBA all'applicazione in produzione.

«Le query sicure non sono un optional, sono la base – un codice che non può essere iniettato non richiede correzioni successive.»

Errori comuni e compromessi nella pratica

Le trappole più frequenti:

  • Uso di prisma.$executeRaw senza parametrizzazione – facile da trascurare, soprattutto durante le migrazioni.
  • Costruzione dinamica di nomi di tabelle o colonne – Prisma non consente la parametrizzazione degli identificatori, quindi è necessario validarli tramite whitelist.
  • Abbandono della validazione dell'input a favore della “fiducia” nel frontend – porta a vettori di attacco imprevisti.

Compromessi:

  • In alcuni casi è necessario utilizzare RAW per report complessi. In tal caso è consigliabile isolare questo livello in un servizio separato e avvolgerlo con un ulteriore strato di sanitizzazione.
  • Se l'applicazione deve gestire query ad‑hoc, considera l'uso di una whitelist di campi e operatori consentiti invece di inserire liberamente il testo.

Esempio pratico – checklist di implementazione

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

const prisma = new PrismaClient();

// 1. Schema di validazione dell'input
const userSchema = z.object({
  username: z.string().min(3).max(30),
  email: z.string().email(),
});

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

  // 3. Uso sicuro dell'API Prisma – non RAW
  return await prisma.user.create({
    data: {
      username: data.username,
      email: data.email,
    },
  });
}

// 4. Esempio RAW con parametrizzazione
export async function findUsersByDomain(domain: string) {
  const safeDomain = domain.replace(/[^a-zA-Z0-9.-]/g, ''); // sanitizzazione aggiuntiva
  return await prisma.$queryRaw`
    SELECT * FROM "User" WHERE email LIKE ${'%@' + safeDomain}`;
}

Il codice sopra dimostra come combinare la validazione dello schema, l'uso di un'API sicura e il RAW parametrizzato nei casi in cui è necessario.

Riepilogo e invito alla collaborazione

Applicando le pratiche descritte – parametrizzazione, tipizzazione, validazione e limitazione dei privilegi – elimini il rischio di SQL injection nei progetti basati su Prisma e TypeScript, soddisfacendo al contempo i requisiti di OWASP Top 10 e CWE‑89. Se hai bisogno di un audit di sicurezza, supporto per l'hardening del database o assistenza nell'adozione delle migliori pratiche, contatta Coderia.it – il nostro team di specialisti ti aiuterà a costruire un'architettura backend solida e sicura.

Cominciamo

Hai un progetto in mente?

Descrivilo in poche righe: rispondo entro 24 ore con un preventivo gratuito e una proposta di stack.