21 de julio de 2011

Ponencia-Taller de Dr. Metrics


El pasado día 19 de Julio del 2011, me pasé por una Ponencia-Taller que realizaba Dr. Metrics (Enric Quintero), organizado por Iniciador Barcelona, sobre Web Anlytics (Análisis Web) para ver que podía sacar de allí para abrir mi mente a futuras ideas, expectativas profesionales, absorber algo más de conocimiento y si se daba la ocasión, hacer algo de networking.

En el anunció del “Taller” se indicaba que Dr. Metrics era un crack de los productos Google Analytics y Optimizer, así que me hizo pensar que spamearia bastante de estos productos, algo que ya me parecía bien, por eso asistí, porque seguro que siempre se puede aprender algo; no obstante la ponencia me sorprendió porque el nivel de SPAM sobre Google fue bajo, además de ser crítico con lo que estos productos aportan y no aportan.

Dr. Metrics, claramente, anunció que el analizar el éxito de tu site no solo se trata de el número de visitas, que páginas se han visitado y cuanto tiempo se ha visitado cada página, sino que al final toda esa información es importante si puedes ligarla con otros aspectos que te puedan describir el comportamiento de los visitantes y del porque de sus interacciones.

Lo que espera todo el mundo cuando consulta las métricas de su site, es ver que beneficio le está aportando, definiendo beneficio como venta de productos, venta de servicios, presentación de la empresa para posterior contacto, fama, etc.

Dr. Metrics dejó claro que las métricas son importantes, pero solo son una pieza de un puzzle, es decir que sin relacionarlas con otros aspectos, se puede decir que no sirven para nada. Entre las otras piezas del puzzle mencionó aspectos como análisis de lo que sucede en tu backend (por ejemplo las transacciones interesantes realizadas en la BBDD, como sería el cierre de un proceso de compra), encuestas al usuario cuando decide abandonar tu site en procesos importantes no finalizados (por ejemplo en medio de el pago con tarjeta de crédito de una compra o contratación de servicio) y algunos aspectos más que mencionó.

Me entusiasmo la idea que recalcó sobre de buscar “los tres pies al gato” cuando ves que las visitas de tu site son bajas o que hay bastantes abandonos en páginas que no tiene mucho sentido (por ejemplo en medio del proceso de compra); lo primero que dijo sobre este aspecto es que antes de ponerse a cruzar datos como un loco es que revises la infraestructura donde se organiza todo este circo, es decir si tu/s servidor/es a lo largo del mundo, plataforma y horario tienen un adecuado rendimiento, tienen una disponibilidad adecuada y todo tu site funciona bien y no van errores 400, 500, … Resumiendo que primero empieces la casa por los fundamentos y no por el tejado, así que primero a invertir en un desarrollo con un nivel adecuado de calidad (incluyendo seguridad) y óptimo, eso si desde mi punto de vista no te pases con lo de óptimo, que luego el desarrollo, llamemos código, es un Jeroglífico solo entienden los iluminados que lo han creado y como esto se larguen de la empresa ya verás los dolores de cabeza que tendrás; y una vez tengas un desarrollo de calidad aceptable te va a tocar invertir en servidor/es, comunicaciones, y buen sys admin que sepa configurar y optimizar, y no nos olvidemos de securizar, los cabr... que van a servir tu site.

Sobre los sistemas/servicios/implementaciones de análisis de métricas, también habló, y no solo de Google Analytics, sino de otros como Yahoo Analytics, u otros sistemas de uso privado como el archiconocido, no gratuito, Urchin; no obstante finalizó este apartado venerando a Google Analytics por su facilidad de uso para usuarios no técnicos, es decir que Google, parece tener “la madre del cordero” en usabilidad dando la importancia que tiene en el hecho de sacarle provecho, ya que tener muchas funcionalidades no sirve de nada si luego no sabes usarlas.

Finalmente llegó el tuno de las preguntas, se preguntaron unas pocas, pero realmente solo recuerdo la mía, así que la voy a dejar aquí, que para eso es mi blog:
¿Te has planteado como va a cambiar todo este mundo de analizar a los usuarios ahora que los gobiernos se están poniendo las pilas en legislaciones de privacidad y que se están realizando, por fin, unas campañas de concienciación sobre la privacidad de los datos en la red? (bueno no fue exactamente así, pero similar)

Y la conclusión de al respuesta fue que la información no es gratis, aunque lo parezca, así que si vas a querer que tus usuarios dejen en tu site tu rastro tendrás que recompensarlos, por ejemplo, descuentos, sorteos, etc; algo que deberían tomar no ta muchos de los explotadores que corren por este país, que parece que todo los tiene que salir gratis, es decir a cambio de nada.

Podéis consultar el resumen de la ponencia realizado por Iniciador Barcelona, junto con slides de la presentación, aquí (y si queréis verme a mí, lo podéis hacer en la foto que hay al público).


Hasta la próxima enfermos.

8 de julio de 2011

[PHP] Verificación de entradas en arrays multidimensionales (2/2)

conjuntoEntradas() {
  [PHP] Verificación de entradas en arrays multidimensionales (1/2)
  [PHP] Verificación de entradas en arrays multidimensionales (2/2)
}


Llegado al punto que al no ser las dos opciones comentadas en el primer post de esta serie de mi gusto por el motivo que ya expuse, además estar desfavorecidas frente a otras, por su menor rendimiento en velocidad de ejecución, podría haber optado por tirar por el derecho y decidir utilizar la función isset(), es decir la que en el comentario de la documentación de función is_null(), se dejaba claro que era la más óptima entre estas tres opciones.

No obstante, durante mi búsqueda de como hacer la verificación de la existencia de claves dentro de los arrays multidimensionales, me tope con otra función, que por nombre y definición (Verifica si el índice o clave dada existe en el array) debería ser la más apropiada para realizar dicho menester; estoy hablando de la función array_key_exists().

No obstante, en los comentarios de la documentación de array_key_exists(), alguien y había comentado la diferencia de velocidad de ejecución con isset(), siendo de nuevo, favorable para ésta última.

Aún habiendo este comentario, yo quería hacer mis pruebas, ya que al final del comentario, se menciona que la diferencia de rendimiento no es tan grande en un sistema operativo Mac o Linux, como lo es un MS Windows; además la prueba del comentario se realiza sobre un array unidimensional y no multidimensional, que son con los que yo me iría encontrando en mis implementaciones y por otra parte, me entró la vena friki por realizar la prueba sobre un profiler, y como ya había utilizado en una vez anterior, el elegido fue Xdebug, utilizando, con el mismo motivo, el visor KCachegrind; así que manos, la obra.

Primero la implementación de las funciones que me permitirán discernir entre las dos distintas formas de verificar la presencia de claves en arrays multidimensionales con la función array_key_exists().

function aa_verificacion_a_una_instruccion_fallo_2d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave2.5', $var1['clave1.3'])) {
        }
    }
}

function ab_verificacion_por_dimension_fallo_2d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                (array_key_exists('clave2.5', $var1['clave1.3']))) {
        }
    }
}

function ba_verificacion_a_una_instruccion_fallo_3d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1'])) {
        }
    }
}

function bb_verificacion_por_dimension_fallo_3d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']) ) {
        }
    }
}

function ca_verificacion_a_una_instruccion_fallo_4d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}

function cb_verificacion_por_dimension_fallo_4d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave3.0', $var1['clave1.3']['clave2.1']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}


function da_verificacion_a_una_instruccion_fallo_3d_sobre_4d($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.1'])) {
        }
    }
}

function db_verificacion_por_dimension_fallo_3d_sobre_4d($var1) {
    for ($i = 0; $i < 10000; $i++) {
        if (array_key_exists('clave1.3', $var1) && 
                array_key_exists('clave2.1', $var1['clave1.3']) &&
                array_key_exists('clave3.1', $var1['clave1.3']['clave2.1']) &&
                array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}
Aunque se podía intuir con total certeza que la verificación a una instrucción, directamente haciendo referencia a la clave en la dimensión que se quiere verificar, será más óptima que la verificación dimensión por dimensión hasta llegar a la profundidad de la dimensión que realmente se quiere comprobar; opté por realizar la prueba y así poder ver de manera cuantificable la diferencia que había, y tener que tragarme mis gustos y optar por hacer la comparación con isset(), haciendo referencia a posiciones de memoria inexistentes si las dimensiones de menor profundidad a al que se quiere verificar, ya no existen, como a comenté en la primera entrada de esta serie. Los resultados obtenidos fueron estos:

 Diagrama de llamadas a funciones de comparación de la dos maneras de utilizar array_key_exists()

Diagrama de llamadas a funciones de comparación de la dos maneras de utilizar array_key_exists() de menos a mayor % utilizado 

Bueno, una vez hecho un poco el ganso, tocaba realizar la comprobación definitiva, comparar la eficiencia de ejecución entre array_key_exists() e isset(), así que esté fue el script que utilicé:
function aa_usando_array_key_exists($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.1']['clave3.0'])) {
        }
    }
}

function ab_usando_isset($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (isset($var1['clave1.3']['clave2.1']['clave3.0']['clave4.1'])) {
        }
    }
}

function ba_usando_array_key_exists_fallo_dimension_anterior($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (@array_key_exists('clave4.1', $var1['clave1.3']['clave2.5']['clave3.0'])) {
        }
    }
}

function bb_usando_isset_fallo_dimension_anterior($var1) {
   for ($i = 0; $i < 10000; $i++) {
        if (isset($var1['clave1.3']['clave2.1']['clave2.5']['clave4.1'])) {
        }
    }
}
Y los resultados obtenidos fueron estos:


Diagrama de llamadas a funciones de comparación entre la utilización de array_key_exists() e isset()


Diagrama de llamadas a funciones de comparación entre la utilización de array_key_exists() e isset() de menos a mayor % utilizado

Así que como dice el dicho, “una imagen vale más que 1000 palabras”, la eficiencia queda demostrada.

Para concluir solo me queda aclarar un aspecto que alguno le debe descuadrar; se trata de ¿porqué en el caso de la utilización de isset() no tengo ninguna pega por lo que he comentado con el resto? Me refiero al hecho de no gustarme hacer referencias a posiciones de memoria inexistentes. Pues bien, el caso de isset() lo veo sustancialmente distinto, ya que por definición la función sirve para “determinar si una variable esta definida y no es NULL”, así que aparte de considerar que lo que va a hacer es verificar la existencia o inexistencia de una posición de memoria (en términos de definición de posiciones de memoria alocadas en tu programa), si la posición no existe no aparece ningún mensaje de notificación informando de ello, claro está sin anteponer @ a la llamada de la función; así que no me da la sensación de estar realizando algo que no es del todo correcto.


Hasta la próxima enfermos.

1 de julio de 2011

Un poco de colaboración y organización de equipos de trabajo sobre SharePoint 2010


Esta semana, concretamente el martes, he terminado las jornadas de formación de SharePoint que ha realizado Gepesa.

A lo largo de los tres días me enterado del potencial de está herramienta, que hasta el momento lo único que sabía es que permitía trabajar con archivos en un entorno compartido por múltiples usuarios controlando los accesos y gestionando el acceso concurrente, bloqueado y/o detectando conflictos.

Ahora ya sé que no solamente ofrece esa funcionalidad sino muchas más, las cuales aumentan la productividad de los entornos de equipos de trabajo o, incluso, de una organización al completo.

No obstante, después de todo lo que tiene la herramienta, sigue sin proporcionar las necesidades del entorno que tiene la empresa donde prestó mis servicios. Actualmente y desde hace ya un largo tiempo la empresa utiliza una herramienta, desarrollada íntegramente dentro de esta misma, que hace la funcionalidad de explorador de ficheros sobre carpetas compartidas en los servidores, pero controlando y garantizando que sólo un usuario puede estar modificando un documentos al mismo tiempo, es decir lo que viene ha hacer SharePoint, pero aquí no hay copia del documento al disco local de la estación de trabajo sino que se trabaja directamente sobre el documento almacenado en el servidor (Esto, por lo que me contaron, sólo se da de serie en SharePoint sobre ficheros de MS Word y utilizando Office 2007 hacia arriba).

En el entorno que se da actualmente en la empresa, realmente, no se accede a los servidores de ficheros directamente sino que se hace a través de un DFS junto con su servicio de replicación (DFSR), replicando los archivos en los distintos servidores de las distintas sedes de la empresa.

En el entorno mencionado, los usuarios se quejan constantemente de la lentitud de acceso a los ficheros, y llevan razón si lo comparamos con un acceso a un fichero en el disco local, pero si lo comparamos con un acceso remoto no lo es tanto, con ciertas excepciones, justificada por la inversión en hardware que se hace y el tiempo y recursos que se asignan a “los informáticos” para optimizar los sistema.

En fin, que tal y como está ahora, sí le pedimos a los usuarios que tiene que descargar cada vez que tiene que modificar un fichero (se trabaja con ficheros de distintos tipos, ficheros de programa de cálculo, planos de Autocad, ofimáticos y bastantes más) y luego volverlo a subir y desbloquearlo, nos montan una revolución, y no sería sin razón, ya que estarían empleando más tiempo en hacer lo que ahora hacen, aunque quedaría por analizar si empezar a usar este entorno aportaría ciertos beneficios que compensasen el tiempo de más que tendrían que emplear cada usuario, es decir ver la relación entre el tiempo empleado en los procedimientos de trabajo y la productividad obtenida en global, por ejemplo, este proceso es más costoso pero se obtiene beneficios por otra parte que optimizan el tiempo de otros procesos, aumenta la satisfacción del cliente, etc.

Además de la funcionalidad comentada, que es la que justifica mi asistencia a las jornadas, y como ya he dicho, SharePoint ofrece otras funcionalidades que ahora he podido ver que en la empresa se realizan a través de Lotus Notes (principalmente me refiero a la funcionalidad de BBDD documentales y “flujos” de trabajo (Workflows)) pero ni de lejos se llega al nivel de funcionalidad requerido y menos todavía a la sencillez de parametrización; que conste que con esto no estoy diciendo que IBM no tenga una herramienta o complemento de Lotus Notes que permita ponerse al mismo nivel que SharePoint, y tampoco estoy diciendo que nosotros estemos utilizando correctamente la herramienta, pero con el nivel de conocimiento actual y con los recursos que se asignan al Dpo. de TI, ya es mucho lo que se consigue, y llegar más allá requería una inversión, aún más, de nuestro tiempo libre, el cual nunca será valorado y mucho menos recompensado de algún modo.

Bueno dejando de parte la precaria situación, quiero mencionar que SharePoint ofrece (a mi parecer) de manera sencilla la definición de flujos de trabajo, no obstante su sencillez, no quiere decir que los "flujos” se crean automáticamente, sólo es una herramienta, la lógica la pone una persona con conocimiento del negocio"; espero que este último comentario no ofenda a nadie debido a su trivialidad, pero hay muchos que están ahí, en las cumbres directivas, que viendo una demo de esto, como yo he visto, ya se piensan que todo esto se hace automáticamente o con sólo 5 minutos del tiempo de uno de los "frikis" del Dpo. de TI, y con este erróneo concepto, se limitan a comprar una licencia del producto, creyendo que con esto ya lo tienen todo; y aún peor pasa cuando existe una versión que no se paga, porque el día que se enteran te sueltan que “los del Dpo. de TI de la empresa son unos apalancados, no innovan nunca, sino ¡mira!, ¡mira! Esto es gratis y ¿porqué no lo tengo en mi empresa?, La empresa tal (la de un colega suyo) tienen un sistema que hace todo esto, y yo no acabo de entender porque no lo tengo en la mía, blabla blabla”.

En conclusión, SharePoint, como muchas otras que habrán pero que no he tenido la ocasión de ver en una demostración, es una potente herramienta para entornos de equipos de trabajo, ofrece múltiples funcionalidades que permiten controlar accesos a los recursos compartidos, organización de la información, definición de flujos de trabajo, creación de espacios para compartir el conocimiento, y todo eso que favorece (no hace, eso lo hace la dirección creando políticas organizativas) que un equipo y en general una empresa, sea lo que por definición es: una ORGANIZACIÓN.

Para finalizar, quiero agradecer a Gepesa por el buen trabajo que ha hecho organizando estas sesiones, ya que han sido de muy buena calidad, demostrando a nivel práctico un buen conjunto de las funcionalidades y posibilidades que ofrece SharePoint 2010.

Hasta la próxima enfermos.

19 de junio de 2011

[PHP] Verificación de entradas en arrays multidimensionales (1/2)

conjuntoEntradas() {
  [PHP] Verificación de entradas en arrays multidimensionales (1/2)
  [PHP] Verificación de entradas en arrays multidimensionales (2/2)
}

Ya hace un tiempo que empecé un desarrollo de unas de mis pajas mentales con el conocido framework Web MVC (Model View Controller) denominado Zend Framework. Desde que empecé este desarrollo, el cual he tenido que interrumpir en algunas algunas ocasiones por ciertas obligaciones las cuales me gusté o no tengo que darle preferencias, además de solo poderle dedicar parte de los días que no me empleo en la empresa en la cual estoy contratado a tiempo completo, y digo parte, porque me es imposible no dedicar una parte de esos días a descansar, atender asuntos personales, buscarme la vida por otras partes o hacer otros hobbies muy necesarios para mí, me han ido surgiendo dudas sobre ciertos aspectos del lenguaje PHP; uno de ellos ya lo dejé plasmado en una entrada en este mismo blog hace algún tiempo.

Cuando empecé a descubrir las cosas que me ofrece el propio framework, a día de hoy aún me queda alguna cosa que funcionalidad más bien no por descubrir, sino por utilizar y conocer bien como se utiliza, me dí cuenta que a medida que iba desarrollando mis idas de olla, podría ir modularizando ciertos componentes, que me podrían servir para futuras pajas mentales, además de poder utilizar de manera extensiva en el desarrollo de esta; es decir lo que resumiríamos en arquitecturar código de programación para favorecer el reaprovechamiento mediante creación de componentes genéricos; algo así como ya han hecho los propios desarrolladores de dicho Zend Framework, de ahí que haya acabado en eso, en un framework.

Con todas esta paranoia que me dio y me continúa dando, por el reaprovechamiento basándome en la modularización; una de las cosas que más utilizo es la configuración de los componentes mediante ficheros de configuración, ya sean INI o XML, para poder reutilizarlos sin tener que escribir código de programación.

Zend Framework, ofrece unas clases para leer este formato de ficheros, y alguno más, y después poder obtener un array multidimensional de clave=>valor para posteriormente poder tratar el contenido desde PHP de una manera sencilla. De hecho el propio framework utiliza estos formatos para especificar las configuraciones de la aplicación web que se va a desarrollar y también para configurar parte de sus componentes.

Al empezarlo a utilizarlos en mis componentes y ver que necesitaba, en muchos casos, verificar la existencia de ciertos parámetros obligatorios en los ficheros de configuración, y esto lo tenía que hacer con la verificación de la existencia de claves dentro de los arrays multidimensionales, descubrí que desde PHP se ofrecen varias funciones o maneras de poder verificar la existencia de valores dentro de arrays, así que la paranoia de la optimización se apoderó de mi, provocando una curiosidad, necesaria por hacer cada componente algo más óptimo, por saber cual de ellas tiene un mayor rendimiento en cuanto a velocidad de proceso.

En los comentarios que dejan los usuarios en la documentación de PHP, en varias de las funciones que se pueden utilizar para verificar la existencia de claves, ya se puede saber que algunas de ellas son más óptimas que otras, por ejemplo, la función is_null(), tiene un rendimiento mucho peor que la comparación directamente con NULL, pero esta tiene un rendimiento más bajo si la comparamos con isset(), no obstante de todos estas funciones, aunque nos podrían servir para verificar la existencia de una clave, a mí, particularmente, no me gusta mucho tener que hacer referencia a valores que no van a existir si la clave no existe, que sería lo que tendríamos que hacer con is_null() y con la comparación con NULL, pongamos un ejemplo:

Defino un array que voy a utilizar para todos mis ejemplos y pruebas, dentro de este conjunto de entradas

$var1 = array(
        'clave1.0' => 'valor1.0', 
        'clave1.1' => 'value1.1',
        'clave1.3' => array (
            'clave2.0' => 'value2.0', 
            'clave2.1' => array(
                'clave3.0' => array(
                    'clave4.0' => 'value4.0'
                )
            )
        )
    );

Si quisiéramos verificar la existencia de una clave, con las dos maneas que he comentado, tendríamos que hacer lo siguiente:

if (is_null($var1['clave1.4'])) {
      print "La clave1.4 no exise \n";
  }

  if($var1['clave1.4'] === NULL) {
      print "La clave1.4 no exise \n";
  }

Funcionar, funciona pero no me gusta, porque para la verificación accedemos a una posición del array inexistente, por lo cual se genera para ambos caso el siguiente mensaje de notificación (eso si tenemos el PHP configurado para que notifique los errores del nivel NOTICE):

  PHP Notice: Undefined index: clave1.4 in /path/al/script.php on line NN

Aunque dicho mensaje podríamos provocar que no apareciese anteponiendo @ delante la función o delante la variable en el caso de la comparación con NULL.


Hasta la próxima enfermos.

13 de junio de 2011

El Gobierno de las TIC en la PyME de nuestra querida España


Llevando más de un mes sin pisar el Blog para escribir alguna de mis tonterías, acogiéndome a la gran excusa que utilizamos gran parte de los mortales, “no he tenido tiempo”, aprovecho este maravilloso día, festivo en Barcelona, para perder el tiempo escribiendo una entrada, en este maldito blog, desde el balcón de casa.

Ahora que ya me he disculpado, con la mentira de siempre, voy a pasar a decir de que puñetas voy a hablar; durante este tiempo de “reflexión”, he ido acumulando cosas de las que escribir, algunas incluso las he empezado y no las he terminado y otras se quedarán como cosas que puede escribir pero al no hacerlo, han caducado, al menos por el interés que pueden tener ahora mismo, aunque realmente, pienso que lo que escribo aquí no va mucho más allá de mi propia y absurda satisfacción.

“¡Mierda! Ya me he vuelto a ir por las ramas, perdonad”; el tema gira entorno a este artículo publicado en TNI, el 25 de mayo del 2011, titulado de la siguiente manera: ¿Cómo conseguir un departamento de informática más eficiente?

Sí, habla de la eficiencia del departamento de informática, o más conocido actualmente como departamento TIC, no habla de PyME, ni se enmarca dentro de España, esto lo añado yo, 1) porque empleo mi tiempo currando en una PyME, 2) está dentro de España.

El artículo, a mi parecer dice verdades como puños:
  1. Externalizar sí, pero sólo lo necesario.

    Como en la mayor parte de las tendencias, modas, ideologías políticas, religiones, etc..., irse a los extremos es poco apropiado a medio-largo plazo, esto lo deberíamos saber todo si miramos un poco al pasado; cuantas veces se ha oído, por algún que otro cabreo con o sin fundamento por parte de “directivos”: “me voy a cargar el departamento de informática, lo voy a subcontratar y listo”.
    Así que, directivo, si fue un calentón, no pasa nada a todos nos pasa, sino lo fue echa le un ojo al artículo, que te irá bien para reflexionar.
    Por otra parte, no quiero que se llegue a pensar que estoy diciendo que una PyME, más bien P que M, no deba subcontratar todo su departamento de informática, cuando el tamaño, en cuanto a empleados, es algo normal, ya que no solo se hace con el departamento de informática, sino con muchos otros. Por otra parte, si la mentalidad del directivo de a pié, ya sea de una P o M (no dedicada al negocio de las TIC), es: “la informática que sea invisible, que se limite a funcionar y ya está”, entonces subcontrata este departamento ya que si nos basamos por lo que dice el artículo: “y únicamente externalizar todo aquello que no se considere como valor competitivo diferencial para la empresa.”, claro está que el únicamente se convierte en el 100%.

  2. Organización y procesos del departamento.

    Volvemos a lo mismo sobre lo de no irse a los extremos; parte de una metodología de organización ya probada, ya que si tiene cierta antigüedad y continúa existiendo, es porque muchos se dieron de ostias durante su creación, eso si no te aferres a ella como si de la única verdad se tratara y adáptala a tu negocio, que nadie más bien que tú sabe que peculiaridades tiene.
    Lo que está claro es que tu departamento TIC, tiene que estar organizado y gestionado y con unos procesos claros, definidos y acorde con la empresa y este no se convierta en un grupo de frikis que tienes ahí que continuamente todo los empleados de la empresa tienen el derecho de solicitar las cosas a salto de mata, y si lo prefieres así, luego no pidas plazos (esto se traduce en compromisos) con respecto a otras cosas, que vienen del equipo directivo o que requieren una cierta cantidad de recursos.

  3. Arquitectura tecnológica definida.

    Otras de las cosas que he oído muy habitualmente de la boca de algunos directivos y mandos intermedios es que “no quiero ni oír y menos hablar del software a medida, esto no es una empresa de informática”; muchos creo que no saben ni lo que dicen, porque luego resulta que la empresa, como poco, tiene una Web que no han hecho con ninguno de las aplicaciones de creación de sites que ofrecen las numerosas empresas de hosting y unos cuantos ficheros mdb con algunas tablas, formularios e informes que ha tenido que hacer alguno de los miembros o ex-miembros del departamento TIC; “sí, señores míos, eso también es desarrollo propio, a más pequeña escala, pero lo es”.
    Creo que casi todos, sabemos que dentro de una empresa NO TIC, no se va a desarrollar un paquete de software de ofimática convencional, no se va a desarrollar un DBMS (Data base management system, o para que se entienda más SGBD) y un largo etc. de aplicaciones de uso general, global o estándar, como prefieras llamarlo; lo que si te tienes que enterar es que tu negocio puede tener ciertas particularidades que difícilmente te lo va a ofrecer una solución comercial, al menos en su totalidad, es decir que si quieres que se adapte totalmente a ti, tendrás que parametrizarla y/o implementar ciertos servicios, mecanismos, addins o como quieras llamarles, para no tener que pasar, si no quieres, por el tubo.

  4. Mejor prevenir que curar.

    Esta famosa frase que llevamos escuchando todos desde que llegamos a este mundo y que todos comprendemos pero pocas veces la tenemos presente a la hora de tomar decisiones, y no tiene más transcendencia que correr algún que otro riesgo, que en determinadas ocasiones el riesgo es diversión y como todos nos tenemos que ir a la tumba de vez en cuando incurrimos en él para justificar nuestro corto tiempo que pasamos en este mundo; no obstante no creo que la mayor parte de las decisiones que se toman en una empresa, sean puramente para pasar un buen rato, ya que estas acostumbran a tener una transcendencia a corto, medio y largo plazo. Cierto es, que lo que acabo de comentar se aplica a todas las decisiones, pero si que normalmente se encasillan en ciertas unidades funcionales (normalmente asociadas a un determinado departamento).
    En el caso que me atañe, en el departamento TIC donde trabajo actualmente, esto se da en su totalidad:

    1. ¿pasividad? LA HAY, porque después de tomarse las cosas en serio, e intentar que la dirección se las tome o al menos te escuche, y ver como ni se toman en serio, ni te escuchan, el responsable a pié se acaba cansando con el paso del tiempo y opta por esta postura.

    2. ¿siempre a remolque? SÍ, con los recursos que se destinan, como se inculca a todos los empleados que son (si he dicho que, no quien) “los individuos que están ahí trasteando con las máquinas” y ver las pocas expectativas de cambio te obligan a ir a remoque, muchas veces asumiendo responsabilidades que no llevan a ningún lugar más que tener que dedicar horas de tu tiempo libre a cambio de nada; en este caso por lo que respecta a la tecnología, si que es cierto que puede parecer imposible de cambiar, pero no es por la propia tecnología, más bien por lo que acabo de comentar.

    3. ¿anticiparse? NUNCA, después de emplear tiempo y esfuerzos muchas veces, y la mayor parte fuera del tiempo de trabajo estipulado, para proponer cambios antes de llegar al día 0, y ver que no han servido de nada porque llega el día 0 y los cambios hay que hacerlos ya sí o sí, con la consecuencia de que todo se hace más bien mal por las prisas y falta de previsión acarreando futuros problemas que todavía provocará que el departamento TIC vaya más “a remolque”.

    4. ¿cambios organizativos en el resto de la empresa para que el departamento TIC funcione mejor? JAMAS, los del departamento TIC están para la informática sea invisible a efectos de problemas y funcionamiento individual de cada empleado, así que si que “si usted tiene algún problema informático, sea cual sea, levante el teléfono y marque las extensión del departamento TIC sin ningún reparo, sea urgente o no, ya que lo suyo siempre lo será y las actividades que hacen allí que no sea esta no tienen la mayor importancia”.

Bueno, comentado el artículo y extrapolandolo a la situación que yo estoy viviendo y me atrevo (siempre teniendo en cuenta que es mi punto de vista personal) después de haber contrastado con otros compañeros del sector y dentro de España y haberlo visto a primera vista en alguna que otra PyME, a concluir qué: es una tónica habitual dentro de la PyME de esta España, para empresas cuyo negocio no son las TIC, dejando comentarios de estas a parte ya que no he tenido la experiencia de haberlo vivido ni tampoco oído de manera explícita.

Y a tú, si te encuentras en esta situación de directivo y detectas todo esto, si crees que esto puede ayudar a mejorar tu negocio cara al futuro puedes empezar a tomar medidas, no hace falta que las apliques de golpe, Roma no se creo en un día; eso sí, si eres de los que te has comido un MBA, creo que verás claramente que muchos de los aspectos, o al menos una parte, se enmarcan claramente dentro de las buenas prácticas de administración del negocio y sino es así empieza a plantearte si no perdiste el tiempo haciéndolo, ya que creo, que poco de todo lo que te contaron te llego.


Hasta la próxima enfermos!

1 de mayo de 2011

SPF v1 en Gmail ¿como funciona?


Un día mirando un poco el buzón de SPAM de una cuenta de Gmail me encontré con un correo de phishing de Twitter el cual Gmail, además de haberlo etiquetado como SPAM, le había metido una alerta, muy resaltada, avisando de que el email no era legítimo del emisor indicado.

Mensaje clasificado como SPAM con aviso de un remitente no legítimo

A raíz de esto me empezó a picar la curiosidad y decidí ver las cabeceras de ese email.

Además me fui al link informativo ("Learn more") para ver que me contaban más acerca de este aviso (echarle un ojo al link si queréis ver que dice gmail acerca de todo esto).

Todo esto me hizo recordar a un conjunto de post que escribió el Maligno, los cuales me leí con mucho mimo para entender bien lo que explicaba y ahora que los menciono aquí aprovecho para darle las gracias por escribirlos; en ellos explicaba las sutiles diferencias entre SPF y SenderID y como eran interpretados por los servicios de correo de Gmail y Hotmail.

Maligno nos indicaba como conclusiones de sus pruebas que Gmail, las cuales cito de nuevo a continuación:
  • PRIMERO: Gmail aplica From: y no Sender:.
  • SEGUNDO: No elimina el correo aún cuando lee la política del dominio que él ha decidido.
  • TERCERO: No muestra ninguna alerta al usuario.

Claro está que la conclusiones que él sacó eran totalmente ciertas para la prueba que realizó, pero después de haber visto el correo comentado arriba ya no tengo claro si siempre es así o no.

En el caso de este correo phisheado de Twitter, parece que:
  1. Gmail no siempre coge el campo From: para verificar el resultado de SPF (Sender Policy Framework); en este caso deduzco que ha cogido el campo Return-Path: o a saber el que durante la transmisión del email a los servidores de Gmail.
  2. A veces si que muestra alertas.

A parte de estas evidencias, me dedique a revisar la política SPF del dominio indicado en la dirección presente en el campo Return-Path: (pcavote.com). Revisando dicha política, yo no logré identificar que la IP [85.92.129.132] que envió el correo, que correspondía al servidor reseller06.pcextreme.nl, fuese un servidor reconocido del domino pcavote.com; aunque la política de dicho dominio es SOFTFAIL (~), es decir que el receptor debería dejar pasar los correos recibidos de servidores no reconocidos por la política SPF, si que es cierto que puede clarificarlos de manera especial para alertar al usuario, que parece que es lo que ha hecho Gmail al etiquetarlo como SPAM, pero realmente si revisamos dichas cabeceras, no es así, ya que el resultado del SPF es PASS, y según is observaciones (ATENCIÓN puedo haberme equivocado) el emisor no está reconocido por la política así que el resultado tendría que ser SOFTFAIL.

A continuación os dejo la serie de consultas DNS para lograr obtener todas las IPs que estarían autorizadas para enviar correos bajo el dominio pcavote.com:

> server 8.8.8.8
Servidor predeterminado:  google-public-dns-a.google.com
Address:  8.8.8.8

> set type=txt
> pcavote.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

pcavote.com     text =
        "v=spf1"
        "mx"
        "a:mailhost.sparkred.com"
        "include:sparkred.com"
        "~all"

> set type=mx
> pcavote.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

pcavote.com     MX preference = 10, mail exchanger = dmx1.bfi0.com

>set type=a

>dmx1.bfi0.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

Nombre:  dmx1.bfi0.com
Address:  208.70.143.4

> set type=a
> mailhost.sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

Nombre:  mailhost.sparkred.com
Address:  67.228.250.41

> set type=txt
> sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

sparkred.com    text =
        "v=spf1"
        "a"
        "mx"
        "a:mailhost.sparkred.com"
        "~all"

> set type=a
> sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

Nombre:  sparkred.com
Address:  75.126.129.131

> set type=txt
> sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

sparkred.com    text =
        "v=spf1"
        "a"
        "mx"
        "a:mailhost.sparkred.com"
        "~all"

> sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

sparkred.com    MX preference = 10, mail exchanger = webmail.sparkred.com

> set type=a
> webmail.sparkred.com
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

Nombre:  webmail.sparkred.com
Address:  174.37.50.21

Y el resultado de IPs obtenido de las consultas anteriores:



En este punto ya no entendía nada, es decir, o yo no entiendo como funciona bien el SPF y por lo tanto algo se me escapa, o Gmail no implementa el SPF como se índica en el estándar (RFC 4408); debido a esto no me quedé tranquilo y me fui a buscar lugares donde pudiese hacer alguna prueba de concepto más, como hizo el Maligno en su día.

Así que me busque una bonita web que me dejase enviar cosas a los colegas y envié un email al Gmail indicando que era un pavo de La Caixa (lacaixa.es), es decir utilicé el mismo dominio que utilizó el Maligno en sus pruebas.

Envío de email a través del formulario de “enviar a un amigo” de una web


Recepción en Gmail del email enviado desde el formulario web “envía a un amgio”

Y el resultado obtenido es el mismo, se colo en buzón de entrada sin ningún tipo de alerta y con un resultado de SPF a FAIL; aunque esta vez la cabecera del correo no lleva ni el campo Sender: ni X-Sender:, pero sí Retun-Path:.


Cabeceras del email recibido enviado desde el formulario web de “envía a un amigo”

Aún después de todo esto no me quedé satisfecho y decidí probar el mismo ejemplo sobre otra web de las que también permite enviar cosas a colegas y ver de nuevo que pasaba.

Recepción en Gmail del email enviado desde otro formulario web “envía a un amgio”

El resultado obtenido con esta última prueba fue sutilmente distinto, se coló en el buzón de entrada, pero el resultado del SPF fue PASS, tampoco tenía campos Sender: ni X-Sender:, pero si que tenía también el campo Return-Path:, pero no con el valor de la cuenta de correo del supuesto emisor, sino con una cuenta del dominio que envía los correos introducidos en el formulario web, de ahí a que el resultado del SPF fuese PASS, ya que este dominio no tiene una política SPF definida.

Cabeceras del email recibido enviado desde otro formulario web de “envía a un amigo”

Y las consultas que hice sobre el dominio voc-servicios2.sarenet.es fueron:

> set type=a
> voc-servicios2.sarenet.es
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8
Respuesta no autoritativa:

Nombre:  voc-servicios2.sarenet.es
Address:  194.30.33.176

> set type=txt
> voc-servicios2.sarenet.es
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8

sarenet.es
        primary name server = ns1.sarenet.es
        responsible mail addr = dnsmaster.sarenet.es
        serial  = 2011032204
        refresh = 86400 (1 day)
        retry   = 7200 (2 hours)
        expire  = 2592000 (30 days)
        default TTL = 300 (5 mins)

> set type=mx
> voc-servicios2.sarenet.es
Servidor:  google-public-dns-a.google.com
Address:  8.8.8.8

sarenet.es
        primary name server = ns1.sarenet.es
        responsible mail addr = dnsmaster.sarenet.es
        serial  = 2011032204
        refresh = 86400 (1 day)
        retry   = 7200 (2 hours)
        expire  = 2592000 (30 days)
        default TTL = 300 (5 mins)

De todo esto puedo sacar algunas conclusiones, además de las que ya sacó el Maligno, como que Gmail no garantiza un aviso aunque el resultado SPF de los emails recibos sea FAIL.
  1. Gmail utiliza el dominio del campo Return-Path: para calcular el resultado SPF.
    He podido observar que en varios emails que el campo siempre está presente, o con una dirección (parte local, o del dominio o ambas) distinta del campo From: o sino con el mismo valor.
  2. Si el valor del campo Return-Path: difiere del campo From: entonces aparece en los detalles de la cabecera del email un campo denominado mailed-by con el dominio de la dirección presente en el campo Return-Path:.

Hasta la próxima enfermos.


21 de abril de 2011

Se nos pasa por la cabeza meter nuestros ficheros en la nube (Dropbox)


Introducción
El otro día cuando ya me largaba de la empresa me llegó lo que ya hacía un tiempo que esperaba que llegase; “Oye que estamos valorando esto del Dropbox, que todo el mundo está utilizando y que se habla tan bien, para meterlo como herramienta de trabajo, ya que tenemos que aprovechar este tipo de servicios que están ahí ¿que opinas?”

Bueno llegado a este punto, a mi que no me gusta, como norma general y siendo bastante estricto, decir que algo es como es cuando no estoy el 99% seguro de que es así, el 1% restante considero que es pocas veces alcanzable, quitando lo de la muerte, empecé a decir lo que ya conocía que era cierto, lo que conocía sin seguridad advirtiendo de que no estaba seguro (porque ha venido de voces en off) y de lo que podía intuir, claro está indicando que lo intuía pero que tenía que contrastarlo.

El que me pillo por banda es uno de los directivos junto con varios miembros del grupo de trabajo, el cual él también dirige (la empresa no es tan grande para que el directivo solo dirija la empresa), y todo venía, entiendo, porque algunos de los miembros del grupo de trabajo ya están utilizando los servicios de Dropbox a nivel personal, y que me les mola (con esto no quiero decir que el servicio no mole), han empezado a darle la brasa al manager seguramente pensando: “si vamos al departamento de IT a pedirle esto con lo paranoicos que siempre están con ciertos temas, como la seguridad, la privacidad, etc. y lo poco que les gusta implantar nuevas soluciones en la empresa, nos van a mandar a tomar por c....”.

Dejando de banda lo “bien vistos” que estamos los del departamento de IT, por el resto de personal interno de la empresa, todo acabó en que nos reuniríamos un día y hora concreto (el cual llegado el día no ha habido ni reunión ni comunicación de aplazamiento, es decir como si no se hubiese dicho nada), el cual yo tendría que estar informado de el funcionamiento (tal y como se explique o se informe por parte del equipo técnico de Dropbox, no estoy hablando de que tuviese que hacer ningún tipo de Ingeniería Inversa, ni de poner en duda lo que ellos anuncien y vendan de su servicio) para poder explicarse y resolver las dudas que se habían surgidos en la previa.

Así que como, no soy un usuario activo, por ahora, de este tipo de servicios, no porque los encuentre inútiles, sino porque por ahora no he tenido necesidad de utilizar este tipo servicios, de ahí que no tenga todas sus características en mente, me puse a mirar la FAQ de Dropbox, la cual encontré muy completa, para saber más de su funcionamiento y de ahí ver que posibilidades puede ofrecer, además de poder responder a las dudas que ya se habían planteado (algunas con sugerimientos de que este suprimiese a servicios que ahora ofrecemos desde nuestros servidores) y a las nuevas que podían surgir en la reunión; y de todo esto salio un resumen de las características, el cual os dejo a continuación.

Resumen de características de Dropbox

Cuentas de miembros

  • No se específica un límite de equipos que se sincronizan con una misma cuenta. En la gestión de la cuenta se puede ver los equipos adheridos a la cuenta.
  • Tamaño máximo de ficheros igual a la cuota disponible en la cuenta. En el caso de subir ficheros a través de la web el límite es de 300 Mb.
  • No hay máximo número de ficheros, la cuota de almacenamiento marca el límite. Actualmente se estima que el rendimiento puede verse afectado si se almacenan más de 100.000 ficheros.
  • Transferencia de información aplicando diferencia binaria; solo se sincroniza la información que realmente ha variado.
  • Soporta la sincronización de atributos de los ficheros (derechos, meta datos, etc.), pero se pueden perder si se modifica la información en unidades con formatos de ficheros que no soportan metadatos, por ejemplo FAT32.
  • Recuperación de estines anteriores.
    menú de recuperación versiones ficheros
    listado de versiones de un fichero

    Se mantienen la versiones de cambios durante 30 días, no obstante hay la opción, en las cuentas Pro, de activar el Pack-Rat; las versiones mantenidas no computan en la cuota de espacio de la cuenta.
    No obstante se permite eliminar los ficheros de manera permanente.
  • Permite vínculos únicos a los ficheros en los directorios de acceso público. Con esta funcionalidad se puede agregar estos vínculos en páginas web, e-mails, etc.
  • Se puede compartir directorios con los usuarios registrados en Dropbox que se quiera, atendiendo al uso de espacio en la cuenta.
    Cuando se comparte un directorio, se comparte con derechos de modificación total (adición, modificación y borrado de ficheros existentes), puesto que derechos de solo lectura aplicados sobre un sistema operativo no tiene porque transcender sobre otros sistema operativo, no obstante los atributos del fichero si que son copiados en los servidores de Dropbox. Además los usuarios que han sido invitados, por el propietario de la cuenta, para poder acceder al directorio compartido pueden invitar a otros usuarios al directorio. Solo el propietario puede eliminar usuarios que tienen acceso al directorio compartido.
  • Se puede añadir comentarios sobre los directorios compartidos para facilitar la comunicación con el resto de miembros con acceso al directorio.
  • Se puede renombrar y mover directorios compartidos a nivel de cuenta y gestión interna de la información, no obstante el nombre y la ubicación como ha sido compartido permanecerá inalterable bajo estos cambios.
  • La gestión de conflictos de cambio de ficheros al mismo tiempo se gestiona con el algoritmo “La primera versión que se sube al servidor, gana”, es decir no se utiliza ningún algoritmo de fusión de versiones; no obstante no se descartan las versión que han “perdido”, se mantiene con la siguiente nomenclatura: {nombre del fichero} ({nombre usuario que ha creado esa versión} copy {momento de creación de la versión})
    ejemplo de versión de un fichero generada por conflicto

  • Sincronización LAN. Se incorpora un mecanismo de detección de ordenadores que se sincronizan con una misma cuenta o directorios compartidos con acceso de las distintas cuentas que utilizan distintos ordenadores dentro de una misma Red de Área Local (LAN) para sincronizar los ficheros o directorios cambiados entre ellos antes de sincronizar con los servidores de Dropbox; evitando el consumo de ancho de banda de la conexión de Internet de la LAN.
    Este mecanismo solo es aplicable en una misma subred.
  • Como Dropbox puede utilizarse en múltiples sistemas operativos y esto tienen distintas reglas en los nombres de los ficheros, codificaciones, etc, normalmente al sincronizar este tipo de ficheros con otro sistema operativo que lo ha generado puede degenerar en la creación de una nueva versión del fichero marcada como conflicto o no llegarse a descargarse en el sistema operativo receptor. Las distintas casuísticas documentadas se pueden consultar en https://www.dropbox.com/help/145
Añadidos para cuentas de grupos
  • Gestión de usuarios centralizada desde las cuentas de administradores.
  • El administrador puede ver la cuota de almacenamiento utilizada sobre el total (todos los miembros) y la cuota utilizada por cada miembro.
  • Cuota de espacio de almacenamiento computada en sobre el grupo no limitado al espacio de cada cuenta de miembro individual.
  • Se puede quitar a un miembro del grupo el acceso a un directorio compartido y se puede optar por solo quitarle el acceso al directorio o también indicarle que le elimine los ficheros almacenados en su disco duro.
  • Los miembros que vayan a formar parte de una cuenta de grupo deben convertir su cuenta existente a una del tipo miembro de grupo o crear una una cuenta de miembro de grupo. Si utilizan una cuente existente y la convierten en una cuenta de grupo, el usuario mantendrá sus ficheros, directorios compartidos y sus documentos públicos; si se genera un nueva cuenta, tendrán que proporcionar una dirección de correo distinta, no obstante el usuario puede cambiar su cuenta de correo asociada a la cuenta de Dropbox en cualquier momento desde la interfaz web.

Nota informativa: Información extraída del centro de ayuda (Help Center) de la Web de Dropbox a fecha de 15/04/2011 y no está exenta de errores de interpretación o traducción.


Hasta la próxima enfermos.

16 de abril de 2011

OWASP VII Spain Chapter Meeting


Después de asistir el viernes por la tarde a la OWASP VIII en Barcelona, puedo decir que me ha sido muy útil para enterarme de los ataques de Session Fixation, algo que me sonaba de oído pero que al no haber profundizado sobre el tema, básicamente leyendo, consultando, viendo, escuchando o cualquier otra manera que se os ocurra de absorber conocimiento, desconocía de que se trata realmente, que modus operandi tiene y como se pueden abordar medidas preventivas para evitar que las aplicaciones web sufran este tipo de ataque.

La ponencia realizada por Raúl Siles, de Taddong, denominada “SAP: Session (Fixation) Attacks and Protections (in WebApp)” ha sido, a mi criterio, de lo más interesante, ha explicado que es, que tipo de aplicaciones son atacables, como se ataca, directrices para prevenir o al menos mitigar lo máximo posible el ataque y ha expuesto como ejemplo su experiencia sobre la vulnerabilidad que detectó en SAP y cual fue su trascendencia desde el descubrimiento y notificación hasta su solución y la notificación pública de ésta.

El resto de ponencias también me han aportado, en menor medida, seguramente porque mi interés era menor, y en el caso de la primera, “Web Attacks In The Wild: An overview of las year's probes” de Adrián Pastor, por haber llegado al menos a la mitad de la ponencia, conocimiento sobre ataques web, el estado de los estándares de medios y certificaciones de aplicaciones de pago y como responder a incidentes de infecciones web, desde la preparación del entorno hasta el análisis de los incidentes, pasando por la respuesta que hay que dar sobre estos, de la mano de Carles Fragoso Mariscal, responsable de respuesta a incidentes de CESICAT.

Después de todo esto ya se pasó al debate, donde se discutió de ciertos aspectos bajo el tema principal: El robo de datos de tarjeta como objetivo de los ciberdelicuentes: ¿conocemos el mercado negro asociado?; el cual, al menos yo, disfruté mucho, ya que siempre me gustar escuchar, valorar y si tengo opción, ser crítico en lo que se dice, respetando las creencias y pensamientos de cada uno siempre que se argumenten.


Hasta la próxima enfermos.

6 de abril de 2011

Si eres un banco, cuida tu SPF


El otro día pedí una información, por email, de los servicios que ofrece una de las nuevas entidades bancarias que están apareciendo con el revuelo económico que últimamente está habiendo con las cajas de ahorro.

Aunque lo que realmente pedí fue que me llamasen, posterior conversación telefónica me enviaron un email con todo lo que me habían comentado por teléfono, junto con un enlace donde darse de alta como cliente.


Parte del cuerpo del email de bancacivica.es con el enlace al formulario de alta de nuevos clientes

Debido a todo lo que leo, escucho, etc. de todo lo que pasa con la seguridad del mundo virtual y después de leer informes de claramente indican que zapato calzan las organizaciones criminales que se encuentran detrás, a uno le entra la paranoia constante de sino te están intentando timar además de tener la inseguridad de que cada vez que inicio sesión en el la extranet de una entidad financiera no te estarán robando los credenciales bancarios para que puedan hacer una mejor administración e inversión de la que tu haces con tus ahorros.

Bueno, debido a que al leer el correo entré en estado paranoico, me aseguré de verificar un poco las cabeceras del email recibido para ver de donde viene y por donde ha pasado (que me refiero a lo que ha quedado registrado).


Cabeceras del email recibido de bancacivica.es con el enlace al formulario de alta de nuevos clientes

Todo me parecía normal si no fuese porque el resultado del SPF había dado error, y como no, Gmail no había notificado mediante algún aviso de ello.


Cabecera del email bancacivica.es sin aviso alguno del fallo SPF

El error que se había producido era un “temperror” debido a un timeout en la consulta DNS para la obtención del valor del registro TXT del dominio.
Así que no me quede muy tranquilo viendo esto, por lo entonces un simple fallo en la consulta puede originar que no se verifique el filtro SPF, dando un “temperror” y el mail se cuele sin aviso alguno.
Lo primero que pensé es que debía haber sido un error esporádico, pero no fue así ya que como tenía otro correo recibido, desde la misma dirección de envío, anterior a este, me fui a ver las cabeceras de este y … ¡sorpresa! Se había producido el mismos error.

“Pues vaya, vamos a ver que pasa con el registro SPF de bancacivica.es”; así que me fui ha consultar el registro TXT del dominio y ver si podía sacar algo en claro.

Valor del registro TXT del dominio consultado en varios servidores DNS

Como podéis ver en la captura anterior al intentar conseguir el valor del registro TXT del dominio desde el servidor DNS de Google, se origina un error de timeout, así que de ahí que se explique el resultado que obtiene los servidores de Gmail. No obstante también podéis ver el resultado de la consulta sobre otros dos servidores DNS, el de Terra y el OpenDNS, los cuales no generan error y nos devuelven el resultado del registro.

Claramente podemos ver que tienen una sintaxis incorrecta: ~all- (el guión final no debería estar).

Verificación de la sintaxis del registro TXT en Kitterman

Bueno son cosas que pasan, todos nos equivocamos y muchas veces a la hora de teclear se nos van los dedos, pero claramente podemos ver que después de aplicar el filtro nadie se ha preocupado de verificarlo.

Con todo esto acabo de aprender dos cosas:
  1. Gmail no me dará ningún aviso si hay un error de timeout sobre la verificación SPF.
  2. Si me toca crear algún filtro SPF en futuro, acordarme que luego lo verifique (sobre todo si es para un sector donde la autenticidad de los emails es importante, como una entidad bancaria).


Hasta la próxima enfermos.

19 de marzo de 2011

[PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)

conjuntoEntradas() {
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)
}


El rendimiento

Hasta aquí podía apaliar una de mis inquietudes, que era el nivel de integridad de los atributos de un objeto para cada una de las maneras de tratar los parámetros de los métodos y su asignación a estos, pero todavía me quedaba otra pendiente, que era saber el rendimiento de cada una de estas formas.

Ya se que en el rendimiento de una aplicación están involucrados muchos factores y cuando tu escribes un código, el orden de ejecución de las instrucciones puede ser alterado por el compilador con el objetivo de optimizar el código para una ejecución más eficiente, no obstante siempre que programa y me encuentro delante de los ojos que el orden de ciertas instrucciones podría ser cambiado, a priori por una más optima, si no me aleja enormemente de lo que estoy haciendo, hago el refactoring, o sino me lo marco con @todo; ya sé que ha veces esto puede ser un poco de maniático o de paranoico, pero es algo intrínseco en mi personalidad junto con la concepción de que las pequeñas cosas forman el todo, por lo que si ese pequeño cambio puede llegar a optimizar una mil millonésima parte de la ejecución, lo aplico de todas formas, siempre pienso “mejor eso que nada”.

Bueno dejando de lado mis paranoias, os dejo la modificación del código de la prueba anterior de manera que me permitiera analizar la carga de ejecución de cada manera de pasar parámetros y de asignación de estos atributos.

class A {
    private $arrValor;
    private $arrValorToRef;
    private $arrReferencia;
    private $arrRefToRef;
    

    public function setArrayByValue(array $setArr) {
        $this->arrValor = $setArr;            
    }

    public function setArrayByValueToRef(array $setArr) {
        $this->arrValorToRef = &$setArr;            
    }

    public function setArrayByRef(array &$setArr) {
        $this->arrReferencia = $setArr;
    }

    public function setArrayByRefToRef(array &$setArr) {
        $this->arrRefToRef = &$setArr;        
    }

}


$numIt = 1000000;
$arr = array('key0' => 'value0');
$objA = new A();

for ($it = 0; $it < $numIt; $it++) {
    $objA->setArrayByValue($arr);
    $objA->setArrayByValueToRef($arr);
    $objA->setArrayByRef($arr); 
    $objA->setArrayByRefToRef($arr);
}

La modificación del script de prueba está clara, solo he dejé en los métodos de las clases declarada la asignación del parámetro al atributo, que es lo que quería comparar a nivel de coste de ejecución, y en la ejecución del script iterar unas cuantas vueltas dentro de un bucle la llamada a los cuatro métodos.

Para saber el coste de ejecución lo que hice es ejecutar el script en un profiler, concretamente el de xdebug; hice dos pruebas, una con 1.000.000 iteraciones y otra con 3.000.000 de iteraciones; ¿porqué tantas? para que el profiler pudiese medir con mayor precisión la diferencia entre cada llamada y ¿porqué dos veces?, para ver si los valores se obtenidos daban valores diferenciales similares entre las llamadas de los distintos métodos.

El resultado que obtuve fue el siguiente:

 Gráfico de llamadas a los métodos con 1.000.000 de iteraciones


Tabla de porcentaje de tiempo de carga sobre el total de llamada a los métodos con 1.000.000 de iteraciones

Gráfico de llamadas a los métodos con 3.000.000 de iteraciones

Tabla de porcentaje de tiempo de carga sobre el total de llamada a los métodos con 3.000.000 de iteraciones

Después de los resultados obtenidos a partir de los ficheros generados por el profiler con la ejecución del script, y haber sacada los gráficos y las tablas anteriores de cada ejecución con el visor kcachegrind, me decidí a poner los valores en un hoja de cálculo para poder analizar de manera más cómoda los resultados.

 Valores de los resultados, medias y diferencias entre ellos

Como podemos observar, y era de esperar, el método más eficiente es pasar el parámetro por referencia y asignar la referencia al atributo, ya que no se hace ninguna copia del array pasado por parámetro. Lo más curioso es que el siguiente más eficiente es el método que se pasa el parámetro por valor y se asigna por valor (setArrayByValue), estando por delante de los otros dos, yo, si no hubiese hecho esta prueba, hubiese intuido que éste sería el menos eficiente, ya que debería estar haciendo dos copias del array, una cuando lo pasa por parámetro y la otra cuando lo asigna a la variable, mientras que los otros dos deberían tener costes similares ya que hacen una copia del array.

Conclusiones

Después de lo visto tengo claro que para mantener la integridad y el encapsulamiento de los atributos de una clase en PHP, tengo que pasarlo por parámetro y asignarlos por parámetro, ya que si todo son referencias (parámetro y asignación al atributo), como ya suponía, los valores pueden ser modificados desde fuera; además después, de lo observado, también tengo claro que de nada sirve pasar el parámetro o asignarlo al atributo por referencia, ya que no introduce optimización ninguna, es más, el rendimiento disminuye, ya que la ejecución es más costosa.
Además de todo esto, me puedo despreocupar de que ciertas referencias queden apuntando espacios de memoria liberados, ya que el interprete garantiza la destrucción de los espacios de memoria, solo cuando no haya ninguna variable que pueda referenciar a éste.


Hasta la próxima enfermos.

12 de marzo de 2011

[PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)

conjuntoEntradas() {
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (1/2)
  [PHP] Arrays pasados por parámetro ¿copias o referencias? (2/2)
}


Introducción

Realizando mis jugueteos con la programación en PHP, una de las cosas que necesitaba hacer era pasar arrays a objetos de clases creadas por mi mismo; en algunas de estas clases he considerado oportuno mantener los valores que se pasan por parámetro a través de un array en uno de los atributos de la clase debido a que me pueden ser necesarios para realizar operaciones futuras con o sobre esos valores.

Hasta aquí nada nuevo, ya que es una práctica muy utilizada; pero a mí, que no soy, para nada, un “ninja” del PHP, me hizo pensar que realmente sucedía al pasar un array por parámetro de las distintas maneras que permite el lenguaje, valor o referencia y la manera de asignarlo a un atributo, valor o referencia. Por mis conocimientos, sabía los distintos comportamientos que podían suceder pero, al no estar seguro de cual sería el que se aplicaría en PHP, y si teniendo lo muy claro en otros lenguajes donde tu puedes controlar las posiciones de memoria con referencias y, con mayor control, con punteros, como es el caso de C y su hermano C++.

Como después de buscar y revisar un poco la documentación y algunos enlaces de cuatro búsquedas por Internet no me continuaba sin quedar del todo claro, decidí hacer un script PHP muy simple que me permitiera observar el comportamiento del lenguaje antes esta común situación.
La pequeña prueba
El script que cree, hace lo siguiente:
  1. Declara una clase con:
    • Tres atributos; uno para almacenar el parámetro que se pasará a a cada uno de los tres métodos declarados.
    • Tres métodos, cada uno recibe un array por parámetro, pero uno lo recibe por valor y los otros dos por referencia; la diferencia entre los dos métodos que reciben el array por referencia está en su interior, además de que cada uno asigna el array a un atributo distinto, uno lo asigna el valor y otro asigna la referencia.
      Cada método, además de asignar el array a un atributo, realiza una modificación (añade un nuevo valor) en el array pasado por parámetro.
    class A {
        private $arrValor;
        private $arrValorToRef;
        private $arrReferencia;
        private $arrRefToRef;
        
    
        public function setArrayByValue(array $setArr) {
            $this->arrValor = $setArr;
            $setArr['keyMarkClassAValue'] = 'valueMarkClassA';
            $this->arrValor['keyClassA'] = 'valueClassA';
        }
    
        public function setArrayByValueToRef(array $setArr) {
            $this->arrValorToRef = &$setArr;
            $setArr['keyMarkClassAValueToRef'] = 'valueMarkClassA';
            $this->arrValor['keyClassA'] = 'valueToRefClassA';
        }
    
        public function setArrayByRef(array &$setArr) {
            $this->arrReferencia = $setArr;
            $setArr['keyMarkClassARef'] = 'refMarkClassA';
            $this->arrReferencia['keyClassA'] = 'refClassA';
        }
    
        public function setArrayByRefToRef(array &$setArr) {
            $this->arrRefToRef = &$setArr;
            $setArr['keyMarkClassARefToRef'] = 'refToRefMarkClassA';
            $this->arrRefToRef['keyClassA'] = 'refToRefClassA';
        }
    
    }
    
  2. Declara una array con un valor en su interior, el que se utilizará para pasarlo a los tres métodos de un objeto, de la clase declarada, creado.
    $arr = array('key0' => 'value0');
    
  3. Se van realizando dumpeos del array utilizado como parámetro y del objeto a medida que se van ejecutando los métodos para observar comportamiento.
    print "Contenido del array \$arr antes de asignarlo a la clase: \n";
    var_dump($arr);
    print "\n";
    
    $objA = new A();
    $objA->setArrayByValue($arr);
    
    print "Contenido del array \$arr despues de asignarlo a la clase por valor: \n";
    var_dump($arr);
    print "\n";
    
    $objA->setArrayByRef($arr);
    
    print "Contenido del array \$arr despues de asignarlo a la clase por referencia: \n";
    var_dump($arr);
    print "\n";
    
    $objA->setArrayByValueToRef($arr);
    $objA->setArrayByRefToRef($arr);
    
    print "Contenido del object de A despues de asignarle el array (valor y referencias): \n";
    var_dump($objA);
    print "\n";
    
    $arr['newKey'] = 'newValue';
    
    print "Contenido del object de A despues de ejecutar \$arr['newKey'] => 'newValue': \n";
    var_dump($objA);
    print "\n";
    
    unset($arr);
    
    print "Contenido del object de A despues de ejecutar un unset() del array: \n";
    var_dump($objA);
    print "\n";
    

El encapsulamiento

Con la salida que genera el script podemos llegar a ciertas conclusiones sobre lo que sucede con la asignación del array pasado por parámetro a los atributos del objeto, con las distintas maneras que se permiten, y ver si realmente el atributo del objeto mantiene una referencia a esa posición de memoria o copia el valor, desde el punto de vista de utilización habitual del lenguaje, es decir sin buscar saltarnos lo establecido, ya que al referirme que se puede estar copiando el valor del array a otra posición de memoria, me refiero a la percepción que se tiene como desarrollador, dejando de lado el funcionamiento interno del interprete, ya que este podría estar optimizando el rendimiento de la ejecución demorando la copia de los valores a una nueva posición de memoria hasta el momento antes de que alguno de los valores de la variable sufra una modificación, garantizando e esta manera la integridad de los valores de cada variable.

El resultado obtenido es el siguiente:
  1. Parámetro por valor y asignación por valor. Variable pasada por parámetro y atributo utilizan su propio espacio de memoria.
  2. Parámetro por valor y asignación por referencia. Variable pasada por parámetro es copiada a un nuevo espacio de memoria ya que cuando se asigna por referencia al atributo (su dirección de memoria), los cambios en los datos de cada variable son independientes.
  3. Parámetro por referencia y asignación por valor. Variable pasada por parámetro, supuestamente no es copiada, ya que se está pasando por referencia, pero al asignarla al atributo es cuando se realiza una copia de los datos de esta variable a nuevo espacio de memoria que será donde apuntará el atributo al que se está asignando.
  4. Parámetro pasado por referencia y asignación por referencia. No hay copias de los datos a nuevos espacios de memoria por lo que, tanto la variable pasada por parámetro como el atributo apuntan al mismo espacio de memoria.

Con las cuatro pruebas anteriores se puede deducir que las referencias en PHP son tratadas como en otro lenguaje, como C/C++ (donde el control de la memoria depende totalmente del desarrollador), pero con algo menos de liberta, ya que el lenguaje controla el número de variables que apuntan al mismo espacio de memoria y bajo la existencia de una sola, se imposibilita su liberación impidiendo que una variable haga referencia a un espacio de memoria destruido (caso b), además de también imposibilitar la liberación solicitada explícitamente (unset).

Esto ya me permitía saber que sucedía, en PHP, con los arrays, cuando son utilizados como parámetro en una función/método y en las asignaciones a nuevas variables, pudiendo decidir como hacerlo, si por valor o por referencia, en función de lo que realmente quiero hacer con ellos.
Este tipo de dudas siempre se me plantean con los lenguajes, donde el control de la memoria se hace automáticamente mediante un garbage collector, ya que en algunos, como Java, que aunque no existe el concepto de referencia y valor, si que existen los immutable objects en el mismo JDK, provocando un comportamiento distinto, en objetos de ciertas clases, delante de estos casos.

Hasta la próxima enfermos.

19 de febrero de 2011

Multilingüismo intrínseco


Desde que aprendí a programar, siempre me han interesado conocer distintos lenguajes de programación.
Aunque el conocimiento de distintos lenguajes me interesa, también me interesan muchas otras cosas, es que soy un poco todo terreno, así que no dedico todo mi tiempo libre al aprendizaje de estos, más bien los aprendo cuando tengo una necesidad ya sea de interés propio o bajo encargo.

Recuerdo cuando aprendí a programar, no hace tanto tiempo, fue durante mi primer año de universidad, ya que yo no soy de los que en mi casa hubo un ordenador desde los inicios, porque no había una cultura tecnológica, y aunque si que es cierto que tuve un ordenador unos años antes de empezar en la universidad, solo mantuve unos pequeños contactos con la programación, pero nada serio, así que para mí, mis inicios fueron durante el primer curso universitario.

Yo soy de esos a los que le enseñaron a programar en PASCAL; aunque cuando yo empecé a estudiar en la universidad el lenguaje ya estaba un poco “desfasado”, aunque ahora he descubierto que parece que no tanto, y muchos nos preguntábamos porque cojones nos enseñaban a programar con este lenguaje, he de reconocer que después de terminar el trimestre y empezar el segundo trimestre con C, agradecí que me hubiesen enseñados las bases de la programación (imperativa) con este, ya que la sintaxis es muy parecida a pseudo código, y eso te permitía aislarte de la sintaxis del lenguaje y centrarte en lo que realmente había que aprender, que era la lógica de programar, es decir la elaboración del algoritmo que debía cumplir que a partir de unas precondiones se obtuvieran las postcondiciones.

Después de todo esto y de haber saltado de lenguaje en lenguaje (no han sido tantos como pueda parecer la expresión) te das cuenta que, si no tenemos en cuenta un cambio de paradigma, todo es más de lo mismo:
  1. Aprender la sintaxis a medida que escribes las primeras linea de código, consultando código ya escrito para las instrucciones más utilizadas y la documentación para las instrucciones que se usan menos.
  2. Aprender la API básica de las estructuras de datos y funciones compuestas ya implementadas que se ofrece con el propio lenguaje, para ver que podemos hacer en una sola llamada y no tener que estar consultando la documentación en todo momento.

Está claro que ese aprendizaje requiere un tiempo, y que dependiendo del lenguaje y de los lenguajes que ya conoces, por similitudes de sintaxis que se dan entre ciertos lenguajes, la curva de aprendizaje será más o menos pronunciada; no obstante es solo dedicar un poco de tiempo, sin mucha más complejidad, estás últimas vienen más de la mano del objetivo a acometer, es decir de la funcionalidad de lo que quieres desarrollar.

No obstante, cuando ya conoces un lenguaje y saltas a la aventura de uno nuevo, a mí se me plantean ciertas incógnitas que o bien las resuelvo con la documentación o buscando un poco en Internet o si no lo encuentro o veo que me va a costar más encontrar la respuesta que hacer una pequeña prueba, paso a elaborar, yo mismo, dicha prueba.
Este tipo de incógnitas suelen ser aspectos simples, como ya hace mucho tiempo se me planteo que pasaba con los parámetros pasados a un método en JAVA, si se pasaban por referencia o en copia, ya que no es algo que tu puedas indicar como en otro lenguajes, como sería C++; a mí estas cosas me inquieta no saberlas porque en este caso concreto si se pasa de una manera o de otra me determina si el estado de los objetos que se están pasando pueden cambiar o no, y si es por referencia, como es el caso de JAVA, si ese código es de un tercero y no lo tienes accesible, te tienes que fiar, a priori, de lo que se diga en la documentación, eso si existe.

Alguien se puede preguntar a que viene todo esto, pues el post es una introducción para unos cuantos posts que iré escribiendo sobre ciertas incógnitas del lenguaje de programación (PHP) que estoy utilizando para el desarrollo de un “proyecto” personal que hace tiempo que tenía en mente, y a raíz de haberme metido a desarrollarlo (aunque en con este lenguaje ya lo había utilizado en una versión anterior a la actual y no de manera muy amplia) me he topado con incógnitas en la ejecución de ciertas instrucciones, algunas resueltas con la documentación y otras a base de hacer alguna pequeñas pruebas, que son las que quiero publicar en siguientes posts.


Hasta la próxima enfermos.