Saltar al contenido

29 · Base de Datos

Protección contra SQL Injection

Las interpolaciones en sql"..." son siempre parámetros vinculados — los metacaracteres SQL en el valor son literales, nunca ejecutados.

En esta página

El SQL injection ocurre cuando un valor externo es concatenado en la cadena de la query antes de llegar a la base de datos. Al usar sql"...", Zolo nunca concatena: toda interpolación {expr} se convierte en un ? posicional y el valor se envía por separado a través del driver. La base de datos recibe la estructura de la query por un canal y los datos por otro — los metacaracteres SQL en el valor se tratan como texto, no como código.

El payload clásico '; DROP TABLE users; -- se inserta como variable en una query sql"...". La tabla permanece intacta y no se encuentra ninguna fila.

08-injection-safe.zolo
Playground
// Feature: `sql"..."` interpolations are *bound parameters*, not concatenated

// Syntax: `sql"SELECT ... WHERE x = {evil}"` — at compile time the

// `{evil}` becomes `?` and the value is sent as a parameter. SQL

// metacharacters in the value are literal, not parsed.

// When to use: ALWAYS. Never build queries with `+` or interpolation

// outside `sql"..."`. This file demonstrates why.


use std::database::Database

let db = Database.open("sqlite://:memory:")?
defer db.close()

db.execute(sql"CREATE TABLE users (name TEXT)")?
db.execute(sql"INSERT INTO users VALUES ('alice')")?
db.execute(sql"INSERT INTO users VALUES ('bob')")?

// The classic injection payload — in a string-concat builder it

// would terminate the query, drop the table, and comment out the rest.

// Inside `sql"..."` it's just a string parameter that doesn't match.

let evil = "'; DROP TABLE users; --"
let rows = sql"SELECT name FROM users WHERE name = {evil}".query(db)?
var count = 0
for _ in rows { count = count + 1 }
print("matched: {count}")

// expected: matched: 0


// Proof: the table is still there, both rows intact.

let total = sql"SELECT COUNT(*) FROM users".scalar(db)?
print("total: {total}")

// expected: total: 2


db.query("SELECT * FROM users") ?> .each(|u| print(u.name))

Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.

La regla práctica es simple:

  • Usa sql"..." (o ? + bindings) siempre que un valor provenga de fuera del código fuente.
  • Nunca construyas queries con + ni con interpolación fuera del literal sql"...".

Desafío

Intenta construir la misma query sin sql"..." usando concatenación de cadenas y observa qué ocurre con la tabla. ¿Qué mensaje de error emite Zolo?

Índice global

Encuentra tu camino por Zolo

Prueba una idea

Empieza aquí

9 resultados

9 resultados

enespt-br