Rust es el lenguaje de programación más querido por quinta vez. Es nuestro nuevo salvador de la seguridad?

Publicado el 18 de junio de 2020
por el doctor Matias Madou
ESTUDIO DE CASO

Rust es el lenguaje de programación más querido por quinta vez. Es nuestro nuevo salvador de la seguridad?

Publicado el 18 de junio de 2020
por el doctor Matias Madou
Ver recurso
Ver recurso

Desde hace unos años, parece que los ingenieros de software de todo el mundo no se cansan de programar con Rust. Este lenguaje de programación de sistemas relativamente nuevo, producido por Mozilla, ha capturado los corazones de la comunidad de Stack Overflow y, como cohorte muy poco propensa a sufrir tonterías, cuando votan algo como el"lenguaje de programación más amado" cinco años seguidos, es hora de que todos nos sentemos y tomemos nota.

El lenguaje de programación Rust incorpora elementos conocidos y funcionales de lenguajes de uso común, trabajando con una filosofía diferente que se deshace de la complejidad, al tiempo que introduce rendimiento y seguridad. Es una curva de aprendizaje, y muchos desarrolladores no tienen la oportunidad de jugar mucho con él: sólo el 5,1% de los encuestados en Stack Overflow lo utilizan habitualmente. Sin embargo, dejando esto de lado, no se puede negar que es un lenguaje apasionante, y con mucha más potencia de seguridad que sus predecesores, como C y C++. La adopción masiva va a requerir algunos cambios, tanto de comportamiento como tecnológicos... pero ahora mismo, sigue captando la atención de los desarrolladores a nivel teórico.  

... pero espera, tenemos que iluminar una cosa más: es importante tener en cuenta que Rust es un lenguaje de programación que prioriza la seguridad de la memoria, y la erradicación de los errores de seguridad que están casados con problemas comunes de gestión de la memoria. Estos son un gran problema (y sin duda causan más de un equipo de AppSec migrañas), pero no son los únicos desafíos de codificación segura que enfrentamos.

¿Qué impide exactamente el óxido? ¿Y en qué aspectos del panorama de la seguridad seguimos estando expuestos? Desgranemos el último unicornio de la programación:

La nueva frontera de la programación de sistemas modernos con seguridad de memoria

El equipo de investigación y desarrollo de Mozilla ha trabajado en algunos proyectos increíbles, y la inversión en la programación de Rust como pionera del código abierto no es una excepción. Su vídeo introductorio ofrece una visión de su ética, con el tema clave muy claro: el enfoque actual de la seguridad del software es defectuoso, y Rust está diseñado para resolver gran parte de ese problema.

Parece demasiado simplista, sobre todo porque cada dos por tres nos enfrentamos a enormes violaciones de datos, como la reciente y espantosa metedura de pata de EasyJet. Millones de registros de datos se ven comprometidos con frecuencia, casi siempre obra de una vulnerabilidad de la aplicación web, una mala configuración de la seguridad o un ataque de phishing, y lenguajes como C++ existen desde hace décadas. Sin embargo, no ha sido suficiente tiempo para que los desarrolladores los dominen hasta el punto de aplicar las mejores prácticas de codificación segura. ¿Por qué Rust debería ser diferente? Ya han aparecido nuevos lenguajes, y no es que hayan encontrado una manera de erradicar las vulnerabilidades comunes, o de asegurar que cualquier código escrito sea mágicamente perfecto cuando se compila.

Aunque el concepto sea sencillo, a veces son las respuestas simples las que conquistan las preguntas complejas. Rust es, en todo el sentido de la palabra, una revolución en la programación de sistemas a prueba de memoria que cumple con sus promesas en muchos aspectos... y ciertamente salva el tocino de los desarrolladores que son susceptibles de introducir errores que pueden causar grandes problemas si no se detectan. Java, C, C++, e incluso lenguajes más nuevos como Kotlin y Golang, siguen siendo bastante implacables para el desarrollador que no es consciente de la seguridad. Con ellos, no hay advertencias incorporadas, no hay señales particulares de que la impresionante característica que acaba de ser compilada tiene un gremlin de seguridad escondido bajo el capó.

Así que vamos a profundizar:

¿Qué hace que el óxido sea tan seguro?

Por lo general, un desarrollador tiene como objetivo principal crear características, asegurándose de que sean funcionales y fáciles de usar - tal vez incluso fuentes de orgullo que estarían felices de mostrar en su currículum. Es totalmente normal que un desarrollador cree un gran software, lo envíe y pase al siguiente gran proyecto. En ese momento, los equipos de seguridad comprueban si hay vulnerabilidades y, si las encuentran, su aplicación "terminada" puede volver a su equipo para que la corrijan. El problema puede ser sencillo, o puede estar completamente fuera del alcance razonable de un desarrollador para remediarlo.

El problema es que a nivel superficial, los fallos de seguridad no eran aparentes en absoluto, y si el escaneo, las pruebas y la revisión manual del código no los detectan, entonces un atacante puede aprovechar esa pequeña ventana de oportunidad para explotar el fallo.

Ahora, Rust busca evitar que muchas vulnerabilidades lleguen al código en primer lugar: simplemente no compilará si hay errores de sintaxis, u otros errores de seguridad de memoria que causan problemas de producción a lo largo del SDLC. Se trata de una programación a prueba de memoria por diseño, que garantiza que no hay acceso a la memoria no válida (independientemente de cómo se ejecute el software). Y dado que el 70% de los fallos de seguridad son el resultado de problemas relacionados con la gestión de la memoria, esto es una gran hazaña.

El óxido marcará e impedirá:

  • Desbordamiento del búfer
  • Utilizar después de libre
  • Doblemente libre
  • Desviación de puntero nulo
  • Uso de memoria no inicializada

Si comparamos un fragmento de código de Rust con el de C++, resultará evidente que uno de ellos es seguro por defecto. Mira este ejemplo de un error de desbordamiento de búfer:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Comparar un fragmento de código Rust

Rust lanza una advertencia de seguridad, y entra en pánico al llegar a la función copy_from_slice en tiempo de ejecución para evitar el desbordamiento del buffer, pero no en tiempo de compilación.

En este sentido, es uno de los lenguajes que "empiezan por la izquierda". Pondrá de manifiesto los errores y obligará a los desarrolladores a escribir el código de forma correcta para evitar introducir fallos de seguridad relacionados con la memoria, por lo que el cumplimiento de los plazos depende de que el programador preste atención, ponga remedio y se mantenga fiel a la ruta de entrega.

El planteamiento de este lenguaje parece sencillo, pero habría sido una hazaña increíble conseguir que funcionara con esta potente lógica, y lo cumple. Rust es, desde el punto de vista de la seguridad, un paso de gigante... si sólo lo usara más gente. Compañías como Dropbox son pioneras en su uso a gran escala, y eso es genial de ver. Pero, hay más consideraciones antes de llegar a la conclusión de que un problema de adopción es todo lo que nos impide un futuro más seguro.

El ajuste de cuentas de Rust.

Hay un par de pequeños (bueno, grandes) problemas, a saber, que la programación en Rust tiene más flexibilidad para introducir errores de lo que podría parecer. No solucionará las vulnerabilidades del Top 10 de OWASP, que siguen provocando brechas, retrasos y una cultura general de técnicas de codificación inseguras. También hay algo de una dinámica de ángeles y demonios, o, como es más conocido: Rust seguro vs. Rust inseguro.

Como se explica en la documentación oficial, el Rust Seguro es la forma "verdadera" de Rust, y el Rust Inseguro incluye funciones que se consideran "definitivamente no seguras", aunque a veces son necesarias - como si se requiere la integración con algo en otro lenguaje. Sin embargo, incluso con Unsafe Rust, la lista de funcionalidades adicionales sigue siendo limitada. En Rust inseguro, es posible hacer lo siguiente dentro de bloques inseguros:

  • Dereferencia de punteros sin procesar
  • Llamar a funciones no seguras (incluyendo funciones C, intrínsecas del compilador y el asignador bruto)
  • Implementar rasgos inseguros
  • Mutar la estática
  • Acceder a los campos de las uniones.

Incluso en el llamado modo "inseguro", uno de los superpoderes de la programación de Rust sigue funcionando: el "verificador de préstamos". Por lo general, previene los problemas de memoria, las colisiones en los cálculos paralelos y muchos otros errores a través del análisis estático del código, y este análisis seguirá haciendo comprobaciones en un bloque inseguro, solo que requiere mucho más trabajo para escribir construcciones inseguras sin que el compilador intervenga con una guía en determinadas situaciones.

Esto no parece un gran problema para la mayoría de los desarrolladores experimentados - después de todo, somos conocidos por retocar para obtener lo mejor de nuestras aplicaciones y abrir algunas funciones más geniales - pero potencialmente abre un agujero negro que puede conducir a graves errores de configuración y vulnerabilidades de seguridad: el comportamiento indefinido. La programación en Rust (incluso cuando se utiliza de forma insegura) bloquea las posibilidades de vulnerabilidades bastante bien en comparación con C o C++, pero invocar un comportamiento indefinido puede ser un riesgo.

¿Es el fin de la confianza en la codificación segura dirigida por los desarrolladores?

¿Recuerdas que antes dije que Rust tiene componentes de lenguajes conocidos? Una de las principales vulnerabilidades de seguridad de Rust es que, bueno, tiene componentes de lenguajes conocidos, concretamente C.

Rust sigue siendo un "lenguaje de programación seguro", pero, de nuevo, la introducción de un usuario es donde las cosas pueden despegarse. El desarrollador todavía puede ajustarlo para que se ejecute sin marcar errores (una propuesta atractiva, ya que esto desbloquea más capacidades), y esencialmente, incluso en un estado seguro, los desarrolladores todavía pueden ser tan "inseguros" como quieran, porque tienen una capa de orientación y protección antes de que las cosas puedan ir realmente mal.

Y ambos escenarios anteriores se vuelven más peligrosos a medida que profundizamos, ya que los resultados de Rust son similares a los de las herramientas de escaneo - así como no existe una herramienta SAST/DAST/RAST/IAST del ejército suizo que escanee cada vulnerabilidad, cada vector de ataque y cada problema, Rust tampoco lo hace. Incluso con Rust se pueden introducir algunas vulnerabilidades con bastante facilidad.

El riesgo de comportamiento indefinido cuando se ejecuta Rust inseguro tiene el potencial de abrir problemas de desbordamiento de enteros, mientras que, en general, incluso las configuraciones seguras no evitarán el error humano en las configuraciones erróneas de seguridad, la lógica de negocio o el uso de componentes con vulnerabilidades conocidas. Estos problemas siguen representando una amenaza muy real si se dejan sin parchear, y en un entorno "supuestamente seguro" como el verdadero Rust, puede incluso causar un comportamiento complaciente si un codificador cree que todos los problemas importantes serán recogidos a pesar de todo.

He descubierto que Rust no es muy diferente a un mentor de programación - un ingeniero senior que se ha tomado el tiempo de sentarse con un codificador menos experimentado, revisando su trabajo y mostrándole los posibles errores, señalando las eficiencias y, en algunos casos, asegurándose de que no se compila hasta que esté bien. Sin embargo, es mucho mejor que los programadores de Rust aprendan la teoría y se comprometan con las mejores prácticas por sí mismos, ya que ese mentor podría cortar las cuerdas del delantal, y tú no quieres quedarte colgado.

¿Preparado para encontrar y solucionar vulnerabilidades comunes de Rust ahora mismo? Juega al desafío.
Ver recurso
Ver recurso

Autor

Doctor Matias Madou

Matías es un investigador y desarrollador con más de 15 años de experiencia práctica en seguridad de software. Ha desarrollado soluciones para empresas como Fortify Software y su propia empresa Sensei Security. A lo largo de su carrera, Matías ha dirigido múltiples proyectos de investigación sobre seguridad de aplicaciones que han dado lugar a productos comerciales y cuenta con más de 10 patentes en su haber. Cuando está lejos de su escritorio, Matias ha servido como instructor para la formación de seguridad de aplicaciones avanzadas courses y regularmente habla en conferencias mundiales como la Conferencia RSA, Black Hat, DefCon, BSIMM, OWASP AppSec y BruCon.

Matías es doctor en Ingeniería Informática por la Universidad de Gante, donde estudió la seguridad de las aplicaciones mediante la ofuscación de programas para ocultar el funcionamiento interno de una aplicación.

¿Quieres más?

Sumérjase en nuestras últimas ideas sobre codificación segura en el blog.

Nuestra amplia biblioteca de recursos tiene como objetivo potenciar el enfoque humano de la mejora de la codificación segura.

Ver blog
¿Quieres más?

Obtenga las últimas investigaciones sobre la seguridad impulsada por los desarrolladores

Nuestra amplia biblioteca de recursos está repleta de recursos útiles, desde libros blancos hasta seminarios web, que le ayudarán a iniciarse en la codificación segura orientada a los desarrolladores. Explórela ahora.

Centro de recursos

Rust es el lenguaje de programación más querido por quinta vez. Es nuestro nuevo salvador de la seguridad?

Publicado el 18 de junio de 2020
Por el doctor Matias Madou

Desde hace unos años, parece que los ingenieros de software de todo el mundo no se cansan de programar con Rust. Este lenguaje de programación de sistemas relativamente nuevo, producido por Mozilla, ha capturado los corazones de la comunidad de Stack Overflow y, como cohorte muy poco propensa a sufrir tonterías, cuando votan algo como el"lenguaje de programación más amado" cinco años seguidos, es hora de que todos nos sentemos y tomemos nota.

El lenguaje de programación Rust incorpora elementos conocidos y funcionales de lenguajes de uso común, trabajando con una filosofía diferente que se deshace de la complejidad, al tiempo que introduce rendimiento y seguridad. Es una curva de aprendizaje, y muchos desarrolladores no tienen la oportunidad de jugar mucho con él: sólo el 5,1% de los encuestados en Stack Overflow lo utilizan habitualmente. Sin embargo, dejando esto de lado, no se puede negar que es un lenguaje apasionante, y con mucha más potencia de seguridad que sus predecesores, como C y C++. La adopción masiva va a requerir algunos cambios, tanto de comportamiento como tecnológicos... pero ahora mismo, sigue captando la atención de los desarrolladores a nivel teórico.  

... pero espera, tenemos que iluminar una cosa más: es importante tener en cuenta que Rust es un lenguaje de programación que prioriza la seguridad de la memoria, y la erradicación de los errores de seguridad que están casados con problemas comunes de gestión de la memoria. Estos son un gran problema (y sin duda causan más de un equipo de AppSec migrañas), pero no son los únicos desafíos de codificación segura que enfrentamos.

¿Qué impide exactamente el óxido? ¿Y en qué aspectos del panorama de la seguridad seguimos estando expuestos? Desgranemos el último unicornio de la programación:

La nueva frontera de la programación de sistemas modernos con seguridad de memoria

El equipo de investigación y desarrollo de Mozilla ha trabajado en algunos proyectos increíbles, y la inversión en la programación de Rust como pionera del código abierto no es una excepción. Su vídeo introductorio ofrece una visión de su ética, con el tema clave muy claro: el enfoque actual de la seguridad del software es defectuoso, y Rust está diseñado para resolver gran parte de ese problema.

Parece demasiado simplista, sobre todo porque cada dos por tres nos enfrentamos a enormes violaciones de datos, como la reciente y espantosa metedura de pata de EasyJet. Millones de registros de datos se ven comprometidos con frecuencia, casi siempre obra de una vulnerabilidad de la aplicación web, una mala configuración de la seguridad o un ataque de phishing, y lenguajes como C++ existen desde hace décadas. Sin embargo, no ha sido suficiente tiempo para que los desarrolladores los dominen hasta el punto de aplicar las mejores prácticas de codificación segura. ¿Por qué Rust debería ser diferente? Ya han aparecido nuevos lenguajes, y no es que hayan encontrado una manera de erradicar las vulnerabilidades comunes, o de asegurar que cualquier código escrito sea mágicamente perfecto cuando se compila.

Aunque el concepto sea sencillo, a veces son las respuestas simples las que conquistan las preguntas complejas. Rust es, en todo el sentido de la palabra, una revolución en la programación de sistemas a prueba de memoria que cumple con sus promesas en muchos aspectos... y ciertamente salva el tocino de los desarrolladores que son susceptibles de introducir errores que pueden causar grandes problemas si no se detectan. Java, C, C++, e incluso lenguajes más nuevos como Kotlin y Golang, siguen siendo bastante implacables para el desarrollador que no es consciente de la seguridad. Con ellos, no hay advertencias incorporadas, no hay señales particulares de que la impresionante característica que acaba de ser compilada tiene un gremlin de seguridad escondido bajo el capó.

Así que vamos a profundizar:

¿Qué hace que el óxido sea tan seguro?

Por lo general, un desarrollador tiene como objetivo principal crear características, asegurándose de que sean funcionales y fáciles de usar - tal vez incluso fuentes de orgullo que estarían felices de mostrar en su currículum. Es totalmente normal que un desarrollador cree un gran software, lo envíe y pase al siguiente gran proyecto. En ese momento, los equipos de seguridad comprueban si hay vulnerabilidades y, si las encuentran, su aplicación "terminada" puede volver a su equipo para que la corrijan. El problema puede ser sencillo, o puede estar completamente fuera del alcance razonable de un desarrollador para remediarlo.

El problema es que a nivel superficial, los fallos de seguridad no eran aparentes en absoluto, y si el escaneo, las pruebas y la revisión manual del código no los detectan, entonces un atacante puede aprovechar esa pequeña ventana de oportunidad para explotar el fallo.

Ahora, Rust busca evitar que muchas vulnerabilidades lleguen al código en primer lugar: simplemente no compilará si hay errores de sintaxis, u otros errores de seguridad de memoria que causan problemas de producción a lo largo del SDLC. Se trata de una programación a prueba de memoria por diseño, que garantiza que no hay acceso a la memoria no válida (independientemente de cómo se ejecute el software). Y dado que el 70% de los fallos de seguridad son el resultado de problemas relacionados con la gestión de la memoria, esto es una gran hazaña.

El óxido marcará e impedirá:

  • Desbordamiento del búfer
  • Utilizar después de libre
  • Doblemente libre
  • Desviación de puntero nulo
  • Uso de memoria no inicializada

Si comparamos un fragmento de código de Rust con el de C++, resultará evidente que uno de ellos es seguro por defecto. Mira este ejemplo de un error de desbordamiento de búfer:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Comparar un fragmento de código Rust

Rust lanza una advertencia de seguridad, y entra en pánico al llegar a la función copy_from_slice en tiempo de ejecución para evitar el desbordamiento del buffer, pero no en tiempo de compilación.

En este sentido, es uno de los lenguajes que "empiezan por la izquierda". Pondrá de manifiesto los errores y obligará a los desarrolladores a escribir el código de forma correcta para evitar introducir fallos de seguridad relacionados con la memoria, por lo que el cumplimiento de los plazos depende de que el programador preste atención, ponga remedio y se mantenga fiel a la ruta de entrega.

El planteamiento de este lenguaje parece sencillo, pero habría sido una hazaña increíble conseguir que funcionara con esta potente lógica, y lo cumple. Rust es, desde el punto de vista de la seguridad, un paso de gigante... si sólo lo usara más gente. Compañías como Dropbox son pioneras en su uso a gran escala, y eso es genial de ver. Pero, hay más consideraciones antes de llegar a la conclusión de que un problema de adopción es todo lo que nos impide un futuro más seguro.

El ajuste de cuentas de Rust.

Hay un par de pequeños (bueno, grandes) problemas, a saber, que la programación en Rust tiene más flexibilidad para introducir errores de lo que podría parecer. No solucionará las vulnerabilidades del Top 10 de OWASP, que siguen provocando brechas, retrasos y una cultura general de técnicas de codificación inseguras. También hay algo de una dinámica de ángeles y demonios, o, como es más conocido: Rust seguro vs. Rust inseguro.

Como se explica en la documentación oficial, el Rust Seguro es la forma "verdadera" de Rust, y el Rust Inseguro incluye funciones que se consideran "definitivamente no seguras", aunque a veces son necesarias - como si se requiere la integración con algo en otro lenguaje. Sin embargo, incluso con Unsafe Rust, la lista de funcionalidades adicionales sigue siendo limitada. En Rust inseguro, es posible hacer lo siguiente dentro de bloques inseguros:

  • Dereferencia de punteros sin procesar
  • Llamar a funciones no seguras (incluyendo funciones C, intrínsecas del compilador y el asignador bruto)
  • Implementar rasgos inseguros
  • Mutar la estática
  • Acceder a los campos de las uniones.

Incluso en el llamado modo "inseguro", uno de los superpoderes de la programación de Rust sigue funcionando: el "verificador de préstamos". Por lo general, previene los problemas de memoria, las colisiones en los cálculos paralelos y muchos otros errores a través del análisis estático del código, y este análisis seguirá haciendo comprobaciones en un bloque inseguro, solo que requiere mucho más trabajo para escribir construcciones inseguras sin que el compilador intervenga con una guía en determinadas situaciones.

Esto no parece un gran problema para la mayoría de los desarrolladores experimentados - después de todo, somos conocidos por retocar para obtener lo mejor de nuestras aplicaciones y abrir algunas funciones más geniales - pero potencialmente abre un agujero negro que puede conducir a graves errores de configuración y vulnerabilidades de seguridad: el comportamiento indefinido. La programación en Rust (incluso cuando se utiliza de forma insegura) bloquea las posibilidades de vulnerabilidades bastante bien en comparación con C o C++, pero invocar un comportamiento indefinido puede ser un riesgo.

¿Es el fin de la confianza en la codificación segura dirigida por los desarrolladores?

¿Recuerdas que antes dije que Rust tiene componentes de lenguajes conocidos? Una de las principales vulnerabilidades de seguridad de Rust es que, bueno, tiene componentes de lenguajes conocidos, concretamente C.

Rust sigue siendo un "lenguaje de programación seguro", pero, de nuevo, la introducción de un usuario es donde las cosas pueden despegarse. El desarrollador todavía puede ajustarlo para que se ejecute sin marcar errores (una propuesta atractiva, ya que esto desbloquea más capacidades), y esencialmente, incluso en un estado seguro, los desarrolladores todavía pueden ser tan "inseguros" como quieran, porque tienen una capa de orientación y protección antes de que las cosas puedan ir realmente mal.

Y ambos escenarios anteriores se vuelven más peligrosos a medida que profundizamos, ya que los resultados de Rust son similares a los de las herramientas de escaneo - así como no existe una herramienta SAST/DAST/RAST/IAST del ejército suizo que escanee cada vulnerabilidad, cada vector de ataque y cada problema, Rust tampoco lo hace. Incluso con Rust se pueden introducir algunas vulnerabilidades con bastante facilidad.

El riesgo de comportamiento indefinido cuando se ejecuta Rust inseguro tiene el potencial de abrir problemas de desbordamiento de enteros, mientras que, en general, incluso las configuraciones seguras no evitarán el error humano en las configuraciones erróneas de seguridad, la lógica de negocio o el uso de componentes con vulnerabilidades conocidas. Estos problemas siguen representando una amenaza muy real si se dejan sin parchear, y en un entorno "supuestamente seguro" como el verdadero Rust, puede incluso causar un comportamiento complaciente si un codificador cree que todos los problemas importantes serán recogidos a pesar de todo.

He descubierto que Rust no es muy diferente a un mentor de programación - un ingeniero senior que se ha tomado el tiempo de sentarse con un codificador menos experimentado, revisando su trabajo y mostrándole los posibles errores, señalando las eficiencias y, en algunos casos, asegurándose de que no se compila hasta que esté bien. Sin embargo, es mucho mejor que los programadores de Rust aprendan la teoría y se comprometan con las mejores prácticas por sí mismos, ya que ese mentor podría cortar las cuerdas del delantal, y tú no quieres quedarte colgado.

¿Preparado para encontrar y solucionar vulnerabilidades comunes de Rust ahora mismo? Juega al desafío.

Nos gustaría contar con su permiso para enviarle información sobre nuestros productos y/o temas relacionados con la codificación segura. Siempre trataremos sus datos personales con el máximo cuidado y nunca los venderemos a otras empresas con fines de marketing.

Enviar
Para enviar el formulario, habilite las cookies "Analytics". Siéntase libre de desactivarlas de nuevo una vez que haya terminado.