Rust contra inyecciones SQL y XSS: escribiendo web de forma segura

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué Rust es el nuevo estándar de seguridad en la web?

\n

Cuando se trata de seguridad web, muchos desarrolladores piensan inmediatamente en ORM, consultas preparadas y escape de HTML. Pero, ¿y si le dijera que el propio lenguaje de programación puede asumir la mayor parte de este trabajo? Eso es exactamente lo que hace Rust: un lenguaje que no perdona errores, pero tampoco permite cometerlos.

\n\n

En este artículo, analizaremos cómo la seguridad de Rust se manifiesta en los dos ataques más críticos a aplicaciones web: inyecciones SQL y XSS (Cross-Site Scripting). Verá ejemplos de código reales, una comparación con Python y comprenderá por qué Rust se está convirtiendo en la opción número uno para proyectos donde el precio del error es la seguridad del usuario.

\n\n

Cómo Rust previene las inyecciones SQL: de la teoría a la práctica

\n

La inyección SQL es un clásico. Todos sabemos que debemos usar consultas preparadas. Pero en Rust, este patrón está integrado en la cultura del lenguaje a nivel de tipos y del sistema borrow checker.

\n\n

Comparación de enfoques: Python vs Rust

\n

Mire este código típico en Python que podría ser vulnerable:

\n
# Python (peligroso)\nuser_input = "'; DROP TABLE users; --"\nquery = f"SELECT * FROM users WHERE name = '{user_input}'"\ncursor.execute(query)\n
\n

Incluso si usa psycopg2, podría olvidar accidentalmente el escape. Rust, en cambio, le obliga a pensar de otra manera.

\n\n

En Rust, con las bibliotecas sqlx o diesel, no puede simplemente insertar una cadena en una consulta: el sistema de tipos no lo permite:

\n
// Rust con sqlx (seguro)\nuse sqlx::PgPool;\n\nlet user_input = "'; DROP TABLE users; --";\nlet user: Option<User> = sqlx::query_as(\n    "SELECT * FROM users WHERE name = $1"\n)\n.bind(&user_input) // Enlace type-safe\n.fetch_optional(&pool)\n.await?;\n
\n

Observe $1 y .bind(). Rust no permite insertar un valor directamente en la cadena de la consulta. Esto no es solo una convención, es un requisito de compilación. La seguridad de Rust aquí se manifiesta en que físicamente no puede crear una inyección SQL si usa las bibliotecas correctas.

\n\n

¿Por qué funciona a nivel de tipos?

\n

En Rust, la cadena de la consulta y los datos son tipos diferentes. Bibliotecas como sqlx verifican las consultas en tiempo de compilación (compile-time checked queries). Si intenta hacer algo peligroso, el código simplemente no compilará:

\n
// ¡Esto no compilará!\nlet query = format!("SELECT * FROM users WHERE name = '{}'", user_input);\nsqlx::query(&query); // Error: se espera &str, no String con interpolación\n
\n

El sistema de propiedad (ownership) y préstamo (borrowing) no le permite "tragar" accidentalmente datos peligrosos. Esto no es magia, es disciplina de ingeniería integrada en el lenguaje.

\n\n

Protección contra XSS: escape y verificación automática

\n

XSS es cuando un atacante inyecta scripts en su HTML. En Rust, puede protegerse en varios niveles, y algunas verificaciones ocurren incluso antes de ejecutar el programa.

\n\n

Motores de plantillas con escape automático

\n

En Python, usa jinja2 con autoescape=true. En Rust, existen askama o maud que hacen lo mismo, pero con seguridad de tipos. Aquí hay un ejemplo con askama:

\n
// Rust con askama (motor de plantillas)\nuse askama::Template;\n\n#[derive(Template)]\n#[template(source = "<h1>¡Hola, {{ name }}!</h1>", ext = "html")]\nstruct HelloTemplate {\n    name: String,\n}\n\nfn main() {\n    let t = HelloTemplate {\n        name: "<script>alert('XSS')</script>".to_string(),\n    };\n    let rendered = t.render().unwrap();\n    // Salida: <h1>¡Hola, &lt;script&gt;...</h1>\n    // ¡Las etiquetas se escapan automáticamente!\n}\n
\n

Observe

Blogs

Book Recommendations