Los procedimientos almacenados no evitan mágicamente la inyección de SQL, pero sí hacen que evitarlo sea mucho más fácil. Todo lo que tienes que hacer es algo como lo siguiente (ejemplo de Postgres):
CREATE OR REPLACE FUNCTION my_func (
IN in_user_id INT
)
[snip]
SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]
¡Eso es! El problema solo surge cuando se forma una consulta a través de la concatenación de cadenas (es decir, SQL dinámico), ¡e incluso en esos casos puede vincular! (Depende de la base de datos).
Cómo evitar la inyección de SQL en su consulta dinámica:
Paso 1) Pregúntese si realmente necesita una consulta dinámica. Si está uniendo cadenas solo para configurar la entrada, entonces probablemente lo esté haciendo mal. (Hay excepciones a esta regla: una excepción es para informar consultas en algunas bases de datos, puede tener problemas de rendimiento si no lo obliga a compilar una nueva consulta con cada ejecución. Pero investigue este problema antes de saltar a eso. )
Paso 2) Investigue la forma correcta de establecer la variable para su RDBMS particular. Por ejemplo, Oracle le permite hacer lo siguiente (citando sus documentos):
sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE '
|| v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!
Aquí todavía no está concatenando la entrada. ¡Estás atado de forma segura! ¡Hurra!
Si su base de datos no admite algo como lo anterior (es de esperar que ninguno de ellos siga siendo tan malo, pero no me sorprendería), o si todavía debe concatenar su entrada (como en el caso "a veces" de informar consultas como Insinué arriba), entonces debe usar una función de escape adecuada. No lo escribas tú mismo. Por ejemplo, postgres proporciona la función quote_literal (). Entonces correría:
sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);
De esta manera, si in_name es algo tortuoso como '[snip] o 1 = 1' (la parte "o 1 = 1" significa seleccionar todas las filas, ¡permitiendo al usuario ver los salarios que no debería!), Entonces quote_literal guarda su trasero por haciendo la cadena resultante:
SELECT salary FROM employees WHERE name = '[snip] or 1=1'
No se encontrarán resultados (a menos que tenga algunos empleados con nombres realmente extraños).
Esa es la esencia de esto! Ahora déjame dejarte con un enlace a una publicación clásica del gurú de Oracle Tom Kyte sobre el tema de la inyección SQL, para llevar el punto a casa: Linky