SQL injection w Prisma to problem, który może pojawić się nawet przy nowoczesnych ORM‑ach, jeśli nie zastosujemy odpowiednich praktyk. W tym artykule przedstawiamy model zagrożenia, mechanizmy działania Prisma, porównanie podatnego i poprawionego kodu oraz checklistę mitygacji opartą o OWASP Top 10, CWE i zasadę least‑privilege.
Model zagrożenia – jak powstaje SQL injection
Atak SQL injection polega na wstrzyknięciu nieautoryzowanego fragmentu języka SQL do zapytania generowanego przez aplikację. W kontekście Prisma najczęściej dochodzi do tego, gdy programista korzysta z tzw. raw queries lub interpoluje zmienne w stringach bez walidacji. Mechanizm Prisma sam w sobie sanitizuje parametry przekazywane jako obiekty, ale nie chroni przed niebezpiecznym użyciu prisma.$queryRaw czy prisma.$executeRaw z niewłaściwym formatowaniem.
Jak Prisma i TypeScript pomagają w eliminacji ryzyka
Prisma oferuje dwa poziomy ochrony: statyczny (typy TypeScript) oraz runtime (parametryzowane zapytania). Typy zapewniają, że pola przekazywane do zapytań istnieją w schemacie, a runtime automatycznie zamienia wartości na parametry bindowane, co eliminuje możliwość wstrzyknięcia kodu SQL. Kluczowe jest jednak konsekwentne używanie metod findUnique, findMany, create etc., zamiast ręcznego budowania zapytań.
Przykład: podatny vs. poprawiony kod
Poniżej prezentujemy dwa fragmenty – pierwszy narusza zasady bezpieczeństwa, drugi wykorzystuje pełny potencjał Prisma i TypeScript.
// podatny kod – użycie $queryRaw z interpolacją stringa
const userId = req.query.id; // pochodzące od użytkownika
const result = await prisma.$queryRaw(`SELECT * FROM "User" WHERE id = ${userId}`);
W powyższym przykładzie wartość userId jest wstawiana bezpośrednio do zapytania, co umożliwia atakującemu podmianę na 1; DROP TABLE "User";. Poprawny sposób to użycie parametrów bindowanych:
// poprawiony kod – parametr bindowany
const userId = Number(req.query.id);
if (Number.isNaN(userId)) {
throw new Error('Invalid user id');
}
const result = await prisma.$queryRaw`
SELECT * FROM "User" WHERE id = ${userId}`;
Prisma automatycznie zamienia ${userId} na placeholder $1 i przesyła wartość osobno, co eliminuje możliwość wstrzyknięcia.
Checklist mitygacji – co zrobić, by nie popełnić błędu
- Używaj wyłącznie metod ORM (find*, create*, update*, delete*) zamiast
$queryRawi$executeRaw. - Gdy musisz użyć raw query, zawsze stosuj parametryzację (
prisma.$queryRaw`...${value}`). - Waliduj i konwertuj wszystkie dane wejściowe (np.
Number(),zod,class‑validator). - Włącz w bazie minimalne uprawnienia (least‑privilege) – konto Prisma nie powinno mieć uprawnień DDL.
- Regularnie skanuj kod pod kątem CWE‑89 (SQL Injection) przy pomocy SAST.
Odwołania do standardów – OWASP, CWE i zasada least‑privilege
OWASP Top 10 klasyfikuje SQL injection jako A03 – „Injection”. CWE‑89 opisuje dokładnie technikę wstrzykiwania oraz rekomendowane środki zaradcze, w tym użycie przygotowanych instrukcji i unikanie dynamicznego budowania zapytań. Zasada least‑privilege wymusza przydzielenie kontu bazy minimalnych uprawnień – w praktyce konto Prisma powinno mieć jedynie SELECT, INSERT, UPDATE, DELETE na potrzebnych tabelach.
„Bezpieczeństwo nie jest jednorazowym testem, a ciągłym procesem – każdy nowy fragment kodu to potencjalny wektor ataku.”
Typowe błędy i kompromisy
Najczęstszy błąd to uzależnienie się od „magicznych” stringów w logice biznesowej i późniejsze ich wklejanie do raw queries. Inny problem – brak walidacji typów przy konwersji danych wejściowych, co prowadzi do nieoczekiwanych NaN i w konsekwencji do fallbacku na stringi. Kompromisem może być użycie prisma.$queryRawUnsafe w sytuacjach, gdy nie ma alternatywy, ale wtedy należy ręcznie zapewnić sanitację i ograniczyć dostęp do takiej funkcji do jednego, dobrze przetestowanego modułu.
Praktyczna checklista wdrożeniowa
- Audyt kodu pod kątem użycia
$queryRawi$executeRaw. - Wymuś typowanie wszystkich parametrów w TypeScript (np.
type UserId = number). - Skonfiguruj Prisma schema z odpowiednimi rolami –
@@mapi@@idnie muszą być modyfikowane w runtime. - Wdroż testy integracyjne, które próbują wstrzyknąć złośliwe ciągi do endpointów.
- Ustaw reguły CI/CD, które blokują merge przy wykryciu CWE‑89 w wynikach SAST.
Stosując powyższe praktyki, zminimalizujesz ryzyko SQL injection w aplikacjach Node.js korzystających z Prisma i TypeScript, a jednocześnie utrzymasz wysoką wydajność i czytelność kodu.
Jeśli potrzebujesz wsparcia przy hardeningu warstwy danych, audycie bezpieczeństwa lub wdrożeniu CI/CD zgodnego z OWASP, skontaktuj się z Coderia.it – pomożemy Ci zbudować solidne i bezpieczne rozwiązania backendowe.



