Sé que PreparedStatements evita / previene la inyección de SQL. ¿Como hace eso? ¿La consulta de formulario final que se construye utilizando PreparedStatements será una cadena o no?
Sé que PreparedStatements evita / previene la inyección de SQL. ¿Como hace eso? ¿La consulta de formulario final que se construye utilizando PreparedStatements será una cadena o no?
Respuestas:
El problema con la inyección SQL es que se usa una entrada de usuario como parte de la instrucció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 construye su comando SQL uniendo cadenas, aún es vulnerable a las inyecciones SQL incluso cuando usa declaraciones preparadas.
Considere dos formas 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 "usuario" provenía de la entrada del usuario y la entrada del usuario era
Robert'); DROP TABLE students; --
Luego, en primera instancia, estarías manguera. En el segundo, estarías a salvo y Little Bobby Tables estaría registrado en tu escuela.
Para comprender cómo PreparedStatement previene la inyección de SQL, debemos comprender las fases de ejecución de la consulta SQL.
1. Fase de compilación. 2. Fase de ejecución.
Cada vez que el motor del servidor SQL recibe una consulta, debe pasar por las siguientes fases,
Fase de análisis y normalización: en esta fase, se comprueba la sintaxis y la semántica de la consulta. Comprueba si las tablas y columnas de referencias utilizadas en la consulta existen o no. 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 la consulta, como select, from, where, etc., se convierten en un formato comprensible para la máquina. Esta es la fase donde 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 decisión 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 la consulta. 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 ingrese la misma consulta, no tenga que pasar por la Fase 1, la Fase 2 y la Fase 3 nuevamente. La próxima vez que ingrese la consulta, se comprobará directamente en la caché y se recogerá desde allí para ejecutarse.
Fase de ejecución:
en esta fase, la consulta proporcionada se ejecuta y los datos se devuelven al usuario como ResultSet
objeto.
Las declaraciones preparadas 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 pasa al motor de SQL Server, pasa por las siguientes fases
ACTUALIZAR usuario set username =? y contraseña =? DONDE id =?
La consulta anterior se analizará, 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 comprensible para la máquina. Por lo tanto, podemos decir que la consulta almacenada en caché está precompilada y solo los marcadores de posición deben reemplazarse con datos proporcionados por el usuario.
Ahora, en tiempo de ejecución, cuando entran los datos proporcionados por el usuario, la consulta precompilada se recoge de la caché y los marcadores de posición se reemplazan con datos proporcionados por el usuario.
(Recuerde, después de que los marcadores de posición se reemplazan con datos del usuario, la consulta final no se vuelve a compilar / interpretar y el motor de SQL Server trata los datos del usuario como datos puros y no como un SQL que debe analizarse o compilarse nuevamente; esa es la belleza de PreparedStatement. )
Si la consulta no tiene que pasar por la fase de compilación nuevamente, 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 ejecuta la consulta directamente.
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 única de PreparedStatement, está libre de ataques de inyección SQL.
Puede obtener una explicación detallada con un ejemplo aquí: https://javabypatel.blogspot.com/2015/09/how-prepared-statement-in-java-prevents-sql-injection.html
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 el rendimiento mejorado cuando se ejecuta la instrucción varias veces, incluso con diferentes valores para los parámetros (suponiendo que el controlador admite PreparedStatements) ya que el controlador no tiene que realizar el análisis y compilación de SQL cada uno vez que cambian los parámetros.
me conjetura que será una cadena. Pero los parámetros de entrada se enviarán a la base de datos y se aplicarán las conversiones / conversiones apropiadas antes de crear una declaración SQL real.
Para darle un ejemplo, podría intentar ver si CAST / Conversion funciona.
Si funciona, podría crear una declaración final a partir de él.
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 sea aceptable como parámetro numérico). ¿Mira qué pasa?
La declaración preparada es más segura. Convertirá un parámetro al tipo especificado.
Por ejemplo stmt.setString(1, user);
convertirá eluser
parámetro en una cadena.
Supongamos que el parámetro contiene una cadena SQL que contiene un comando ejecutable : el uso de una instrucción preparada no lo permitirá.
Agrega metacaracteres (también conocido como conversión automática) a eso.
Esto hace que sea más seguro.
Inyección SQL: cuando el usuario tiene la oportunidad de ingresar algo que podría ser parte de la instrucción sql
Por ejemplo:
Consulta de cadena = “INSERTAR EN LOS VALORES de los estudiantes ('” + usuario + “')”
cuando el usuario ingresa "Robert"); DROP TABLE estudiantes; - "como entrada, provoca la inyección SQL
¿Cómo la declaración preparada evita esto?
Consulta de cadena = “INSERTAR EN LOS VALORES de los estudiantes ('” + “: nombre” + “')”
parámetros.addValue ("nombre", usuario);
=> cuando el usuario ingresa nuevamente “Robert '); DROP TABLE estudiantes; - ", la cadena de entrada está precompilada 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/
CAST(‘Robert’);
de CAST(‘Robert’); DROP TABLE students; –‘ AS varchar(30))
se rompería, luego procedería a abandonar la tabla si ese fuera el caso. Detiene la inyección, por lo que creo que el ejemplo no es lo suficientemente completo como para explicar el escenario.
Declaración preparada:
1) La precompilación y el almacenamiento en caché del lado DB de la instrucción SQL conduce a una ejecución general más rápida y la capacidad de reutilizar la misma instrucción SQL en lotes.
2) Prevención automática de ataques de inyección SQL por escape integrado de comillas y otros caracteres especiales. Tenga en cuenta que esto requiere que utilice cualquiera de los métodos PreparedStatement setXxx () para establecer el valor.
Como se explica en esta publicación , elPreparedStatement
solo no te ayuda si todavía estás concatenando cadenas.
Por ejemplo, un atacante deshonesto aún puede hacer lo siguiente:
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 crear sentencias SQL. Use una API dedicada para ese propósito:
En las declaraciones preparadas, el usuario se ve obligado a ingresar datos como parámetros. Si el usuario ingresa algunas declaraciones vulnerables como DROP TABLE o SELECT * FROM USERS, los datos no se verán afectados, ya que estos se considerarían como parámetros de la declaración SQL