ASP.NET Membership: Cómo guardar datos adicionales de los usuarios

En los  últimos posts he estado hablando sobre la seguridad de ASP.NET basada en Forms. Esto ha traído algunas preguntas por parte de los visitantes. Una de ellas, bastante común, es la de cómo almacenar información adicional atada a los usuarios que hemos autenticado.

La API de Membership que viene con ASP.NET, y en concreto el proveedor de Membership para trabajo contra SQL Server (SqlMembershipProvider) nos provee de los medios suficientes para almacenar la información básica sobre los usuarios, esto es, el nombre, su login y su clave, que es lo mínimo necesario para trabajar. En este gráfico puedes ver la estructura completa creada por ASP.NET (más bien por aspnet_regsql.exe) en nuestra base de datos para dar soporte a SqlMembershipProvider y relacionados.

Obviamente casi siempre necesitaremos almacenar mucha más información sobre ellos, relacionándola de manera directa y sencilla para poder extraerla. Así, por ejemplo, podemos necesitar almacenar sus datos de contacto, infromación sobre documentos que genere,  estadísticas de aceso, y mil informaciones más.

Lo que haríamos normalmente en cualquier aplicación creada íntegramente por nosotros, es crear una(s) nueva(s) tabla(s) para almacenar esta información adicional sobre el usuario, y relacionarla creando claves externas en la base de datos, usando el identificador único del usuario para ello. Y con Membership exactamente lo mismo. Podemos crear tablas extra y relacionarlas con la tabla aspnet_Users mediante la clave primaria de ésta, UserId.

Nota: El nombre de usuario, campo LoweredUserName) es también único para cada aplicación (es decir combinado con el campo  ApplicationId), pero es mejor utilizar la clave primaria de la tabla.

La única pega es que, posteriormente, a la hora de hacer consultas y extraer los datos necesitaremos saber este Id único para poder filtrar. ¿Y eso como lo hago?

Muy sencillo. La clase MembershipUser dispone de una propiedad llamada ProviderUserKey que proporciona precisamente ese valor único para cada proveedor. En el caso del proveedor para SQL proporciona el valor del campo UserId que hemos visto. Para el del usuario actualmente autenticado sería, en VB, así:

        Dim usuario As MembershipUser = Membership.GetUser
        Dim usuarioID As String = usuario.ProviderUserKey.ToString

Para un nombre de usuario cualquiera, aunque no esté autenticado, sería:

        Dim usuario As MembershipUser = Membership.GetUser("usuario")
Dim usuarioID As String = usuario.ProviderUserKey.ToString

OJO: hay que tener en cuenta que con el SqlMembershipProvider este UserId es un GUID, por eso lo transformamos en una cadena (aunque se podría transformar directamente en una clase Guid). En el caso de otros proveedores podría ser cualquier otra cosa, por ejemplo, un entero.

Con esto no tienes problma de relacionar cualquier información extra en la BD con los usuarios de ASP.NET.

Sencillo, pero mucha gente lo desconoce. Espero que te sea útil 🙂

Seguridad Web: Las cookies de autenticación de ASP.NET y su seguridad

En mi anterior post hablaba sobre el funcionamiento de las cookies en los navegadores y de cómo podíamos usar una extensión estándar (HttpOnly) para intentar impedir que las cookies sean accesibles desde el lado cliente y sólo se puedan manejar desde el servidor.

No obstante se trata de una medida que, de funcionar, complica un poco a los posibles piratas, pero no es una verdadera barrera de seguridad. Para empezar ni siquiera está soportada por todos los navegadores. Las cookies residen en el disco duro del usuario por lo que son fáciles de manipular por cualquiera. Además se envían al servidor en cada petición, por lo que cualquiera con un proxy estilo Fiddler puede leerlas y manipularlas antes de enviarlas al servidor.

Es decir, las cookies son elementos realmente inseguros.

A raíz de estas disquisiciones alguien me escribió preguntándome por la seguridad de la autenticación Forms de ASP.NET (la más habitual). Ésta se basa precisamente en la existencia de una cookie que identifica al usuario y que, por defecto, tiene una validez de 30 minutos, con renovación automática de este periodo en cada petición.

Un momento, ¿cómo?, ¿que la seguridad se basa en que hay una cookie en mi equipo? ¡Qué miedo!

Bueno esto es lo que podría pensarse si las cosas fueran tan sencillas como aparentan. Quiero decir que, en efecto, los datos sobre la sesión del usuario se almacenan en una cookie, pero no de cualquier manera, sino de manera segura.

El funcionamiento de este sistema es, básicamente, el siguiente:

1.- el usuario introduce sus credenciales y se validan (contra una base de datos o contra cualquier otro almacén marcado por el proveedor).
2.- Una vez validado positivamente se genera un ticket o testigo de la sesión actual con una validez de 30 minutos.
3.- Éste se encripta y se almacena en una cookie enviada al cliente y persistida durante la sesión del usuario.
4.- En cada nueva petición al servidor, la cookie se envía y un módulo especializado (FormsAuthenticationModule dentro del espacio de nombres System.Web.Security) desencripta la cookie y se encarga de re-autenticar al usuario en el sistema (estableciendo el objeto Principal actual y renovando la validez de la cookie si así está especificado).

Opcionalmente se puede almacenar el ticket en una cookie persistente que se guaradará en el disco duro del usuario durante por defecto 30 minutos (si bien se puede poner un valor algo más largo que generalmente será más apropiado). Eso significa que aunque el usuario cierre el navegador, al volver a abirlo se mantendrá su estado de autenticación intacto más allá de los 30 minutos por defecto y aunque cierre el navegador.

¿Qué se almacena en la cookie?

La cookie contiene el ticket de la autenticación Forms. Este ticket, representado por la clase FormsAuthenticationTicket, contiene los siguientes datos/miembros:

· Version: la versión del formato del ticket que se está usando. Actualmente la versión 2.
· Name: el nombre del usuario actual, que es único para todo el sistema y que es la pieza clave para luego restituir la sesión autenticada, así como ligarlo con otras API de ASP.NET como Roles o Profile.
· Expiration: cuándo caduca el ticket (y por lo tanto la cookie).
· IssueDate: fecha en la que se generó
· IsPersistent: si la cookie se guardará a disco o no.
· UserData: datos extra sobre el usuario. Normalmente esto es una cadena vacía ya que se escribe desde el proveedor de Membership, y las implementaciones por defecto no escriben nada aquí.
· CookiePath: la ruta relativa a partir la cual se almacena la cookie. Por defecto es «/».

Esta información es la que se serializa y se encripta, estableciendo una cookie para almacenarla en el cliente. Existe un método privado de la clase FormsAuthentication llamado MakeTicketIntoBinaryBlob que se encarga de serializar estos datos, que es llamado desde otro método privado, Encrypt, que se encarga del cifrado.

¿Cómo se encripta la cookie?

Dentro de la configuración de las cookies de autenticación en web.config, en el nodo <forms> podemos establecer algunas propiedades para controlar el comportamiento de este tipo de autenticación. Una de estas propiedades es protection. Puede tomar los valores siguientes:

· Encryption: con este valor el ticket se encripta antes de meterlo en la cookie.
· Validation: fuerza la validación de la cookie, pero no la encripta.
· All: Es el valor predeterminado y también el recomendado. Fuerza tanto el cifrado como la validación de la cookie que contiene el ticket de autenticación.
· None: hace que la cookie no se cifre ni se valide. Está para casos extremos pero se desaconseja totalmente su uso, ya que entonces sí que los temores que llevaron a crear este post serían ciertos, por que no hay protección alguna de la cookie. Eso sí, el rendimiento es mejor porque no tiene que hacer nada.

El cifrado se realiza usando la información especificada en la sección <machineKey> de web.config. A partir de la versión 2.0 de .NET por defecto se utiliza el algoritmo AES (Advanced Encryption Standard, el famoso Rijndael, estándar de la máxima seguridad en cifrado simétrico), pero también están soportados otros algoritmos menos seguros como DES y 3DES.

Para la validación de la cookie se emplea un algortimo de resumen digital (hash). Se concatenan los datos del ticket con una clave de validación, y se obtiene el hash del total usando los algoritmos SHA1 o MD5. POr defecto se usa SHA1, que es el más seguro y rápido de los dos. Dado que se le concatena una clave que sólo es conocida en el servidor, este esquema asegura que no se pueda añadir el código de validación de la cookie desde fuera.

La clave de cifrado y descifrado así como la de validación usadas por defecto es autogenerada en el servidor. Si pretendemos usar la autenticación (así como la validación del Viewstate y otros servicios dependientes) en una granja de servidores, deberemos generar estas claves manualmente y colocarlas en todos los servidores de la granja. Puedes leer todos los detalles aquí.

Como vemos se trata de un sistema muy seguro y que nos protege de intercepciones de la información de autenticación.

De hecho la mayor parte de los sistemas de autenticación de sitios con millones de usuarios como Facebook o Live ID de Microsoft, se basan en técnicas similares.

Analizando el código de las clases de seguridad Web de ASP.NET usando .NET Reflector se pueden ver con todo detalle los entresijos del funcionamiento interno de este sistema, algo que te recomiendo si estás interesado en todas estas cuestiones.

Existe un artículo de la Knowledge Base de Microsoft orientado a resolver problemas con la autenticación Forms que, en su último apartado, trae el código fuente de un módulo que se puede instalar en cualquiera de nuestras aplicaciones para descifrar en el servidor la información de cookies de autenticación que llega y poder hacer logging de la misma. Es un interesante código para analizar y aprender con él sobre el funcionamiento del sistema. Lo tienes aquí.

¡Espero que te sea útil! 🙂

Seguridad Web: Evitar ataques XSS con Cookies accesibles sólo desde el servidor

Una de las técnicas de hacking de páginas web más conocidas es la de Cross-Site-Scripting o XSS. Mediante esta técnica, las aplicaciones Web vulnerables pueden ser atacadas para multitud de propósitos: servir de zombies para atacar a otras Webs inundándolas con peticiones, ejecutar código en zonas de seguridad menos restrictivas (como la local) o, sobre todo, robar la identidad de los usuarios del sitio vulnerable. Ha sido utilizado tradicionalmente en combinación con correos electrónicos maliciosos para entrar en sitios Web protegidos suplantando la identidad de usuarios autenticados. En mi curso de Desarrollo de aplicaciones seguras y seguridad de .NET monto un ejemplo completo de cómo utilizarlo en un supuesto sitio de banca electrónica (muy mal hecha y vulnerable), para robar la sesión del usuario y entrar en su cuenta.


Este robo de sesiones se basa en la obtención mediante XSS de la cookie de sesión de un usuario, enviándola a un servidor bajo el control del atacante. Éste al recibirla puede ir inmediatamente al sitio web atacado y entrar como si fuese el usuario cuya identidad ha robado. En general el robo de cookies es un problema, si no tan grave como el descrito, al menos con consecuencias sobre la privacidad de los sitios Web.


No nos pensemos que este problema de seguridad es algo esotérico que no nos pasará en nuestras aplicaciones. Le pasa a cualquiera. Lo han sufrido empresas como Google, Facebook o incluso hace unos días aparecieron estos problemas en las web de las principales empresas de seguridad). Hay informes que revelan que 9 de cada 10 aplicaciones Web tienen algún problema aunque sea leve de XSS. Así que no lo subestimes.


Manejo de cookies: cliente y servidor


Generalmente en nuestras aplicaciones las cookies las escribimos con código de servidor. Éstas se envían al navegador en una cabecera HTTP y luego se reenvían, en cada nueva petición, de nuevo al servidor, donde podemos leerlas o modificarlas si así es necesario. Estas cookies sólo pueden ser accedidas desde el mismo dominio desde el que han sido creadas, por lo que un código malicioso que esté en un marco o en otra página abierta en el navegador (en otra venta o e una pestaña) no tiene acceso a las mismas. Es, en teoría, información privada y accesible sólo para nuestro dominio.


Sin embargo, por defecto, hay una forma adicional de leer las cookies enviadas por un servidor y es mediante JavaScript. El objeto document del DOM de una página web dispone de una propiedad cookie que muestra todas las cookies del dominio actual así como sus contenidos en una cadena de parejas nombre=valor separadas por punto y coma. Y es ahí precisamente en donde se rompe la seguridad. Si alguien logra inyectar código malicioso de Script en una página (por ejemplo, metiéndolo camuflado en un comentario), este código puede leer las cookies del servidor actual y enviarlas fácilmente a donde quiera. Entre estas cookies habrá datos del usuario que pueden ser privados (de ahí que no se recomiende guardar datos importantes en una cookie) y también cookies de sesión, que es en lo que se basan la mayor parte de las tecnologías Web para mantener el estado entre llamadas HTTP.


Desde hace ya muchos años existe un añadido a la cabecera HTTP para manejo de cookies que planta una restricción en cuanto a quien puede leerlas o no. Se trata de la extensión HttpOnly. Esta cadena añadida al final de la cabecera indica a los navegadores que no deben permitir la lectura de las cookies desde el lado cliente, sólo desde el servidor. Así, el código JavaScript no puede leer las cookies que lleven esta extensión a la cabecera y por lo tanto las protegemos de los ataques de XSS.


El aspecto de una cabecera de cookie normal es este:



Set-Cookie: miCookie=Dato=XXXXYYYYZZZZZ; path=/


Para evitar que las cookies puedan ser leídas desde el cliente sólo hay que añadir la extensión HttpOnly al final, así:



Set-Cookie: miCookie=Dato=XXXXYYYYZZZZZ; path=/; HttpOnly


Cómo establecer esta opción en cookies con ASP.NET


En ASP.NET es muy sencillo conseguirlo mediante código ya que la clase HttpCookie dispone de una propiedad a tal efecto. Considera el siguiente código sencillo en el que una página ASPX escribe un par de cookies que serán enviadas al navegador:



La primera de las cookies es una cookie «normal y corriente». Se establece un nombre («Numero») y un valor (1), se añade a una cookie, se le pone un tiempo de caducidad y se manda al cliente. Por defecto no se incluye la extensión HttpOnly por lo que esta cookie va a ser accesible a código JavaScript en las páginas de nuestra aplicación.


La segunda cookie es idéntica a la anterior, pero en este caso establecemos su propiedad HttpOnly a True, de modo que se añade en la cabecera la extensión que hemos visto, y el navegador restringirá su acceso únicamente al servidor.


Podemos comprobar que está funcionando de manera muy fácil, basta con añadir un:



alert(document.cookie);


dentro de un bloque JavaScript en alguna página del sitio para ver como se abre una ventana mostrando los contenidos de las cookies a las que nuestro código JavaScript tiene acceso. Comprobaremos que la segunda cookie no aparece por ningún lado, sin embargo sigue accesible en el código de servidor. Además podemos verla en las cabeceras que se mandan al servidor, usando una herramienta de inspección como Fiddler (comentada en mi anterior post referenciado arriba)


Activación de HttpOnly para toda la aplicación


La propiedad que acabamos de ver está muy bien cuando queremos establecer esta opción sólo para algunas cookies, pero ¿y si queremos que todas las cookies sean de acceso exclusivo desde el servidor? Y especialmente si queremos que esta opción esté activa para todas las cookies de sesión, como la que mantiene el estado HTTP y que genera la propia infraestructura de ASP.NET.


La solución es establecer una opción en web.config. Dentro del nodo <system.web> podemos escribir esto:



A partir de ese momento todas las cookies serán de manejo exclusivo en el servidor, por lo que podremos despreocuparnos de utilizar la propiedad que hemos visto.


Conviene utilizar esta opción en las aplicaciones en las que recibamos datos de los usuarios que puedan contener HTML y código de JavaScript, y desde luego aparte de esto, observar siempre las buenas prácticas de seguridad en aplicaciones Web, así como la regla número 1 de seguridad que todo programador debe seguir: «jamás confíes en nada que te envíe un usuario».


Soporte de HttpOnly en los diferentes navegadores


Internet Explorer 4.0, allá por el año 1997 (casi en la prehistoria de Internet) ya soportaba esta extensión de seguridad. Así que IE es el mejor candidato para estar seguros de que funciona esta extensión. IE8 además es el único navegador que incorpora un filtro anti-XSS que si bien no es efectivo a 100% (algo imposible seguramente), hace un gran trabajo y es más de lo que ofrece la competencia, lo que demuestra la seriedad con la que en Redmond se toman la seguridad.


Firefox (o sea Mozilla, es decir, Netscape y otros que se basaban en ese motor etc…) sin embargo no lo empezó a soportar hasta su versión 2.0.0.5, en el año 2007 (diez años despues de IE). Y encima tenía un bug, por que no las retiraba del objeto XMLHttpObject, algo que se solucionó en la versión 3.0.


Opera empezó a soportarla en su versión 9.5 (Junio de 2008), por lo que todas las versiones modernas funcionan como es debido en este aspecto.


El navegador de Google, Chrome, lo soporta en el sentido de que no permite la lectura por parte de código de Script de las cookies marcadas con HttpOnly. Sin embargo soporta su escritura, algo un tanto extraño pero que mitiga mucho el efecto de un atacante malicioso.


El navegador Safari, de Apple, no tiene en cuenta para nada esta extensión y permite a JavaScript hacer lo que quiera con las cookies, lo que lo convierte en un objetivo apetecible para ataques XSS.


Así que podemos utilizarla sin demasiado problema confiando en que funcione. De todos modos lo mejor es tener en cuenta la seguridad en nuestras aplicaciones y poner contramedidas para evitar los ataques XSS  🙂

Un milagro: error de concurrencia en Facebook

Lo reconozco, no me he podido resisitir más. Las presiones eran demasiado fuertes y me he metido en Facebook. Llevo sólo un par de días y la aplicación, técnicamente hablando, me parece que está muy bien por lo que he podido ver (el UI). Me gusta mucho su sencillez, la agilidad de la interfaz AJAX, el chat, las notificaciones, etc..


Pero hoy, dándole al botón de «Me gusta» se ve que coincidí en el mismo preciso instante con otra persona haciendo lo mismo (porque justo a continuación aparecía una notificación al respecto) y fijaos el mensaje que me apareció:



No me digas que no es flipante: una aplicación con decenas de millones de usuarios, super-escalable, y ¿me aparece esto?. Creo que he encontrado la aguja en el proverbial pajar. Es un don que tengo 🙂


Al menos sale en un formato apropiado y no «casca» miserablemente como pasa con otras.


¿Alguien sabe qué tecnología usa FaceBook por debajo? SQL Server seguro que no 😉
¿Y para la parte de programación Web de servidor?


Si alguien encuentra otro error de este estilo que lo mande para la colección. Ya he hablado con unos cuantos que lo usan asiduamente, mucho más que yo, y nadie se ha encontrado jamás un error. Ya digo, es un don que tengo.


Saludos!

El atributo "defer" de JavaScript

La metodología clásica de creación de páginas Web recomienda que todos nuestros scripts se encuentren en la cabecera de la página. Está bien tener un orden pero realmente no es necesario. Es más, nadie nos dice que no podamos incluso tener varias cabeceras en la página, una por ejemplo, después de cerrar la etiqueta </body>, si queremos.


Hay algunas aplicaciones que usan mucho JavaScript. Sobre todo ahora con el uso masivo de capacidades AJAX en las aplicaciones Web. Algunos de estos scripts son simples bibliotecas de funciones con decenas o cientos de ellas que lo único que hacen es retrasar la carga de página mientras son procesadas por el navegador, ya que éste no sólo carga cada Script sino que también lo interpreta y ejecuta a medida que lo va leyendo. En otros casos el script necesita tener acceso a todos los elementos de la página antes de poder actuar (es decir, el HTML de la página debe ser procesado por completo y el árbol DOM construido). Si lo colocamos en la cabecera no funcionará lo cual nos fuerza a ponerlo después del cierre del cuerpo, lo cual, por otra parte no es un problema, pero debemos recordárselo a los que usen la biblioteca de funciones. Mi biblioteca AJAXInterceptor es un buen ejemplo de esto, ya que requiere que se coloque al final para funcionar.


Para evitar estos problemas y, sobre todo, acelerar la carga de las páginas, Microsoft introdujo en Internet Explorer 4.0 hace ya unos años el atributo defer de JavaScript. Posteriormente este atributo ha pasado a formar parte de la especificación HTML 4.01 y posteriores.


Básicamente lo que consigue es que el navegador no procese el código JavaScript hasta que la página ha cargado por completo, al final del todo, en lugar de en el momento de leerlo. Está pensado para que si tu Script no contiene ninguna sentencia document.write o similares que modifiquen el contenido del DOM, entonces que se pueda procesar todo esto al final, acelerando la carga de la página.
Su sintaxis es la siguiente:


    <script type=»text/javascript» defer=»defer»>


El efecto real es como si tu Script, esté en donde esté colocado en la página, estuviese colocado justo al final de la misma, puesto que no se procesará hasta que el resto de la página se haya procesado.


OJO: que se procese al final no quiere decir que no se descargue cuando toca. Al encontrarse una etiqueta <script> que hace referencia a un archivo externo, el navegador descargará igualmente el script, sólo que no lo procesa. Así que no nos libramos de esta fase, aunque normalmente sólo lo hará la primera vez si tenemos una adecuada política de caché. Para retrasar también la descarga, en la nueva especificación de HTML se está trabajando en un nuevo atributo async que servirá precisamente para eso y que a mí me parece muy interesante.


He preparado un ejemplo que muestra cómo funciona este atributo en una página:



Lo que se hace es introducir una mezcla de scripts tanto in-line como con referencia externas, algunos de los cuales están en la cabecera y otros en el cuerpo y algunos tienen defer y otros no. Cada uno de ellos simplemente anota en una variable un texto indicando qué tipo es. Al final hay un botón que muestra la cadena en el orden en el que se concatenó, lo que nos da el orden de ejecución del Script.


Puedes descargar el ejemplo aquí.


En Internet Explorer 8.0 (en realidad en cualqueir versión de IE desde la 4.0) el resultado es el siguiente:



Que es lo que cabría esperar, y como vemos los scripts con defer se ejecutan al final, en el mismo orden en el que están en la página.


Sin embargo si lo ejecutamos en Firefox 3.0.1 obtenemos esto:



Es decir, el comportamiento normal, como si no tuviera defer aplicado. ¿Qué ha pasado?


Lo que ocurre es que Firefox no soporta el estándar y hace caso omiso de este atributo, por lo que la ejecución es exactamente la misma que en el caso de no tener defer 🙁


Este es un bug reconocido por Mozilla ¡desde el año 2000 nada menos!. Lo cierto es que en la inminente versión 3.5 del navegador, por fin, lo han solucionado y ahora funcionará bien. Pero el caso es que no nos servirá por el momento.


Los otros navegadores (opera, Safari, Chrome…) ni siquiera tienen intención de soportarla. No deja de llamarme la atención cómo para algunas cosas dicen ser tan cumplidores de los estándares y con otras pasan absolutamente de todo 🙁


Mi recomendación


Para mí el atributo defer es interesantísimo, así como el futuro posible atributo async, pero el caso es que hoy por hoy sólo deberíamos utilizarlo cuando estemos seguros de que nuestra página la verá únicamente Internet Explorer.


Si queremos una solución que funcione para todos los navegadores, lo mejor es colocar los scripts al final de la página, justo después del body, para asegurarnos de que al menos el grueso de la página se visualiza y luego los scripts pesados se procesan sin interferir en esta primera visualización.


Otra opción es cargar dinámicamente los scripts escribiendo código similar al que os comentaba el otro día para mantener la sesión abierta.


Nota final: Detectar si se hay scripts deferidos o no en una página


Cómo puedo detectar si defer funciona o no en una página.


Muy sencillo, con un código como este:


    <script type=»text/javascript»>
        var _deferFunciona = true;
    </script>
    <script type=»text/javascript» defer=»defer»>
        _deferFunciona = false;
    </script>
    <script type=»text/javascript»>
        var deferFunciona = false;
        if (_deferFunciona)
          deferFunciona = true;
    </script>


Este ejemplo está también en el ZIP que te puedes descargar.


En resumen


Es una verdadera lástima que este atributo tan útil no funcione en todos los navegadores, sobre todo considerando que hace años que está en el estándar 🙁


Si vas a hacer una página específica para Internet Explorer no dudes en usarlo. Si es para otro navegador usa otras técnicas para asegurarte de que los scripts no interfieren y ralentizan la carga de páginas pesadas.

Supernet, que no es tan "super" y otras gambadas en bancas electrónicas

Llevo usando la banca electrónica de diversos bancos desde hace muchos años. Incluso creo que debo de haber sido de los primeros usuarios de algunas de ellas, sufriendo su mal funcionamiento en los primeros años. Recuerdo que en algún caso hasta detecté problemas de seguridad (hace ya una década) avisando a los interesados, que los parchearon enseguida pero ni siquiera tuvieron la decencia de dar las gracias.

Lo cierto es que para ser aplicaciones de tanta responsabilidad y tan ampliamente usadas, la mayoría de las bancas electrónicas que conozco son aplicaciones Web bastante mal hechas, sobre todo desde el punto de vista de la usabilidad, donde les queda mucho camino por recorrer a casi todas. Actualmente utilizo 5 bancas electrónicas de otros tantos bancos, y son todas para echarse a temblar a excepción, quizá, de la de Fibanc.

Una que me sorprende siempre negativamente y que es una de las que más años llevo usando, es la del Banco Santander. Desde mi punto de vista ni siquiera en un banco o caja pequeños, con menos recursos, podría justificarse una banca electrónica mala y anticuada. Pero en el caso del Santander parece mentira que un banco tan grande e importante tenga «eso». Lo peor de todo es que la han cambiado recientemente y, la verdad, quitando que ya no te fuerzan a usar Java en el lado cliente 😉 no le veo tampoco demasiadas mejoras. Desde luego no parece una aplicación del año 2009. Otra que tal baila es la de Caja Madrid, que es una entidad muy importante también, pero cuya banca electrónica deja mucho que desear.

En fin, todo esto viene a cuento porque últimamente he tenido bastantes dificultades con la del Santander, y me acordé de este tema de las bancas electrónicas, que me ha tenido quemado durante todos estos años.

El otro día necesitaba buscar una transferencia que había realizado y de la que no sabía exactamente la fecha pero sí el importe, por lo que hice la siguiente búsqueda en «SuperNet» del Santander:

Al darle a «Buscar», de manera inmediata (es decir, ni se intenta la búsqueda ni nada), recibo este mensaje:

Muy «user friendly». Desde luego la búsqueda de SuperNet no es tan «super» después de todo sino es capaz de buscar esto 😉

Además lo gracioso es que si le quitas la restricción del importe te saca el listado sin problemas, por lo que no es cuestión de la cantidad de registros, es por el filtro. A lo mejor el servidor no puede filtrar porque la BD vete a saber qué tecnología usa para albergar tal cantidad de datos que debe de tener, pero podrían, por ejemplo, implementar un filtrado a posteriori sobre los resultados, incluso en el cliente si me apuras.

En fin, es sólo un ejemplo, pero podría poner muchos más. La mayoría son pequeñas cosas, pero todas sumadas hacen un montón.

De todos modos me encantaría mostrar un ejemplo de la confianza que despiertan algunas bancas electrónicas en sus usuarios. Esta captura la guardé ya hace bastante tiempo, pero es que es antológica y además pasaba de vez en cuando, no fue una cosa puntual. Estaba haciendo una transferencia en la banca electrónica de Caixanova y, tras validarla, recibo este mensaje:

O sea, dicho claramente lo que pone es: «No tenemos ni idea de si su transferencia se ha realizado o no. Pero oiga, mire usted en su cuenta y si falta el dinero es que sí, la hemos hehco. Si no falta, vuelva a hacerla a ver si esta vez la cosa funciona». Sí, claro, que me voy a fiar yo de la transaccionalidad de esto después de cosas que he visto X-DDD

En fin, que hacer una banca electrónica debe de ser muy complejo sobre todo por la cantidad y el tipo de datos que se manejan, pero eso no quita que se pueda hacer pensando un poco en el usuario ¿verdad?

No estaba de más que se leyera más por los bancos el libro «Why Software Sucks», de David Platt.

Como evitar que las sesiones caduquen por inactividad: The Film

Uno de los posts más visitados de mi blog es en el que comento cómo evitar que las sesiones caduquen por inactividad. Es la tercera parte de una serie de posts sobre caducidad de sesiones en ASP.NET.


Ha habido también muchos comentarios y parece que a mucha gente le cuesta bastante implementar la solución, por lo que tras varias peticiones (tanto en mi blog original, JASoft.org, como en Geeks.ms) me he decidido a generar un vídeo práctico mostrando como se hace. 


Es del estilo de los que tenemos en los cursos de campusMVP pero con mucha peor calidad, que viene impuesta por las limitaciones de SOAPBox. Lo cierto es que estos sitios de vídeo en Internet no son los más adecuados para este tipo de grabaciones por su elevada compresión, que limita la calidad, pero bueno… se deja ver. A ver si lo puedo colgar en Channel9 de Microsoft en breve y así que podáis verlo con major calidad.


Puedes pulsar en el gráfico de abajo para verlo.


Mantenimiento de sesiones en ASP.NET
Mantenimiento de sesiones en ASP.NET


Además te puedes descargar el código fuente desarrollado en el vídeo para poder experimentar por tu cuenta.


Espero que esto disipe por fin las dudas y le sea de más utilidad a todo el mundo.


¡Saludos!


Actualización día 2/6/2009: Microsoft ha publicado el vídeo en alta calidad en Channel9, por lo que mejor visita este enlace para verlo bien y poder descargarlo en diversos formatos.