Tag Archive: Bases de datos


Ha pasado algo más de un año desde la última entrada, pero hemos vuelto con las pilas recargadas. A ver lo que me dura esta vez.
En el último post hablé sobre la seguridad en Symfony y lo desastroso que puede ser una mala configuración. Recordemos que si dejabamos expuesto la carpeta app de un proyecto en Symfony2, podiamos dejar accesible el fichero parameters.yml dejando expuesta las credenciales de la base de datos. Dejar  esto en un servidor con el proyecto accesible desde internet, es invitar a que los malvados nos hagan maldades.

A fecha de hoy, y buscando un poco en Google con el siguiente dork: inurl:app/config/parameters.yml te puedes encontrar varios proyectos con este fichero abierto para todos los públicos.
Y en algunos, no solo te encuentras las credenciales de la base de datos, sino también el usuario y contraseña de una cuenta de correo, (de gmail por ejemplo) si tienen configurado el mailer.

parameters.yml real

Ejemplo de un parameters.yml filtrado

Viendo esto, vamos a repasar las medidas de seguridad para evitar esta fuga de información:

  1. Lo más importante, intenta no dejar publicada la carpeta app. Es el fallo más grande.
  2. Si no queda otro remedio, asegurate que los ficheros .htaccess que vienen con la carpeta estén funcionando, puede que tengamos configurado apache para que no nos deje sobreescribir las directicas de seguridad necesarias.
  3. A lo mejor sería interesante incluir alguna directiva que denegara el acceso a través de web de los ficheros .yml.
  4. Si tenemos el proyecto en un repositorio git, es importantisimo poner en el .gitignore el parameters.yml. Mejor configurarlo 30 veces en producción que tener una sola fuga de información

Con todo esto en cuenta, se nos puede dar la situación de que no quede más remedio que publicar la carpeta app accidentalmente. Pero si hemos seguido los anterioes consejos,
no deberiamos de tener tantos problemas ya que hemos protegido los ficheros yml. Pero creernos que estamos a salvo sería un error. En Symfony2 tenemos la carpeta app/cache
en la que se almacenan los compilados de las plantillas y otros recursos del proyecto. Esta carpeta no suele estar protegida por ningún .htacces, de forma que sus documentos serían accesibles.
Dentro de ella encontramos el fichero appProdDebugProjectContainer.xml donde encontraremos lo mismo que hay en parameters.yml, pero no solo eso, también información jugosa como los bundles que se utilizan en el proyecto, que rutas están protegidas y mediante que roles,etc.

appDevDebugProjectContainer.xml

Fichero appDevDebugProjectContainer.xml publicado

De modo que hay que asegurarse de proteger también esta carpeta.

Conclusión, NO dejeis publicado el directorio app. Os ahorrareis muchos dolores de cabeza. Y tened cuidado con las carpetas que dejais accesible al público, sean del framework que sean.

Me he decidido a comenzar a explorar Ruby on Rails. La verdad que parece una solución MVC bastante potente, ya que entre todas sus ventajas, ofrece una interfaz REST que viene bastante bien para proporcionar servicios a consumir por otras aplicaciones.

La instalación en Ubuntu es bien sencilla siguiendo los pasos de la Wiki oficial.

Una vez hecho estos pasos, podemos seguir los pasos del primer ejemplo de un blog que viene en el Get Started

Aunque me he encontrado con un problema siguiendo los pasos, al intentar crear la base de datos. El problema era que aunque había cambiado el fichero de configuración de base de datos para utilizar mysql, me seguía diciendo que faltaba la gema de sqlite3, concretamente:

Could not find sqlite3-ruby-1.3.2 in any of the sources
Try running `bundle install`.

Así que tenemos dos soluciones:
La primera y menos limpia, es la de instalar la gema y dejarla ahí aunque no la utilicemos.

La segunda, es editar el fichero Gemfile, donde se indican las dependencias y comentamos la línea de sqlite y añadimos la de mysql:

#gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'mysql'

De esta forma, tambien nos evitamos el error uninitialized constant Mysql

Y aún estoy de exámenes, hasta el viernes, que estaré por fin libre de este gran peso, y esperemos, que con resultados satisfactorios.

Mientras tanto, para no tener abandonado el blog, ahi va mi pequeña aportación semanal.
Normalmente, en toda base de datos de una aplicación que se precie, suele tener algún campo del tipo Date. Pues Mysql, por norma general, si el campo no puede ser NULL, le asigna como valor por defecto ‘0000-00-00’, un valor que puede parecer inocente en un principio, pero si ya tenemos una aplicación Java funcionando o de una nueva, al intentar recuperarla del ResultSet, obtendremos una bonita excepción del tipo :


java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Date

Aunque la primera solución que se nos puede pasar por la cabeza, después de las ganas de querer apalear la máquina virtual de Java, sería modificar la base de datos y cambiar todos los registros cuyo valor sea ‘0000-00-00’ por un NULL o si no podemos, por la fecha más antigua posible (Esa de 1970 que bla bla bla).  Ahora bién, esto puede ser bastante engorroso, aparte de que posiblemente nos pueda causar problemas posteriores con otras zonas de la aplicación. Pero por suerte, tenemos una solución bastante más asequible, rápida y escalable. Es tan sencillo, como pasarle como parámentro al conector de Mysql para java lo siguiente : “zeroDateTimeBehavior=convertToNull”, quedando por ejemplo, la línea de la conexión algo así:

"jdbc:mysql://localhost:3306/pagos?user=root&password=root&zeroDateTimeBehavior=convertToNull";

De esta forma, automaticamente, el conector, cada vez que recupere un registro del tipo fecha que sea cero, lo que hará será darle al ResultSet un null, solucionando así gran parte de nuestros problemas.

Si quereis aprender más sobre toda la funcionalidad del conector de Mysql, siempre podeis dirigiros a la documentación oficial del conector.

Cuando estamos tratando con consultas a bases de datos en Java, sobre todo en un proyecto Enterprise, podemos llegar a hablar de consultas kilométricas que acceden a varias tablas con una cantidad ingente de campos. Y si pretendemos hacer las cosas bien, utilizando los PreparedStatement, por temas de seguridad , legibilidad y reutilización, seguramente, si tenemos que hacer algún cambio en una sentencia, añadiendo o eliminando algún parametro, nos podemos encontrar con que deberemos cambiar bastantes líneas de código, en vez de la que debemos añadir/quitar solamente.

Vamos a poner un ejemplo práctico, si tenemos la siguiente sentencia de consulta a una base de datos:


SELECT usuarios.*, roles.descripcion, posts.entrada, posts.titulo FROM usuarios,descripcion,posts
WHERE usuarios.rolId=roles.id AND posts.userId=usuarios.id AND posts.fecha BETWEEN ? AND ?
AND usuarios.userId = ? AND posts.id = ? AND posts.isVisible = ? AND posts.visitas > ?

Esta consulta no es muy extensa, pero nos valdrá para ilustrar el supuesto práctico.  Ahora tendríamos el siguiente código Java para realizar la consulta:


String consulta = //la consulta de arriba;
PreparedStatement stmt = conexion.prepareStatement(consulta);
stmt.setDate(1,desde);
stmt.setDate(2,hasta);
stmt.setInt(3,userId);
stmt.setInt(4,postId);
stmt.setBoolean(5,isVisible);
stmt.setInt(6,numVisitas);

ResultSet result = stmt.executeQuery();

Esta sería la forma normal de trabajar, pero si en un futuro tenemos que realizar alguna modificación a la consulta,
por ejemplo, quitamos la necesidad de las dos fechas en la condición. Nos encontramos conque deberemos eliminar dos lineas de código
y modificar las otras 4, para que cuadre el número del parámetro. Esto no nos llevaría mucho tiempo en una sola consulta, pero si hubiera que modificar más consultas (porque se haya eliminado un campo que se utilizaba en todas las consultas como condición),  o si tratamos de una consulta con 20 parámetros por ejemplo, ya requeriría más tiempo empleado en el mantenimiento.

Así, que para ahorrar en tiempo de mantenimiento futuro, lo que podemos hacer, es insertar una variable que vaya aumentando con cada inserción de un nuevo parámetro, de esta forma,  no  tenemos que estar trabajando con el número de parámetro que se le pasa a los métodos set… y nos ahorraremos más de un dolor de cabeza. El código resultante, sería algo así:

int parameter=1;
String consulta = //la consulta de arriba;
PreparedStatement stmt = conexion.prepareStatement(consulta);
stmt.setDate(parameter++,desde);
stmt.setDate(parameter++,hasta);
stmt.setInt(parameter++,userId);
stmt.setInt(parameter++,postId);
stmt.setBoolean(parameter++,isVisible);
stmt.setInt(parameter++,numVisitas);

ResultSet result = stmt.executeQuery();

De esta forma, ya nos podemos despreocupar, de que el número de un parámetro coincida
con el de la consulta, y si hacemos alguna modificación en la consulta, no tendremos que realizar demasiado
cambio en el código y por último, nos facilita el copy & paste que tanto gusta a algunos.
Para finalizar, solo hay que recordar que el número de parametros, empieza con 1, no con 0 como los arrays, y que el número
de parametros que requiere la consulta, debe ser igual al número de parámetros que le pasamos, uno más o uno menos
resultará en una excepción.