java - inyeccion - ¿Cómo evita o previene una inyección SQL un PreparedStatement?
pruebas de inyeccion sql (9)
Sé que PreparedStatements evita / previene la inyección de SQL. ¿Como hace eso? ¿La consulta de formulario final construida con PreparedStatements será una cadena o no?
Como se explica en esta publicación , el Estado PreparedStatement
por sí solo no lo ayuda si todavía está concatenando Cadenas.
Por ejemplo, un atacante pícaro aún puede hacer lo siguiente:
- llamar a una función de reposo para que todas las conexiones a su base de datos estén ocupadas, por lo tanto, haciendo que su aplicación no esté disponible
- extraer datos sensibles de la base de datos
- eludiendo la autenticación del usuario
No solo SQL, sino incluso JPQL o HQL pueden verse comprometidos si no está utilizando parámetros de enlace.
En pocas palabras, nunca debe usar la concatenación de cadenas al construir sentencias de SQL. Use una API dedicada para ese propósito:
Considere dos maneras de hacer lo mismo:
PreparedStatement stmt = conn.createStatement("INSERT INTO students VALUES(''" + user + "'')");
stmt.execute();
O
PreparedStatement stmt = conn.prepareStatement("INSERT INTO student VALUES(?)");
stmt.setString(1, user);
stmt.execute();
Si el "usuario" proviene de la entrada del usuario y la entrada del usuario fue
Robert''); DROP TABLE students; --
Entonces, en primer lugar, te pondrías a manguera. En el segundo, estarías a salvo y Little Bobby Tables estaría registrado para tu escuela.
Declaración preparada:
1) La precompilación y el almacenamiento en caché del lado de la base de datos de la instrucción SQL permiten una ejecución general más rápida y la posibilidad de reutilizar la misma instrucción SQL en lotes.
2) Prevención automática de ataques de inyección de SQL mediante el escape integrado de comillas y otros caracteres especiales. Tenga en cuenta que esto requiere que use cualquiera de los métodos PreparedStatement setXxx () para establecer el valor.
El SQL utilizado en un PreparedStatement está precompilado en el controlador. A partir de ese momento, los parámetros se envían al controlador como valores literales y no como partes ejecutables de SQL; por lo tanto, no se puede inyectar SQL utilizando un parámetro. Otro efecto secundario beneficioso de PreparedStatements (precompilación + envío de solo parámetros) es un rendimiento mejorado al ejecutar el enunciado varias veces incluso con diferentes valores para los parámetros (suponiendo que el controlador admita PreparedStatements) ya que el controlador no tiene que realizar el análisis SQL y la compilación tiempo los parámetros cambian.
El problema con la inyección SQL es que la entrada del usuario se usa como parte de la declaración SQL. Al usar declaraciones preparadas, puede forzar que la entrada del usuario se maneje como el contenido de un parámetro (y no como parte del comando SQL).
Pero si no usa la entrada del usuario como un parámetro para su declaración preparada, sino que crea su comando SQL uniendo cadenas, aún es vulnerable a las inyecciones de SQL incluso cuando usa declaraciones preparadas.
Inyección SQL: cuando el usuario tiene la posibilidad de ingresar algo que podría ser parte de la declaración sql
Por ejemplo:
String query = "INSERT INTO students VALUES (''" + user + "'')"
cuando el usuario ingresa "Robert"); DROP TABLE estudiantes; - "como entrada, causa la inyección de SQL
¿Cómo la declaración preparada previene esto?
String query = "INSERT INTO students VALUES (''" + ": name" + "'')"
parameters.addValue ("nombre", usuario);
=> cuando el usuario ingresa de nuevo "Robert"); DROP TABLE estudiantes; - ", la cadena de entrada se precompila en el controlador como valores literales y supongo que se puede convertir como:
CAST (''Robert''); DROP TABLE estudiantes; - ''AS varchar (30))
Entonces, al final, la cadena se insertará literalmente como el nombre de la tabla.
http://blog.linguiming.com/index.php/2018/01/10/why-prepared-statement-avoids-sql-injection/
La declaración preparada es más segura. Convertirá un parámetro al tipo especificado.
Por ejemplo, stmt.setString(1, user);
convertirá el parámetro de user
a una Cadena.
Supongamos que el parámetro contiene una cadena SQL que contiene un comando ejecutable : el uso de una declaración preparada no permitirá eso.
Agrega metacarácter (también conocido como conversión automática) a eso.
Esto hace que sea más seguro.
Para comprender cómo PreparedStatement previene la inyección de SQL, debemos comprender las fases de la ejecución de SQL Query.
1. Fase de compilación. 2. Fase de ejecución.
Cada vez que el motor de SQL Server recibe una consulta, debe pasar por debajo de las fases,
Fase de análisis y normalización: en esta fase, se verifica la sintaxis y la semántica de Consulta. Comprueba si existen o no tablas de referencias y columnas utilizadas en la consulta. También tiene muchas otras tareas que hacer, pero no vayamos en detalle.
Fase de compilación: en esta fase, las palabras clave utilizadas en consultas como select, from, where, etc. se convierten a formato entendible por máquina. Esta es la fase en la que se interpreta la consulta y se decide la acción correspondiente a tomar. También tiene muchas otras tareas que hacer, pero no vayamos en detalle.
Plan de optimización de consultas: en esta fase, se crea el Árbol de decisiones para encontrar las formas en que se puede ejecutar la consulta. Descubre la cantidad de formas en que se puede ejecutar la consulta y el costo asociado con cada forma de ejecutar Query. Elige el mejor plan para ejecutar una consulta.
Caché: el mejor plan seleccionado en el plan de optimización de consultas se almacena en caché, de modo que cada vez que entre la misma consulta, no tenga que pasar nuevamente por la Fase 1, Fase 2 y Fase 3. Cuando ingrese la consulta de la próxima vez, se verificará directamente en Caché y se seleccionará desde allí para ejecutarla.
Fase de ejecución: en esta fase, la consulta suministrada se ejecuta y los datos se devuelven al usuario como objeto
ResultSet
.
Comportamiento de la API PreparedStatement en los pasos anteriores
Los PreparedStatements no son consultas SQL completas y contienen marcadores de posición, que en tiempo de ejecución se reemplazan por datos reales proporcionados por el usuario.
Cada vez que un PreparedStatment que contiene marcadores de posición se transfiere al motor de SQL Server, pasa a través de las fases siguientes
- Fase de análisis y normalización
- Fase de compilación
- Plan de optimización de consultas
- Caché (consulta compilada con marcadores de posición se almacenan en caché).
ACTUALIZAR el usuario establecido username =? y contraseña =? ¿DÓNDE id =?
La consulta anterior se analizará, se compilará con marcadores de posición como tratamiento especial, se optimizará y se almacenará en caché. La consulta en esta etapa ya está compilada y convertida en un formato de máquina comprensible. Por lo tanto, podemos decir que Query almacenado en caché está precompilado y que solo los marcadores de posición deben ser reemplazados por datos proporcionados por el usuario.
Ahora en el tiempo de ejecución cuando ingresan los datos proporcionados por el usuario, la consulta precompilada se recoge de la memoria caché y los marcadores de posición se reemplazan por datos proporcionados por el usuario.
(Recuerde, después de que los titulares de lugar sean reemplazados por datos de usuario, la consulta final no se compila / interpreta nuevamente y el motor de SQL Server trata los datos de usuario como datos puros y no como un SQL que necesita ser analizado o compilado nuevamente; esa es la belleza de PreparedStatement. )
Si la consulta no tiene que atravesar nuevamente la fase de compilación, los datos reemplazados en los marcadores de posición se tratan como datos puros y no tienen ningún significado para el motor de SQL Server y ejecutan directamente la consulta.
Nota: Es la fase de compilación después de la fase de análisis, que comprende / interpreta la estructura de la consulta y le da un comportamiento significativo. En el caso de PreparedStatement, la consulta se compila solo una vez y la consulta compilada en caché se recoge todo el tiempo para reemplazar los datos del usuario y ejecutarlos.
Debido a la función de compilación de una sola vez de PreparedStatement, está libre de ataque de inyección SQL.
Puede obtener una explicación detallada con el ejemplo aquí: http://javabypatel.blogspot.in/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
Supongo que será una cadena. Pero los parámetros de entrada se enviarán a la base de datos y se aplicarán conversiones / conversiones apropiadas antes de crear una declaración de SQL real.
Para darle un ejemplo, podría intentar y ver si el CAST / Conversion funciona.
Si funciona, podría crear una declaración final.
SELECT * From MyTable WHERE param = CAST(''10; DROP TABLE Other'' AS varchar(30))
Pruebe un ejemplo con una instrucción SQL que acepte un parámetro numérico.
Ahora, intente pasar una variable de cadena (con contenido numérico que sea aceptable como parámetro numérico). ¿Se plantea algún error?
Ahora, intente pasar una variable de cadena (con contenido que no es aceptable como parámetro numérico). ¿Mira qué pasa?