injection - Logging PreparedStatements en Java
sql injection cheat sheet (4)
Una cosa que siempre ha sido dolorosa es registrar errores de SQL (JDBC) cuando tiene un PreparedStatement en lugar de la consulta en sí.
Siempre terminas con mensajes como:
2008-10-20 09:19:48,114 ERROR LoggingQueueConsumer-52 [Logger.error:168] Error
executing SQL: [INSERT INTO private_rooms_bans (room_id, name, user_id, msisdn,
nickname) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE room_id = ?, name = ?,
user_id = ?, msisdn = ?, nickname = ?]
Por supuesto, podría escribir un método de ayuda para recuperar los valores y analizar / sustituir los signos de interrogación con valores reales (y probablemente siga ese camino si no obtengo el resultado de esta pregunta), pero solo quería saber si este problema fue resuelto antes por otra persona y / o si hay algún ayudante de registro genérico que pueda hacer eso automágicamente para mí.
Editado después de algunas respuestas:
Las bibliotecas proporcionadas hasta ahora parecen ser adecuadas para registrar las instrucciones para la depuración, lo que sin duda es útil. Sin embargo, estoy buscando una manera de tomar un PreparedStatement en sí mismo (no una subclase) y registrar su declaración SQL siempre que ocurra un error. No me gustaría implementar una aplicación de producción con una implementación alternativa de PreparedStatement.
Supongo que estoy buscando una clase de utilidad, no una especialización de PreparedStatement.
¡Gracias!
Si está utilizando MySQL, PreparedStatement.toString () de MySQL Connector incluye los parámetros enlazados . Aunque los grupos de conexión de terceros pueden romper esto.
Subclase PreparedStatement para construir la cadena de consulta como parámetros agregados. No hay forma de extraer el SQL de un PreparedStatement, ya que utiliza una forma binaria compilada.
LoggedPreparedStatement parece prometedor, aunque no lo he probado.
Una ventaja de estos sobre un controlador proxy que registra todas las consultas es que puede modificar la cadena de consulta antes de iniciar sesión. Por ejemplo, en un entorno PCI, es posible que desee enmascarar los números de tarjeta.
Esto es muy dependiente de la base de datos. Por ejemplo, entiendo que algunos controladores JDBC (por ejemplo, sybase, quizás ms-sql) manejan declaraciones preparadas creando un procedimiento almacenado temporal en el servidor y luego invocando ese procedimiento con los argumentos suministrados. Entonces, el SQL completo nunca se pasa realmente del cliente.
Como resultado, la API de JDBC no expone la información que está buscando. Es posible que pueda convertir los objetos de su declaración en la implementación del controlador interno, pero probablemente no; es posible que su servidor de aplicaciones ajuste las declaraciones en su propia implementación.
Creo que puede que tenga que morder la bala y escribir su propia clase que interpola los argumentos en el marcador de posición SQL. Esto será incómodo, porque no puede solicitar a PreparedStatement los parámetros que se han establecido, por lo que deberá recordarlos en un objeto auxiliar, antes de pasarlos a la declaración.
Me parece que una de las bibliotecas de utilidades que envuelve los objetos de implementación de su controlador es la forma más práctica de hacer lo que está tratando de lograr, pero va a ser desagradable de cualquier manera.
Intenté log4jdbc y me hizo el trabajo.
NOTA DE SEGURIDAD: A partir de hoy agosto de 2011, los resultados registrados de una declaración preparada de log4jdbc NO SON SEGUROS para ejecutarse. Se pueden usar para el análisis, pero NUNCA se deben volver a introducir en un DBMS.
Ejemplo de registro generado por logjdbc:
2010/08/12 16:30:56 jdbc.sqlonly org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate (DelegatingPreparedStatement.java:105) 8. INSERT INTO A_TABLE (ID_FILE, CODE1, ID_G, ID_SEQUENCE, REF, NAME, BAR , DRINK_ID, AMOUNT, DESCRIPTION, STATUS, CODE2, REJECT_DESCR, ID_CUST_REJ) VALUES (2, ''123'', 1, ''2'', ''aa'', ''awe'', null, ''0123'', 4317.95, ''Rccc'', '' 0 '', nulo, nulo, nulo)
La biblioteca es muy fácil de configurar:
Mi configuración con HSQLDB :
jdbc.url=jdbc:log4jdbc:hsqldb:mem:sample
Con Oracle :
jdbc.url=jdbc:log4jdbc:oracle:thin:@mybdd:1521:smt
jdbc.driverClass=net.sf.log4jdbc.DriverSpy
logback.xml:
<logger name="jdbc.sqlonly" level="DEBUG"/>
Lástima que no estaba en un repositorio maven, pero sigue siendo útil.
Por lo que intenté, si estableces
Solo obtendrá las declaraciones por error, sin embargo, no sé si esta biblioteca tiene un impacto en el rendimiento.
Usa P6Spy : es amigable con Oracle, Mysql, JNDI, JMX, Spring y Maven . Altamente configurable. Integración simple y de bajo nivel Puede imprimir stacktrace . Solo puede imprimir llamadas pesadas - tiempo basado en el tiempo.