A data diode is a network device that only allows data to travel in one direction, they are
used primarily in high security applications like nuclear plants, industrial automation, and
armies all over the world. There reason they aren't more widely used, the sacrifice for
their high security is that normal transport protocols don't work over data diodes, as
they require a bidirectional connection.
And here is where everything becomes muddy, because to overcome this limitation some data
diodes use a secondary channel from the isolated side to the untrusted side to send flow
control information back so TCP connection can pass through. This makes them potentially
vulnerable to a covert channel attack,
but there's almost no information on vulnerabilities, attacks, or test tools.
So I wrote leaky diode a test tool to check
if they are resistant to a couple of a very simple attacks.
The Attacks
The attacks described in this post require a compromised host on the isolated side, and have
a very low throughput (aroud 1 Bytes/min), so they can't realistically be used to leak more
than a few KB of data.
Regardless of the limitations there're still many fields where even such small leaks
would be catastrophic, and would love to be able to test their diodes so lets dive in.
Close Delay
Close delay uses the delay between the start of a connection and the time it's closed
by the server to encode the secret bits.
1 (CLIENT) Open a connection to the server.
2 (CLIENT) Send a request for one of the secret bits and a threshold delay,
then continue sending junk data to keep the connection alive.
3 (SERVER) After receiving a request, close the connection inmediately if the value
of the secret bit is 0, or wait threshold delay before closing the connection if the
value is 1.
4 (CLIENT) If the delay between sending the request to the server and the server
closing the connection is greater than threshold/2 then the bit value is
1, and 0 otherwise.
This attack works well in almost all circunstances, as it doesn't require much bandwith
and is not affected by network lattency or buffers in the data diodes. The drawback is
that uses so many connections tha can be easily detected.
Flow Modulation
Flow modulation uses the flow control mechanisms of TCP to transmit data using the
throughput of a connection as the carrier.
1 (CLIENT) Connect with the server and set the tx rates to signal low and high bits.
(i.e- 60KB/sec for low 300KB/sec for high bits)
2 (CLIENT) Send a request for one of the secret's bits, and start sending random
data at a rate greater than the max encoding rate.
3 (SERVER) On reception of a request start throttling the connection to the
to the speed that encodes the value of the requested bit/bits. (as provided in step 1)
4 (CLIENT) Wait until the data rate stabilizes/settles and then sample it to obtain the bit
value.
5 (CLIENT) Go to step 1 until all the secret bits have been read.
This attack is harder to detect than close delay as it uses a single connection and not
thousands to exfiltrate the data, the data sent can also be made to mimic another protocol
like http to make it even harder to detect. And with enough care a finely tunned tool could
use very close tx rates for high and low values, so it's indistinguishable from a legitimate
connection.
The drawback is that it's vulnerable to network congestion, QoS, and large TCP stack
buffers that can make it inconsistent.
Lower level attacks
If you have privileges to directly manipulate the stack, there are few more possible attacks
that may work depending on the diode:
Using the ACK delay since the reception of a packet.
Only sending ACK on even or odd sequence numbers, to encode low/high bits.
Manipulating the window size.
Some of these are harder to implement and easier to defend against by the diode, but are
great candidades to embed into the OS. Just to be clear I haven't tested any of them.
Test tool
If you have a diode you want to test, download leaky diode
On the isolated side launch the server:
$leaky_server public_ip port 'secret string to leak'
$leaky_client server_ip server_port --mode close --partial
Then wait for a few minutes until the first bytes start to arrive, or if you are impacient add
--verbose argument to show notifications on each bit sent/received.
Se acaba de publicar la nueva entrega de
Two Scoops of Django
la guía definitiva de buenas practicas para Django 1.8, tengo la versión anterior
y he comprado esta. No es un libro para principiantes, pero se lo recomiendo a todos
los desarrolladores experimentados que seguro que encuentran algún truco o
consejo útil. Además la versión de Django 1.8 tiene la particularidad de ser
“Long-Term Support” (LTS) por lo que tiene soporte de 3 años, así que el libro va
a estar actualizado durante más tiempo que versiones anteriores.
Por ahora sólo está disponible en inglés y lo puedes
comprar en Amazon
Hoy he estado programando en Django una vista para la descarga de informes, en
la que los usuarios registrados de una página pueden pedir un informe de la actividad
para un determinado año. La particularidad es que esos informes se generan de forma
dinámica en el momento de la petición, nada complicado pero antes de empezar a
programar he buscado que paquetes había disponibles, y me he encontrado
django-downloadview.
Con eso y un poco de código extra para comprobar que el usuario está autenticado
he solucionado el problema. Algunas veces CBV parecen magia.
#views.pyfromdjango.shortcutsimportrenderfromdjango.core.files.baseimportContentFilefromdjango_downloadviewimportVirtualDownloadViewfromdjango.httpimportHttpResponseForbidden,HttpResponseServerErrorclassLoginRequiredMixin(object):defdispatch(self,request,*args,**kwargs):ifnotrequest.user.is_authenticated():returnHttpResponseForbidden()else:returnsuper(LoginRequiredMixin,self).dispatch(request,*args,**kwargs)classDownloadReportView(LoginRequiredMixin,VirtualDownloadView):defgenerar_report(self,user,year):# Generar contenido del informe para el usuario y fechareturn"Report content for {}{}".format(user.username,year)defget_file(self):# Metodo de VirtualDownloadView que devuelve el archivo virtualreport_name='report.txt'returnContentFile(self.report_content,name=report_name)defget(self,request,*args,**kwargs):report_year=kwargs.get('year',None)# El contenido del informe se genera aquí en lugar de en get_file, para# simplificar latry:self.report_content=self.generate_report(request.user,report_year)exceptException:returnHttpResponseServerError("There was an error while generating the report")returnsuper(DownloadReportView,self).get(request,*args,**kwargs)
Y el archivo urls.py para quien le pueda interesar:
Este es el primer artículo de una series en la que describo como usar
Django en conjunción con DigitalOcean para crear tu propio proveedor de
de servidores VPS. Algo que hace años hubiera sido impensable sin un equipo de
administradores y programadores, y que hoy puede implementarse con unos pocos
miles de lineas de código python.
Este artículo es una introducción al API de DigitalOcean y a su libreria de python,
la cual usaré en futuros artículos para implementar el servicio.
API de DigitalOcean
El API de Digitalocean actualmente
se encuentre en su segunda versión y es muy extenso, no solo permite crear, destruir,
y manejar Droplets(nombre que usa para sus VPS), sino que permite controlar
todos los aspectos de sus servicios, desde la gestión de DNS, hasta la creación
backups, o gestión imágenes. Puede acceder a la documentación del API
aquí
pero por suerte ya existe una libreria para python llamada
python-digitalocean
que simplifica enormemente el proceso, crear un Droplet puede ser tan sencillo
como:
El identificador devuelto durante la creación del Droplet luego puede ser
usado para manejarlo, en el siguiente ejemplo se reinicia, apaga y después
elimina:
La librería también permite redirigir dominios gestionados desde la DNS de
DigitalOcean, por ejemplo si tienes la dirección IP y el hostname de un
Droplet puedes redirigir un subdominio:
importdigitaloceanimporttldextractdroplet_ip="83.54.134.34"droplet_hostname="servidor.midominio.com"# Crear subdominio usando el hostname del servidord_subdomain,d_domain,d_suffix=tldextract.extract(droplet_hostname)domain=digitalocean.Domain(token="digitalocean-personal-access-token",name=d_domain+"."+d_suffix)result=domain.create_new_domain_record(type="A",name=d_subdomain,data=droplet_ip)domain_record_id=result['domain_record']['id']# Eliminar registro creadorecord=digitalocean.Record(id=domain_record_id,domain_name=d_domain+"."+d_suffix,token="digitalocean-personal-access-token")record.destroy()
Y con esto tenemos los fundamentos para manejar Droplets, pero antes de poder entregarlo
al usuario es necesario configurarlo/customizarlo al gusto del usuario.
Metadata y Cloudinit
DigitalOcean incluye un API de Metadatos,
que permite a los Droplets acceder a sus propios datos, suministrar datos de usuario
durante su creación, y procesar esos datos usando CloudInit
si es que contienen alguno de los formatos soportados. En el siguiente ejemplo se envía una
cadena que contiene dos variables:
CloudInit como su nombre indica es una herramienta para inicializar servidores
en la nube, la primera vez que arranca el servidor extrae los datos de configuración,
y si contienen alguno de los formatos soportados los procesa. Uno de esos formatos es
shell script, por ejemplo podemos enviar el siguiente script para crear un archivo
de swap de 2GB:
Cloud Config es otro formato muy versátil, que permite realizar la mayoría de las
tareas más comunes de configuración de forma muy sencilla, y ademas proporciona
funcionalidad extra con su sistema de módulos, en el siguiente ejemplo se añade los
mismos 2GB de swap:
Por último el formato Include File consiste en una lista de URLS cuyo
contenido es descargado y procesado usando las mismas reglas que si fueran los
datos proporcionados con user-data, por ejemplo:
Seguro que puedes ver el potencial de éste formato para esta aplicación. Si te
interesa conocer el resto de los formatos y módulos disponibles te recomiendo
que heches un vistazo a la
documentación
de cloud-init.
En la segunda parte de esta serie profundizare más en como implementar un sistema
de configuración de VPS con Django.
Los videos de Computerphile
siempre son interesantes, pero la última serie de tres videos explicando el funcionamiento
del algoritmo de compresión usado en jpeg, me ha parecido especialmente inspirada:
Si te han gustado los videos, puedes seguir profundizando con éste
artículo(tambíen en Inglés).
Si vas a crear un formulario donde se pueda introducir un DNI/NIF no necesitas
crear tu propio DNIField o programar un validador, ya existe en un paquete llamado
django-localflavor que agrupa ese tipo de campos para los distintos países.
Por ejemplo para España incluye:
ESPhoneNumberField - Números de teléfonos fijos y móviles.
ESIdentityCardNumberField - Numero de identificación NIF/CIF/NIE.
ESCCCField - Código de cuenta de cliente en formato EEEE-OOOO-CC-AAAAAAAAAA
ESProvinceSelect - Selección de provincia.
Instalación
Como siempre pip es la mejor opción para instalar el paquete:
$ pip install django-localflavor
Luego añade 'localflavor' a INSTALLED_APPS en settings.conf:
Al campo dni se le ha añadido la opción only_nif=True para que sólo acepte NIF y
NIE(Numero identificación extranjeros), sin ella también aceptaría códigos CIF.