FlawOpen

flawopen.com/Inyección SQL en JavaScript/Prisma

¿Es seguro Prisma $queryRaw frente a SQL Injection?

Guía de referencia
Respuesta breve

Piensa en un parámetro como un campo sellado de un formulario SQL: la base de datos trata el valor como dato, no como sintaxis. El tagged template $queryRaw enlaza los valores interpolados. $queryRawUnsafe también puede enlazar valores si recibe placeholders y argumentos; el riesgo aparece al concatenar texto no confiable para construir SQL. Ninguno de los dos métodos parametriza nombres de tablas o columnas.

INSEGURO — concatenar la entrada en SQL
const userId = request.query.userId;
const query =
  `SELECT id FROM users WHERE id = ${userId}`;
const rows = await prisma.$queryRawUnsafe(query);
PROTEGIDO — enlazar valores y permitir estructura con una allowlist
const rows = await prisma.$queryRaw`
  SELECT id FROM users WHERE id = ${userId}
`;

// PostgreSQL example: $1 binds data, not an identifier.
const columns = { name: 'name', created: 'created_at' } as const;
const column = columns[requestedSort as keyof typeof columns] ?? 'created_at';
const pageSize = 25;
const sortedRows = await prisma.$queryRawUnsafe(
  `SELECT id FROM users ORDER BY ${column} LIMIT $1`,
  pageSize
);
// The selected SQL structure comes from a fixed map.

Qué hacen los parámetros de Prisma — y qué no hacen

En $queryRaw, usa directamente la llamada tagged template: cada valor interpolado se convierte en un parámetro de la base de datos. No construyas primero una cadena SQL para pasarla como único argumento. Prisma también admite placeholders con $queryRawUnsafe(query, ...values); así se pueden enlazar valores, pero el texto SQL debe ser confiable. Los parámetros representan datos, no identificadores, operadores ni fragmentos SQL. Asigna cada columna seleccionable a una allowlist fija controlada por la aplicación. Prisma recomienda TypedSQL para muchos casos de consultas raw con seguridad de tipos.

Cómo auditar consultas raw de Prisma

grep -rn "\$queryRawUnsafe\|\$executeRawUnsafe" --include="*.ts" --include="*.js" .

Preguntas frecuentes

¿Por qué existe $queryRawUnsafe?

Acepta cadenas SQL raw y puede usar placeholders si los valores se pasan por separado. Su flexibilidad facilita construir cadenas de forma insegura; revisa conjuntamente el texto SQL y los argumentos. No hace seguros los identificadores dinámicos: selecciónalos mediante una allowlist fija.

Referencias

Véase también Inyección SQL (CWE-89): cómo funciona y cómo evitarla en cada lenguaje — flawopen.com ¿Es segura la interpolación en where() de Rails? ¿Sequelize query() es seguro frente a SQL Injection? ¿SQLAlchemy text() es seguro frente a SQL Injection? ¿La verificación de consultas de sqlx en compilación evita la inyección SQL? ¿Los procedimientos almacenados evitan la inyección SQL? ¿El QueryBuilder de TypeORM es seguro frente a SQL Injection?