Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados

Charla Bienvenido a Python en Instituto Libre 09

flyingEl viernes por la tarde se llevó a cabo el evento Instituto Libre 09 en la ciudad de Coronda, más precisamente en el Instituto Superior de Profesorado Nº 6 Dr. Leopoldo Chizzini Melo.

Presenté una charla llamada Bienvenido a Python. Es una introducción al lenguaje de programación Python bastante práctica y con muchos ejemplos. Los slides están disponibles en formato pdf bajo una licencia CC. El documento fue generado a partir de un archivo de texto utilizando rst2pdf.


Cuadro de Honor

El Jueves viajamos con Ceci a Rosario para participar del evento Cuadro de Honor organizado por la revista PuntBiz, la fundación del Banco Municipal de Rosario y la consultora Sesa Select. Desde hace 4 años organizan una jornada con los mejores promedios de las universidades de la provincia. Eramos muchos chicos, uno 150 jóvenes profesionales de las más diversas carreras.

El agasajo se llevó a cabo en el Salón Auditorio de la Bolsa de Comercio de Rosario, hablaron varias personas a las que me gustó escuchar (Gabriel González, director periodístico de PuntoBiz, la Prof. Ana Navarro de Gimbatti y Alejandro Ferrazzuolo, gerente de Select Executives) y terminó con la entrega de diplomas.

juanjoyceci

Un detalle en la misma revista.

En la página de la vice ministra Alicia Ciciliani hay varias fotos del evento y asomamos entre la multitud :)

update: otra foto linda de ese día.

3rafila-s


Ejercicio 16 - proyecto Euler

De vez en cuando se me da por hacer saries de posts en el blog. Sagas. Una de las últimas fue la saga sobre resoluciones a problemas del proyecto Euler. Lo que intentaba era resolverlos con alguna característica interesante de Python y luego explicarla. Luego de los primeros, los ejercisios se volvieron más matemáticos y encontraba menos cosas interesantes de Python que comentar, así que dejé de postear mis soluciones. Acabo de encontrar esta entre mis archivos y creo que tiene algo de originalidad como para merecer ser publicada:

¿Cuál es la suma de los dígitos del número 2^(1000)?

>>> 2**1000

107150860718626732094842504906000[algunos números fueron intencionalmente borrados]

>>> a = 2**1000

>>> sum((int(x) for x in list(str(a))))

1366

¿A alguien se le ocurre otra forma?



Charla: Taint Mode en Python

Estas son los slides (más texto con el grueso de lo que dije) de mi charla en PyCon Argentina 2009. La misma se anunciaba como:

Taint Mode es una característica implementada en algunos lenguajes con el objetivo de prevenir que usuarios malintencionados alteren entradas al sistema para lograr la ejecución de comandos no permitidos u otros tipos de ataques.

En esta charla se introducen los conceptos básicos de Taint Mode y se discute la forma de implementarlo en Python mediante el uso de decoradores. Se muestra una implementación concreta y se analizan sus resultados.

img0

img1

Cómo digo ahí, no soy un experto en seguridad aunque es un área que me interesa, sino me considero un desarrollador.

Cómo desarrollador, muchas veces me encuentro dejando de lado la seguridad por cuestiones más apremiantes.

Por hacer lo urgente, no hacemos lo importante.

Entonces las fechas límite para entregas, las presiones por incorporar nuevas características, el pago solo por lo que se ve, hace que mucho software salga a la calle sin los más mínimos recaudos de seguridad.

Esto trae consecuencias graves para muchas organizaciones y personas, como:

  • Robo o alteración de información
  • Bloqueos en la disponibilidad de un recurso
  • Suplantación de identidad

Formas de mitigar este problema sin duda hay muchas. Una puede ser contar con herramientas que en tiempo de desarrollo permitan verificar la existencia de vulnerabilidades en el código escrito. ¿Qué vulnerabilidades? ¿Todas? Eso sería seguramente imposible. Pero existen herramientas que se especializan en distintos nichos: buffer overflow en C, XSS en PHP.

Empecé a prestarle atención a este tipo de cosas cuestiones cuando empecé a participar de un grupo de investigación sobre seguridad en mi facultad. Yo me estaba postulando para obtener una beca de maestría y una de las condiciones era participar de un grupo de investigación.

Así que empecé a buscar en Internet papers que relacionen cuestiones de  seguridad con Python, como una forma de encontrar algún tema que me interese y pueda profundizar.

Encontré algunos papers de 2 investigadores de la Universidad Estatal de Moscú, Andrew Petukhov y Dimitry Kozlov en los que discutían cómo implementar Taint Mode en Python. Si bien su enfoque consistía en modificar el intérprete en C de Python para lograrlo, de su trabajo incorporé la mayoría de los conceptos que voy a mencionar en la primer parte de la charla. A diferencia de ellos, mi implementación de Taint Mode para Python está escrita totalmente en Python.

img2

img3

El modelo de las manchas intenta describir cómo se comportan los valores que ingresan a un sistema desde el exterior y tiene 3 componentes fundamentales.

FUENTES NO CONFIABLES, FUNCIONES LIMPIADORAS Y SUMIDEROS SENSIBLES.

Todo valor que ingresa a un programa desde el exterior, es considerado por defecto como un valor manchado, ya que no sabemos de su procedencia. Decimos que viene de una fuente no confiable. Los valores recibidos desde el exterior pueden haber sido deliberadamente modificados para causar daño o simplemente por error causar un un problema dentro del sistema.Estas manchas se propagan por el programa mediante operaciones como la asignación o la concatenación.

Las funciones limpiadoras representan los mecanismos que se pueden utilizar dentro de un programa para convertir un valor manchado en un limpio: escapando, codificando o incluso eliminando caracteres sospechosos.

Los valores manchados no deben ser utilizados para: generar respuestas hacia los clientes o construir comandos a ser utilizados contra servicios externos, como los provistos por el sistema operativo, motores de bases de datos o el mismo intérprete. A estos componentes a los que no queremos que lleguen valores manchados, los denominamos "sumidero sensible".

img4

Si un valor manchado alcanza un sumidero sensible, entonces existe una vulnerabilidad en el programa.

De esto se deduce que los valores manchados deben ser limpiados antes de que el flujo del programa los lleve hacia un sumidero sensible.

Esto es correcto, pero debemos preguntarnos: ¿son todas las manchas iguales? ¿Una función limpiadora puede quitar todas las manchas de un valor? ¿Son todos los sumideros sensibles al mismo tipo de mancha? NO.

  • Un valor puede tener más de un tipo de mancha.
  • Una función limpiadora, por lo general, limpia un solo tipo de mancha.
  • Un sumidero es sensible a un solo tipo de mancha.

Cuando un valor ingresa al programa, no sabemos que manchas tiene ¿Debe un desarrollador aplicar todas las funciones limpiadoras a cada valor que procede de una fuente no confiable? No toda función limpiadora es apropiada para procesar todos los valores manchados e incluso hacerlo consumiría recursos en forma innecesaria.

Una mejor estrategia es, dado un tipo de mancha determinado, aplicar una función limpiadora de esta mancha solo a aquellos valores que alcanzarán un sumidero sensible a la mancha en cuestión.

img5

En concreto. Este valor está manchado con SQL Injection y no deberíamos dejar que forme parte de una sentencia que se va a ejecutar contra una base de datos. Pero, en principio, no habría problemas en que se use para renderizar una página que será devuelta al usuario.

Algo similar sucede con este valor. Si bien está manchado para XSS. En principio no habría problemas en que se utilice para generar un comando a ejecutar contra el sistema operativo.

img7

img8

Tres menciones sobre la implementación antes de ver ejemplos de uso.

1) Existen 2 formas generales de implementar este tipo de análisis. De forma estática o de forma dinámica. Una implementación estática realiza la detección analizando el texto de un programa, sin ejecutarlo. Mientras que una implementación dinámica, analiza el coportamiento del programa. Esta es una implementación dinámica, por lo que va a requerir que el programa a evaluar sea ejecutado y utilizado: ejecutando manualmente casos de uso o corriendo tests automatizados.

2) El uso de módulo requiere que sea importado dentro del programa a evaluar y hacer algunas modificaciones en el código fuente. Es intrusivo.

3) La implementación se basa en el uso de decoradores. Existen decoradores para marcar dentro del programa los 3 tipos de elementos del modelo de las manchas: FUENTES NO CONFIABLES, FUNCIONES LIMPIADORAS Y SUMIDEROS SENSIBLES.

img9

img10

Cada tipo de mancha con la que va a trabajar el módulo es identificada por un entero. En la lista KEYS que se ve en la pantalla, XSS es identificada con el 0, SQLI con el 1 y así. Esta lista de valores debe ser modificada si se quiere agregar nuevas vulnerabilidades para que sean reconocidas por la herramienta.

TAINTED es la la estrucutura de datos dónde se lleva el registro de qué variables están manchadas. Es un diccionario dónde las claves son los enteros de la lista KEYS sus valores conjuntos, sets, inicialmente vacíos. Cuando se recibe un valor manchado del exterior, este es almacenado en todos los conjuntos, ya que por defecto tiene todas las manchas y a medida que se va limpiando, es eliminado del conjunto correspondiente.

STR, en mayúsuculas, es una clase que envuelve a la clase str, en minúsculas, provista por Python. Ya que en Python los strings son inmutables, siempre que se procesa un string, por ejemplo cuando se obtiene un substring, se crea un nuevo objeto. Esta clase es necesaria para sobreescribir los métodos que generan un nuevo string y así hacer que la mancha perdure a lo largo del flujo del programa. Por ejemplo:

img11

Si a está manchada, y b está limpia. El string que se obtiene de concatenarlos, también está manchado. Lo mismo sucede con otras operaciones sobre strings: multiplicación, rebanada, formateo, métodos como upper que convierten el string a mayúsculas, o split que devuelve una lista de strings. Por ejemplo, si en este último caso 'a' sería un string de palabras separadas por coma, esta llamada al método split devolvería una lista de palabras y cada una estaría manchada.

Los siguientes elementos a mostrar son los decoradores necesarios para que los elementos del programa manchen variables, las limpien o se alarmen.

img12untrusted es un decorador utilizado para indicar que los valores retornados por una función o método no son confiables. Como los valores no confiables pueden contener potencialmente cualquier tipo de mancha, estos valores son marcados como manchados por todos los tipos de machas.

Si se tiene acceso a la definición de la función o método, se puede utilizar la sintáxis provista por Python para aplicar el decorador.

Al usar módulos de terceros, podemos aplicar de todas formas el decorador. Este ejemplo es de un programa que utiliza el framework web.py.

img13

Algunos frameworks funcionan de una forma diferente: le piden al programador que escriba cierta función o método de forma tal que luego el framework las utiliza para pasarle como parámetro al programa de usuario los valores recibidos desde el exterior. El framework para hacer aplicaciones de red, Twisted, provee un claro ejemplo  cuando se extiende la clase LineOnlyReceiver. Nos pide sobreescribir el método lineReceived, el cual se ejecutará cada vez que se recibe una cadena desde el exterior.

En estos casos, utilizar el decorador untrusted es engorroso o incluso imposible. En su lugar se debe utilizar el decorador untrusted_args, que recibe 2 argumentos opcionales: una lista de posiciones de argumentos no confiables y una lista de argumentos de palabra clave.

En el ejemplo se indica que el argumento de posición 1 no es confiable, y debe ser mancado como tal. Entonces cuando se ejecute el método, el valor recibido será manchado.

Tanto para el decorador untrusted como untrusted_args, se utiliza la siguiente regla para marcar valores:

  1. Si el valor a manchar es un string, se utiliza para crear una instancia de STR y este objeto es guardado en TAINTED.
  2. Si el valor es una lista. Se aplica este algoritmo a todos los elementos de la lista y se retorna una nueva lista con el resultado de cada aplicación.
  3. Si el valor es un diccionario. Se aplica este algoritmo a todos los valores del diccionario y se retorna un nuevo diccionario con las claves originales y los resultados de cada aplicaicón como valores.

img14

Una vez que los valores manchados ingresan en el programa, fluirán a lo largo del mismo y en algún momento, puede ser que se encuentren con una función limpiadora como esta. texto_plano elimina las marcas html de un string.

cleaner es un decorador utilizado para indicar que un método o función tiene la habilidad de limpiar manchas en un valor. Se debe indicar mediante un parámetro el tipo de mancha que la función es capás de limpiar. Como con los otros decoradores, tenemos dos formas de aplicarlo: dependiendo de si tenemos acceso o no a la definición de la función limpiadora.

Funciona de la siguiente forma: si la función texto_plano decorada se aplica al primer ejemplo, nada cambia. Como el valor retornado es distinto al argumento, un proceso de limpieza fue llevado acabo. El valor argumento sigue en la estructura de datos TAINTED.

En cambio, si es aplicada al segundo ejemplo, el valor argumento es igual al retornado, no se limpió nada por que no se requería limpiar nada. El valor original, presumido manchado, en realidad no estaba manchado (para XSS) y por eso es removido del conjunto correspondiente.

img15

Los últimos elementos a marcar en el programa son los sumideros sensibles.

Se utiliza el decorador ssink para marcar aquellas funciones o métodos que no queremos sean alcanzadas por valores manchados.

La función eval de Python es un típico ej. de sumidero sensible a ataques de Interpreter Injection, ya que interpreta ciegamente el string que recibe como  argumento.

Supongamos q nuestro programa es una calculadora e implementamos la funcionalidad de sumar 2 números evaluando el string formado por: un primer valor recibido del exterior, el signo más y un segundo valor recibido desde el exterior. Si los valores no son apropiadamente validados, un atacante, utilizando nuestra calculadora, podría leer el contenido de archivos locales, borrarlos, colgar el programa o cualquier otra cosa que se pueda hacer desde el intérprete de Python.

Aplicando el decorador a eval podemos detectar cuando esta función es utilizada con un valor no confiable como parámetro. Otra forma de lograr el mismo efecto en el ejemplo sería aplicando el decorador a la función suma en lugar de a eval.

img16

El segundo ejemplo también es tomado del framework web.py y marca como sumideros sensibles a SQL Injection los métodos delete, select e insert del objeto que accede a la base de datos.

img17

Con las fuentes inseguras, las funciones limpiadoras y los sumideros sensibles marcados en el programa, podemos ejecutarlo y utilizarlo para ir obteniendo las advertencias sobre posibles problemas de seguridad. Se pueden obtener mensajes de este tipo por la salida estándar, escribir en un archivo o daler cualquier otro destino.

img18

Algunas otras cosas que podemos encontrar con/en el módulo:

  • una batería de más de 80 tests que prueban su funcionalidad
  • la posibilidad de definir la función que se ejecutará cuando una variable manchada con X alcanza un sumidero sensible a X
  • la posibilidad de establecer una bandera que indique si la ejecución se debe cortar o no cuando una variable manchada con X alcanza un sumidero sensible a X
  • un nuevo decorador, validator, para marcar funciones que retornan un valor booleano indicando si una variable puede usarse o no
  • funciones auxiliares para manchar un valor o para testear si un valor está manchado

img19

Último slide de la charla. Todo lo que mostré hasta ahora es un experimento. Puede haber errores u omisiones, de hecho mientras lo fui desarrollando, al probarlo con aplicaciones reales encontraba errores en la implementación o situaciones en los que no podía aplicarlo, lo que me obligaba a darle una vuelta más de rosca a la implementación: así surgió por ejemplo el decorador untrusted_args.

La pregunta ahora es cómo seguimos, y el objetivo de la charla era justamente presentar esta idea entre desarrolladores Python para continuarla en conjunto. Hay  muchas que podemos pensar, desde detalles de implementación hasta casos de uso que se pueden lograr, integración con frameworks de desarrollo para que alguien que se sienta a codificar un sistema tenga facilitada la aplicación de esta herramienta.

Por ejemplo, para web.py sería relativamente sencillo crear un parche para que por defecto los valores recibidos estén manchados. En Django hice el ejercicio de escribir un middleware que haga ese trabajo. Y así, es necesario ir probando cómo se puede adaptar el módulo a herramientas de desarrollo ya conocidas.

Hace poco cree una lista de correos en Google Groups para charlar estos temas, así que los que estén interesados en discutir al respecto y desarrollar esta herramienta, pueden suscribirse.

img20

img21


Charla relámpago: Comet en Twisted

Ayer en las charlas relámpago de PyCon Argentina 2009 mostré cómo utilizar Comet desde Twisted. Tenía un slide disparador que no pude mostrar por que OpenOffice no se abrió y como las charlas relámpago duran 5 minutos, no podía darme el lujo de investigar que pasaba.

"No importa", dije, "de todas formas el slide tenía solo cuatro palabras". Y para hacer justicia sobre las Leyes de Murphy publico aquí ese slide:

cometEl ejemplo que mostré en vivo puede bajarse del sitio web de Nevow/Athena.



Donde no hay seguridad nadie puede romperla

IMG_4773

Hoy me pasó mi padre un artículo en Página 12 con una reciente entrevista a RMS. El artículo se titula, como este post, Donde no hay seguridad nadie puede romperla. En la noticia, el título no es más que una frase sacada de una de sus respuestas, parte de una anécdota casi que poco está relacionada con el resto de la nota, pero me llamó muchísimo la atención. Rescato esta parte:

En ese sistema no había seguridad, no había claves, no había protección de archivos, cualquier persona podía entrar en la computadora bajo cualquier nombre y hacer cualquier cosa, y nos gustaba que fuera así, deliberadamente implementábamos el sistema sin seguridad. Mi trabajo en el laboratorio era mejorar el sistema. Si hubiéramos querido tener seguridad nos tendríamos que haber dedicado, entre otras tareas, a implementar la seguridad, que era lo que no queríamos. Entonces, donde no hay seguridad nadie puede romperla.

El periodista entonces pregunta, a lo mejor algo alarmado, si puede existir un sistema sin seguridad. A lo que Stallman contesta:

Aunque muchos pueden pensar que es imposible, es algo que todavía puede ser posible. Pero con esto no quiero decir que no tiene que haber seguridad en los bancos, por ejemplo, no estoy a favor de robar las cuentas bancarias. Pero nuestro laboratorio no era un banco, no teníamos datos personales, no teníamos datos financieros, fue un laboratorio para colaborar en la investigación y el desarrollo. Pero hoy en día es algo diferente, porque habitualmente usamos computadoras personales, pero en los años ’70 una computadora era demasiado cara, era casi imposible tener una computadora personal. Y en ese período el laboratorio tenía dos computadoras principales que todos teníamos que compartir. Cuando la gente comparte una computadora, tener seguridad entre los usuarios exige imponer un estado policíaco, pero no es igual con las computadoras personales, porque fácilmente se puede excluir a los demás de tu computadora, sin imponerse a uno mismo un estado policíaco. Pero en las computadoras compartidas nosotros no deseábamos tener seguridad, no fue sólo un capricho, fue por motivos racionales, porque queríamos vivir en libertad, no queríamos desarrollar un arma para los administradores para someternos.

Para pensarlo.


Django Middleware

Mientras estudié el tema para hacer un experimento, traduje el 80% de la documentación oficial. La dejo aquí más algunos condimentos personales.

Middleware

Es un sub framework que permite modificaciones al sistema de procesamiento de request/response de Django. Es un sistema de plugins liviano y de bajo nivel que permite alterar globalmente las entradas y salidas de Django.

Cada componente middleware es responsable de hacer alguna función específica.

Activar componentes middleware

Para hacerlo, añadirlo a la lista MIDDLEWARE_CLASSES en la configuración de Django (settings.py). En esta lista, cada componente se representa por un string: el camino completo al nombre de la clase. Por ejemplo:

MIDDLEWARE_CLASSES = (

'django.middleware.common.CommonMiddleware',

'django.contrib.sessions.middleware.SessionMiddleware',

'django.contrib.auth.middleware.AuthenticationMiddleware',

)

En el tratamiento de requests y la generación de responses, existen dos faces:

1) Fase Request (se llama a los métodos process_request() y process_view())

2) Fase Response (se llama a los métodos process_response() y process_exception())

En la primera, las clases son aplicadas desde la primera a la última, según el orden de la lista mencionada. En la segunda fase, se aplican en orden inverso; podemos pensarlo como una cebolla:

middleware

Una instalación de Django puede funcionar sin ningún middleware, pero esto no es recomendado.

Para escribir middleware propios

Cada componente es una clase Python, que no tiene que extender a ninguna clase en particular y debe definir uno o más de los siguientes métodos.

process_request(self, request)

request es un objeto HttpRequest. El método es llamada por cada request, antes de que Django decida que vista ejecutar.

Debe retornar None o un objeto HttpResponse. Si retorna None, Django seguirá procesando el request, ejecutando los otros middlewares y luego la vista apropiada. Si retorna un objeto HttpResponse, Django no hará nada más, solo retornar ese objeto.

process_view(self, request, view_func, view_args, view_kwargs)

request es un objeto HttpRequest. view_func es la función Python que Django está por usar. (Es el objeto function, no el nombre de la función en un string). view_args es un alista de argumentos posicionales que serán pasados a la vista. Y view_kwargs es un diccionario de argumentos de palagra clave que serán pasados a la vista. Ni view_args ni view_kwargs incluye al primer argumento de la vista (request).

process_view() es llamado antes de que Django ejecute la vista. Debe retornar None o un objeto HttpResponse. Si retorna None, Django seguirá procesando el request, ejecutando otros process_view() y luego la vista apropiada. Si retorna un objeto HttpResponse, Django no hará nada más, solo retornar ese objeto.

process_response(self, request, response)

request es un objeto HttpRequest. response es un objeto HttpResponse retornado por una vista de Django.

process_response() debe retornar un objeto HttpResponse. Puede altener el objeto response dado o puede crear uno nuevo.

A diferencia de proces_request() y process_view(), este siempre es ejecutado.

process_exception(self, request, exception)

request es un objeto HttpRequest. exception es un objeto Exception lanzado por la vista.

Django llama a process_exception() cuando la vista lanza una excepción. process_exception() debe retornar None o un objeto HttpResponse. Si retorna un objeto HttpResponse, la respuesta es devuelta al navegador. De lo contrario, el sistema por defecto para manejo de excepciones entra en acción.

__init__

Por lo general estas clases no tienen estado; simplemente contienen a los anteriores métodos. Se puede usar el método init pero se debe tener en cuenta que Django inicializa estas clases sin argumentos y que el método init es llamado solo una vez, cuando el servidor web arranca.

Experimento

Con lo anterior en mente, me quedaron algunas dudas al respecto:

  • si modifico los argumentos de view_func en process_view y retorno None, ¿estos son pasados modificados a la vista?
  • si lo anterior es falso, puedo lograr el mismo efecto haciendo:
    def process_view(self,request, view_func, view_args, view_kwargs):
    
        # modificar request, view_args y view_kwargs
    
        return view_func(request, view_args, view_kwargs)
    ?
  • ¿puedo definir process_response de tal forma que examine response?


Una gran oportunidad de conocer Python!

El 4 y 5 de Septiembre se va a llevar a cabo en Capital Federal el evento PyCon Argentina 2009.

Organizado por la comunidad, con entrada libre y gratuita, se llevará a cabo en la Universidad de Belgrano. Habrá charlas plenarias, programadas y relámpago.

PyCon 2009 Argentina

¿Querés conocer Python? ¿Venís oyendo sobre este lenguaje por mucho tiempo y todavía no te animaste a probarlo? Esta es tu oportunidad! Te esperamos!