viernes, 30 de agosto de 2013

Seguridad en aplicaciones GeneXus

En la reunión de ayer del GUG Montevideo, Diego Rostagnol hizo una presentación sobre seguridad en aplicaciones GeneXus que estuvo interesante.

La charla generó una discusión que estuvo buena, porque se plantearon posibles problemas de seguridad en distintos niveles de la aplicación. Diego planteó algunos casos que yo en particular no había considerado, y creo que los aportes del público sirvieron para aclarar otros que tal vez no estaban del todo correctos.

No me considero un experto en seguridad ni mucho menos, pero igual quería dejar escrito acá más o menos los temas que se hablaron ayer, más que nada porque creo que estos temas son muy importantes y en general no se le dedica el tiempo suficiente.

GeneXus resuelve una buena parte de los problemas de seguridad, y eso es muy bueno, pero también tiene un lado negativo: como GeneXus resuelve cosas de forma automática, podemos pensar que está todo resuelto. Y eso no es así.

Veamos los puntos que surgieron ayer de la reunión, y algún otro que puede haber faltado.

La propiedad Encrypt URL Parameters no evita que se pueda acceder a otros registros

Diego lo mostró ayer en una demo: una URL encriptada se puede desencriptar fácilmente si se conoce el SiteKey o SessionKey que se usa para encriptar.

El problema es que GeneXus usa una clave por defecto, que si no la cambiamos, cualquiera la conoce...

Ver la documentación en el Wiki por más información.

Un campo oculto o "disabled" en un Web Panel no garantiza que no se modifique

Recuerden que el HTML está del lado del cliente, y en general los navegadores permiten modificarlo.

Lo que mostró ayer Diego fue un filtro que el usuario no debería modificar porque no tiene permisos, pero que va como un combo con Enabled = false en el form del Web Panel, que igual se puede modificar y ver los datos que se supone que el usuario no tiene permisos.

Esto en realidad era así porque estaba mal resuelto, se tiene que hacer el control en el for each y no asumir que lo que viene del cliente es válido. Pero de todas formas, es interesante como ejemplo.

HTTPS es obligatorio

Es obligatorio por lo menos en dos lugares:
  • pantalla de login Web, o cualquier otro objeto web que tenga que mandar datos sensibles del usuario
  • servicios REST de las aplicaciones SD.
En realidad, hoy en día no hay ningún buen motivo para no poner HTTPS en toda la aplicación. En algún momento pudo haber diferencia de performance por agregarle el encriptado, pero hoy en día es algo mínimo.

GAM por si solo no resuelve la seguridad

El GAM es un gran avance con respecto a lo que teníamos antes, USENLO!

Lo que había antes, era cada uno programando su esquema de seguridad a mano. Pero igual, GAM por si solo, no resuelve el problema.

En particular, si no usamos HTTPS, cualquiera que pueda ver el tráfico entre el dispositivo y el servidor, puede "robar" el token de autenticación y usarlo sin haberse logueado.

Nunca guarden la contraseña del usuario en su aplicación

En serio, no lo hagan. Si están guardando contraseñas, lo están haciendo mal.

Hay otras formas de autenticar usuarios, contra Google, Facebook, Twitter, OpenId, o lo que sea...

Si de todas formas tienen que guardar usuarios y contraseñas, nunca, nunca, NUNCA, las guarden en texto plano. Tampoco usen algoritmos de encriptación, las contraseñas jamás se tienen que poder desencriptar.

La forma de guardar contraseñas es usando algún algoritmo de hash, pero averigüen antes cuál es seguro (MD5 no lo es), y si pueden apliquen el algoritmo varias veces y agregándole algún código extra que solo conoce la aplicación.

Pero de nuevo, seguramente si guardan contraseñas lo están haciendo mal...

Security Scanner

No se habló nada en la charla de ayer, pero hay una extensión en el Marketplace, que sirve para detectar posibles problemas de seguridad en las aplicaciones.

En particular no la he usado, pero se que hay gente que sí, y que sirve. Les recomiendo que por lo menos la miren y evaluen si les sirve.

Conclusión

La seguridad es un tema delicado.

Lo peor que podemos hacer es confiarnos que está todo resuelto, porque no es así. GeneXus ayuda mucho en varios puntos, pero tenemos que trabajar también nosotros para que las aplicaciones sean realmente seguras.
 

domingo, 18 de agosto de 2013

async/await en C# 5.0

Personalmente no he hecho nada demasiado serio con C# (sí programo, pero no es ni cerca mi lenguaje principal), pero es un lenguaje que me resulta sumamente interesante. Ya había hablado en este blog sobre las mejoras que trajeron las versiones 3.0 y 4.0.

En la última versión de C#, la 5.0 que salió con VisualStudio 2012, se agregaron dos nuevos comandos: async y await. De hecho, es de las pocas cosas nuevas que vinieron con esta versión.

Debo reconocer que al principio no le di mucha importancia, hasta que leí este artículo de Miguel de Icaza que me dejó pensando en el tema: Callbacks as our Generations' Go To Statement

¿Cómo funcionan los comandos async/await? (1)

Cuando se declara un método como async, lo que le estamos diciendo al compilador es que el método puede detener su ejecución en cualquier momento mediante el uso de un comando await.

A su vez, un método declarado como async tiene que devolver un objeto de tipo Task o Task<T> según su valor de retorno "real" sea void o T.

Cuando un método llama a otro que fue declarado como async, tiene la opción de llamarlo y esperar prefijando el llamado con el comando await, o puede seguir ejecutando cosas que son independientes, y guardarse la Task devuelta por el método para esperar más adelante.

Algo así:
public void TestAsyncCall()
{
    Task t1 = SomeLongTaskAsync();
    await AnotherLongTaskAsync();
    await t1;
    ShowCompletionMessage();
}
Por último, cuando un método queda a la espera de un comando await, pasa la ejecución al llamador para que pueda continuar con otra cosa, o quedar a su vez esperando en otro await.

En principio, visto así, no parece ser algo que nos vaya a cambiar la vida. Pero si uno lo piensa en relación al trabajo que puede dar resolver estos temas de forma manual, se da cuenta con la simpleza que lo lograron resolver y cuanto trabajo puede ahorrar.

Comparación con Objective-C

En Objective-C, y en particular para iOS desde la versión 4 en adelante, lo más parecido que tenemos es Grand Central Dispatch.

Supongamos que queremos tener una tarea que ejecute en background, y luego mostrar un mensaje de que terminó. Para eso, tenemos que escribir algo así:
dispatch_queue_t current_queue = dispatch_get_current_queue();
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSError *error = [self someLongOperation];
    dispatch_async(current_queue, ^{
        [[UIAlertView alertForError:error] show];
    });
});
No es mala la solución, pero no tiene la simplicidad que tiene la de C#... Nótese que la mayor parte del código (en este caso, no siempre es así), es para decirle que ejecute de forma asincrónica. En C# lo escribiría tal vez así:
Error err = await SomeLongOperation;
ShowError(err);
Además puede tener algunos problemas.

Como estamos usando dispatch_async, si queremos esperar a que el llamado termine (como con el await), hay que hacerlo usando semáforos.

La alternativa podría ser usar dispatch_sync, pero en ese caso siempre estamos bloqueando, no tengo forma de seguir con ambas ejecuciones en paralelo. Además como el dispatch_sync puede usar el mismo thread de ejecución que el llamador, puedo potencialmente bloquear el thread de UI, cosa que no se debe hacer en ningún caso.

Conclusión

Me pareció una muy buena solución la de C#, creo que es bastante superior a las alternativas que se que tenemos en otros lenguajes.

También me resultó muy interesante el artículo de Miguel de Icaza. Si van al final del artículo hay un link a otro artículo que explica como otra persona implementó una especie de tutorial de su aplicación usando Mono y async/await. Vale la pena leerlo.

Me gustaría saber como se resuelve el tema de la ejecución asincrónica en otros lenguajes, así que agradezco cualquier comentario al respecto.

Actualización, 19/8/2013

Me corrige Fabián, y en parte tiene razón,  que GCD no es lo mejor para eso, que en Objective-C es más fácil usar NSOperationQueue.

Tiene razón en que es de más alto nivel que GCD, y facilita el tema de las dependiencias entre tareas (no se precisa usar semáforos), pero de todas formas se precisa bastante más código que en C# y la lógica queda partida en varios bloques, con saltos en la ejecución entre uno y otro.

En resumen, el argumento se mantiene: las construcciones async y await de C# facilitan mucho la tarea y hacen el código más fácil de leer.


(1) Es una interpretación libre de lo que pude leer e investigar... si me equivoco, agradezco me corrijan.