Deserializando objetos Java sin los .class

En una auditoría que llevamos a cabo recientemente, surgió la necesidad de inspeccionar el contenido de ciertos ficheros en formato binario, que a todas luces se trataba de objetos Java serializados:

$ file serialized.bin 
serialized.bin: Java serialization data, version 5

En efecto, los dos primeros bytes eran el magic number de este tipo de ficheros:

0000000 edac 0500 ...
0000010 ...
0000020 ...
0000030 ...
0000040 ...

pero los objetos serializados debían ser relativamente complejos, por lo que un mero strings sobre el fichero no nos ayudaba a “descifrar” la información.

[Read more…]

Estadística del PIN

Si un ladrón nos robara la tarjeta de crédito, y sin contar con ningún tipo de información adicional (como nuestra fecha de nacimiento o la de nuestros familiares, nuestro número de teléfono, DNI, etc.), ¿qué números PIN debería probar en el cajero más próximo para tener la mayor probabilidad de quedarse con nuestro dinero?

En general, “se sabe” que ciertas contraseñas son escogidas con más frecuencia que otras, y por supuesto los números PIN no son una excepción. Recientemente, la gente de DataGenetics ha publicado PIN number analysis, que echa un poco de luz “cuantitativa” sobre este tema.

Básicamente, se han dedicado a recopilar fugas de información de entidades bancarias, reuniendo una muestra con la friolera de 3,4 millones de PIN reales de 4 cifras. Los resultados coinciden, por desgracia, con la creencia común; el más frecuente el “1234”, seguido por el “1111” y el “0000”:

PIN Frecuencia
#1 1234 10,713%
#2 1111 6,016%
#3 0000 1,881%
#4 1212 1,197%
#5 7777 0,745%
#6 1004 0,616%
#7 2000 0,613%
#8 4444 0,526%
#9 2222 0,516%
#10 6969 0,512%
#11 9999 0,451%
#12 3333 0,419%
#13 5555 0,395%
#14 6666 0,391%
#15 1122 0,366%
#16 1313 0,304%
#17 8888 0,303%
#18 4321 0,293%
#19 2001 0,290%
#20 1010 0,285%

(Fuente: PIN number analysis)

Probando el PIN “1234” sobre una tarjeta de crédito robada de entre la muestra, el ladrón del que hablábamos tendría un 10,713% de probabilidades de acertar a priori: aproximadamente 1 de cada 10 veces. Como los anteriores 20 números más frecuentes suponen un 26,832% del total, probándolos todos la probabilidad de acierto sería mayor que 1 de cada 4 veces.

Otras curiosidades: números que son más fáciles de escribir en un teclado telefónico (el empleado en los cajeros), como el “2580”, son más frecuentes (al ser más fáciles de escribir, también son más fáciles de recordar); los números pares son más frecuentes que los impares; números que empiezan por “19” son más frecuentes que los prefijados por cualquier otro par de números (¿años de nacimiento?); escaleras ascendientes (como “2345”) o descendientes (como “4321”) son más frecuentes que lo que deberían serlo por puro azar, así como repeticiones de pares (“1212”, “2828”), o números empezados por “1” o “0”. Os recomendamos encarecidamente la lectura completa del artículo, donde pueden encontrarse más curiosidades, resultados estadísticos, gráficas, etc.

¿Hasta qué punto los resultados muestrales serían extrapolables a la población de los números PIN de los usuarios de tarjetas de crédito de España? ¿Figura vuestro PIN en el top 20? ¿Y entre los números menos frecuentes? ;-)

Al margen de estas probabilidades “a priori”, cada día colgamos más y más información personal en las redes sociales e Internet en general, y a menudo es fácil obtener la fecha de nacimiento de una persona (o la de sus familiares), su dirección postal, número de móvil, o DNI, a partir de tan sólo su nombre completo, que suele figurar en la propia tarjeta de crédito.

Enlaces

Incorporando la seguridad al proceso de desarrollo de software

No es un secreto para nadie que una parte importante de los problemas de seguridad de los sistemas de información tiene su origen en defectos de las aplicaciones que éstos ejecutan. Tampoco lo es que estos defectos, que se manifiestan en forma de vulnerabilidades, se introducen en el software durante su proceso de desarrollo. Lo que a día de hoy no es algo aún suficientemente conocido, es la solución a este problema.

Históricamente, la industria del software ha funcionado usando una dinámica de liberar al mercado productos con un escaso nivel de madurez y se ha ocupado sobre la marcha de corregir los defectos que fueran apareciendo (véase el enfoque de Berkeley frente al del MIT en la entrada de Javier Vela al respecto, ¿Peor es mejor?). La situación actual es algo distinta ya que la capacidad del entorno de encontrar y explotar vulnerabilidades es muy elevada. Por tanto, liberar una aplicación al mercado, especialmente si está destinada a ofrecer servicios al público a través de Internet, sin haber tomado un mínimo de medidas para evitar la aparición de vulnerabilidades, es sin lugar a dudas una invitación al desastre.

La presión por cumplir con el calendario y el presupuesto de proyecto y la exigencia de los usuarios por disponer de nuevas funcionalidades, provocan con frecuencia que la seguridad no esté precisamente en la parte alta de la lista de prioridades de los equipos de desarrollo. Además, la eliminación de vulnerabilidades se suele entender como una tarea de la que alguien se encarga en la fase de testeo al final del ciclo de desarrollo, cuando la fase de programación ha concluido.

Sin embargo, el énfasis que desde distintas organizaciones se está haciendo por incorporar la seguridad al ciclo de desarrollo de software, así como iniciativas en esta línea de grandes corporaciones productoras de software, parece indicar que las tendencias están cambiando. Muchos pensamos hoy que todas las fases del proceso de desarrollo deberían compartir un objetivo: garantizar la seguridad del software.

A pesar de todo, es bastante común que en organizaciones que producen software, no exista ninguna incorporación formal de medidas de seguridad al ciclo de desarrollo. Los motivos son diversos: falta de presupuesto, de concienciación, de conocimiento… La realidad es que en la mayoría de los casos el software se valora fundamentalmente por la funcionalidad que implementa y la calidad del código raramente se considera; hasta que ocurre lo que nadie tuvo en cuenta…

La existencia de defectos de seguridad es hoy por hoy algo inevitable, sin embargo, la incorporación de una serie de medidas al proceso de desarrollo de software, permite reducir el riesgo a unos niveles aceptables. Con este objetivo se puede actuar en distintos puntos del proceso aplicando cada medida en el momento adecuado:

Análisis de requisitos

Resolver problemas de seguridad en un sistema en producción suele ser un proceso muy costoso y en ocasiones, con un alto impacto en el negocio e incluso en la imagen de la organización que ofrece el producto o servicio. Por este motivo, es importante tener en cuenta los controles necesarios para evitar su aparición desde fases tempranas del proceso, considerando los requisitos de seguridad como parte del análisis junto con los requisitos funcionales.

Es importante además no olvidar la consideración de aspectos de conformidad legal que incluyan en el catálogo de requisitos las obligaciones introducidas por regulaciones como la LOPD o la SOX entre otras.

Diseño

El diseño debe considerar aspectos como la reducción al mínimo de la interfaz atacable, así como su protección mediante la introducción de patrones y soluciones adecuadas para evitar la aparición de vulnerabilidades conocidas. En este punto es referencia obligada alguna de las guías existentes (las recomendaciones de OWASP por ejemplo) que recogen las vulnerabilidades más frecuentes junto con medidas técnicas para evitar su aparición.

Análisis de riegos (Casos de abuso y Modelado de amenazas)

Es frecuente que los analistas especifiquen los requisitos describiendo el comportamiento de un sistema “cuando todo va bien”. Esto suele llevar a una visión funcional del sistema basada en la asunción de que no va a ser objeto de abusos intencionados. Nada más lejos de la realidad, si el sistema va a ser usado, con toda seguridad se abusará de él (voluntaria a involuntariamente). El modelado de amenazas se realiza para determinar si el diseño propuesto mitiga los riesgos identificados y permite a los diseñadores ponerse en el papel del atacante:

  • ¿Qué partes del sistema son más fáciles de comprometer?
  • ¿Cuál es el impacto?

De esta forma las amenazas se identifican y se priorizan. A continuación se comprueba si la amenaza se mitiga mediante la implantación de un control. Si esto no es posible, se cambia el diseño o se asume el riesgo (idealmente, en función del risk appetite definido formalmente por la organización).

Análisis estático de código

En el pasado, el análisis de código se realizaba únicamente de forma manual. Era un proceso que daba buenos resultados cuando lo realizaba un experto, pero suponía un coste muy elevado. Hoy disponemos de herramientas de análisis estático que son capaces de identificar una buena parte de los errores de código por un coste mucho menor que el de un análisis manual.

El uso de estas herramientas es óptimo cuando todos los módulos que componen el software están completos e integrados. El análisis estático se debería realizar como mínimo en cada integración y siempre antes de liberar una nueva versión.

Testeo (o auditoria) de seguridad

Sería estupendo que el análisis estático fuese capaz de identificar todas las vulnerabilidades existentes en el software, pero desgraciadamente esto no es así. Por este motivo es necesaria la introducción de métodos dinámicos de testeo que interactúen con la aplicación como lo haría un atacante (Penetration Testing).

El testeo de seguridad es similar al testeo funcional del software con la diferencia de que en este caso se busca que la aplicación funcione de formas para las que no ha sido diseñada. El testeo funcional acaba (idealmente) cuando cada “feature” ha sido testeada, sin embargo, no es fácil identificar todas las cosas que una aplicación no debería hacer. Por este motivo es importante seguir una aproximación priorizada en la que se puede tomar como criterio la priorización realizada en el modelado de amenazas.

Existen varias herramientas que permiten la automatización del Penn Testing, pero de nuevo en este caso, será necesario contar con las manos de un experto para testear aquellos aspectos que no es posible automatizar.

¿Cómo empezar?

La incorporación de todas estas medidas, especialmente cuando se parte de una situación de poca cultura de seguridad, puede resultar algo abrumadora. Aunque el objetivo final debe ser que el proceso de desarrollo se enriquezca con todas las aportaciones descritas, no es imprescindible que se adopten todas desde el principio para obtener mejoras significativas en la seguridad del software producido.

La modificación del proceso se puede plantear como un proceso de mejora continua, empezando por aquellas medidas que requieren un esfuerzo y nivel de conocimiento y especialización moderado, para ir incorporando el resto según la experiencia y el know-how de la organización vaya creciendo.

Teniendo en cuenta que, especialmente en este caso, algo es mejor que nada, algunas de las medidas presentadas pueden ser adoptadas inicialmente asumiendo un coste reducido y con un retorno importante. El análisis de requisitos de seguridad puede ser la primera de ellas, garantizando así una toma de consciencia de los aspectos de seguridad a implementar. Por otro lado, la implantación de herramientas de análisis estático desde un principio, permite evitar un cantidad importante de errores y potenciales vulnerabilidades con una inversión muy contenida.

En este post se han presentado algunas medidas que tienen que ver directamente con el proceso de producción de software, pero existen algunas más que aplican al entorno de soporte del proceso (separación de entornos, seguridad de los repositorios de información, control de configuración, etc), pero eso da para otra entrada y lo trataremos en una próxima ocasión. Como siempre, pasen un buen fin de semana.

(Fuente de la imagen: OWASP)

Black Hat USA ’09

bhComo todos los veranos, este año se ha celebrado la Black Hat, un conjunto de conferencias donde se desvelan las ultimas tendencias en seguridad, cubriendo con detalle la parte técnica aunque también cada vez mas la parte organizativa y social. Aunque desgraciadamente no he podido asistir a estas charlas, tantos los papers comos los slides están disponibles en la web en la parte de archivos Blackhat.

Muchos equipos investigadores esperan a este evento para desvelar sus descubrimientos, por lo que creo que son de lectura obligatoria para aquellos que quieren ver por dónde van las ultimas tendencias y el “state of the art” en el mundo de la seguridad.

Tras echar un vistazo a las presentaciones, uno tiene la impresión que nada es seguro, ya sean teléfonos móviles, parquímetros, infraestructuras eléctricas, medidas antihacking, certificados SSL, la virtualización, la nube, o cualquier tipo de hardware que puedan imaginar. Los malos pueden incluso leer tu teclado desde el enchufe de tu ordenador, así que la única opción parece ser volver a las cuevas. En fin, que para cualquier “maldad” que puedan imaginar ya hay quien se dedica a aplicarla… y en estas charlas se pueden ver muchas de ellas.

[Read more…]

Errores en la web

(La entrada de hoy es la primera —pero no última— colaboración de Francisco Benet, un amigo de algunos de nosotros —y familia de algún otro— que tiene gran experiencia en la gestión e integración de sistemas, protección de datos de carácter personal y evaluación de soluciones de integración de software y hardware, entre otros aspectos. Esperamos que les guste.)

Habitualmente estamos acostumbrados a hablar de firewalls, defensa en profundidad y perimetral, detectores de intrusión y otros tantos artilugios tecnológicos que nos van a ayudar a mejorar la seguridad de nuestros sistemas. Pero nos dejamos por el camino puntos que son al menos igual de importantes; que no sustituyen pero se complementan entre ellos: la seguridad del código.

[Read more…]

¿En qué piensan los desarrolladores?

El otro día, mirando los archivos que tengo en el ordenador de casa encontré algunos proyectos antiguos en Visual Basic que diseñé hace algunos años. En aquella época trabajaba en una empresa muy pequeña (dos desarrolladores, un administrador de sistemas y “el jefe”), para nosotros todo lo que hacíamos era la mejor opción y los clientes quedaban bastantes satisfechos con nuestro trabajo. Los desarrollos los hacíamos con Visual Basic 6.0 contra bases de datos Microsoft Access y en el mejor de los casos SQL Server 2000; todo Microsoft, por supuesto.

Con los conocimientos de seguridad que he ido adquiriendo a lo largo de mi vida laboral me doy cuenta de que los proyectos que diseñábamos de manera tan “perfecta” tenían… ¡más vulnerabilidades que código escrito!, y que si un usuario malintencionado se hubiera entretenido en explotarlas hubiera destrozado el sistema en cuestión de segundos. Pensando en todo esto me pregunto: ¿Por qué diseñabámos así? ¿No teníamos los conocimientos necesarios? La respuesta es que en ningún momento del desarrollo nos planteábamos la posibilidad de que existieran usuarios malintencionados, o en otras palabras, asumíamos que “los usuarios de nuestra aplicación son demasiado torpes como para hacer esas cosas”. Obviamente, no puedes confiar en que los usuarios de tus aplicaciones vayan a ser “buenos” y no salirse del camino que les dibujas, porque si encuentras uno curioso, puedes llevarte más de una sorpresa desagradable.

Pongamos un ejemplo más técnico. En cierta ocasión, decidimos implementar un proyecto Windows en .Net, y en el app.config establecimos la cadena de conexión a la BBDD junto con el usuario y la clave con permisos de lectura y escritura. Se decidió publicarlo para que nos fuese más cómoda la implantación y las actualizaciones (funcionalidad de .Net que va de “serie” con el Visual Studio 2005). Probamos el funcionamiento de la aplicación una vez publicada y navegamos un poco por los ficheros que nos descargaba el instalador y… ¡sorpresa! El app.config lo había metido en la máquina del cliente (quizá con alguna extensión extra) y si se abría con el Notepad podía verse la cadena de conexión a la BBDD.

Con esta estrategia de implantación y de desarrollo teníamos un sistema poco seguro. ¿Qué opciones se plantean en casos como este?

(a) Presuponer que los usuarios van a conocer la cadena de conexión, el usuario y clave de acceso a la BBDD, por lo que se pueden establecer los permisos pensando en ello.

(b) Si los usuarios no deben conocer nunca datos sobre la BBDD, es necesario realizar un entorno cliente-servidor de manera que nuestra pequeña aplicación utilizada por los usuarios se conecte a una aplicación remota que haga las tareas de BBDD que se le soliciten. De esta manera nuestra aplicación cliente tiene datos de conectividad a nuestra aplicación servidor, pero nunca de la BBDD.

Para evitar todo esto hubiese sido necesario añadir una fase de seguridad adicional en nuestra metodología de desarrollo, en la que entre otras cosas adoptasemos el rol de un posible atacante, probando exhaustivamente todas las posibles casuísticas que hacían vulnerable la aplicación y estudiando la forma de ponerles remedio.

Como desarrollador, debo admitir que todo esto no me lo planteaba en aquella época, ya que diseñaba pequeños proyectos y nunca pensé que existirían usuarios tan “malvados” e “inteligentes” como para explotar posibles agujeros de seguridad. Pero si esos mismos proyectos los desarrollara hoy, por pequeños que fueran, nunca confiaría en que los usuarios lo vayan a utilizar de la manera esperada, sino que me pondría a la defensiva y trataría de pensar: si yo quisiera explotar esta aplicación… ¿qué haría?

Economía en tiempos de guerra

Pasamos una época complicada en el tema económico, en la que diversos estudios aseguran que aumentan las depresiones y las visitas al psicólogo, mientras que otros destacan el aumento del dinero destinado a juegos de azar por parte de las familias. Una de las alternativas de estos juegos de azar que muchos de ustedes conocerán son las apuestas por Internet, que quizá algunos incluso hayan probado.

El procedimiento de uso suele ser sencillo: un registro, un depósito monetario mediante tarjeta de crédito o similares y a buscar rentabilidad en las apuestas (no se preocupen, que ya les hablaré de eso otro día). Supongo que convendrán conmigo en que en esta época en la que el tema de la seguridad informática es tan candente, se le debe dar mucha importancia a las compañías que demuestran rigor al menos en la seguridad de sus portales. Al fin y al cabo parte de los ahorros —o no— de los usuarios va estar un tiempo en sus cuentas bancarias, hasta que éstos puedan recuperarlo.

Como medidas de seguridad, estos portales suelen ofrecen páginas cifradas con https, algunas incluso incorporan algún tipo de mecanismo de comprobación de fortaleza de contraseña en el registro, y en general, ofrecen la apariencia de preocuparse por el tema de la seguridad. Sin embargo, lo que para un usuario puede ser la diferencia para gastar o no su dinero, para las compañías parece no tener importancia. Entre otras cosas, no es extraño que los operadores que atienden el chat de ayuda de alguna de estas casas online soliciten la contraseña del usuario, lo que me hace suponer que almacenan las contraseñas en claro. No parece muy seguro, ¿verdad?

Por ejemplo, ¿realizarían algún tipo de transacción económica con una página que muestra el siguiente mensaje cuando se accede a su portal como un simple invitado?

query: DELETE FROM shoppingcart WHERE NOT EXISTS (SELECT 1 FROM session WHERE session.UserAccount_UserAccountID = shoppingcart.UserAccount_UserAccountID) -> Deadlock found when trying to get lock; try restarting transaction

Dejando a un lado estas pequeñas muestras de lo que no se debe hacer si se quiere ganar la confianza del usuario, y relacionado con el punto anterior, si me lo permiten me gustaría plantearles la siguiente cuestión, que será la encuesta de la semana y a la que podrán contestar a lo largo de esta semana:

[poll id=”6″]

* * *

(N.d.E.) En relación con la encuesta de la semana pasada, los resultados se muestran debajo, dando como resultado que una gran parte de las personas tienen una relativa concienciación de la seguridad, pero sin llegar al modo paranoico. En cualquier caso, la muestra no puede considerarse representativa, y no sólo por el número, sino también por el público objetivo de este blog.

[poll id=”5″]

Por lo demás, buen fin de semana a todos. Nos vemos el lunes, más y mejor.

SQL Injection

—Buenos días, Maestro, hoy vengo a traerte una ofrenda.
—Vaya, una tira cómica de xkcd… son un tanto curiosas.

exploits of a mom

—Sí, ésta la he encontrado en esta noticia de abril sobre un ataque de inyección de SQL. Me ha hecho gracia y se me ha ocurrido traerla como excusa para ver si eres capaz de decirme algo nuevo sobre un tema tan conocido ([1] [2] [3]) y que, sin embargo, sigue dándonos sustos tan a menudo.
—Pues precisamente acabo de leer hace nada otra noticia sobre un ataque a los servidores de MS SQL Server a través del IE7, que parece tener relación. Mira, aquí está. Aunque sé que no hace falta, te traduzco libremente algunas frases:

“[…] otra vulnerabilidad zero-day en un producto de MS. Esta vez es el SQL Server […] el bug de SQL permitiría la ejecución de código malicioso a un usuario autenticado mediante una conexión directa a la BD o también a través de una inyección SQL en una aplicación Web vulnerable […]”

—En la noticia de abril también se habla de inyección de SQL, aprovechando una funcionalidad del Microsoft Internet Information Server (IIS) que llama comandos genéricos, que sólo tiene SQL Server.
—Sí, recuerdo el caso. La vulnerabilidad es una funcionalidad de SQL Server, y eso es lo que permitió que el ataque fuera genérico y por tanto, masivo. Pero la puerta de entrada son las vulnerabilidades en las aplicaciones Web que había en los servidores. El revuelo en ambos casos viene porque la funcionalidad genérica en un caso y el bug en el otro son en productos de Microsoft y permiten ataques genéricos.
—Esto es un sinvivir.
—Claro, el problema es que el software sobre el que descansan nuestras aplicaciones es muy complejo y una vulnerabilidad se cuela con cierta facilidad. Es más, te diría que pasa poco para lo que podría pasar.
—Y, maestro, ¿qué hacemos? Si cambiamos de SGBD (Sistema de Gestión de Base de Datos), tendremos otras vulnerabilidades. No creo que Microsoft sea especialmente peor que los demás.
—Pues no. Lo que pasa es que, muchas veces, no se presta la atención debida a las aplicaciones que se construyen sobre el software de base y no podemos esperar que éste sea invulnerable a cualquier ataque. Además, la entrada se produce porque las aplicaciones Web no están bien diseñadas y programadas. Es decir, que nos dejamos las puertas abiertas. Por ejemplo, todavía no se siguen las reglas básicas para evitar los ataques de inyección de SQL, que, como bien sabes, son…
—Si, claro: “No utilizarás accesos a la BD en tus aplicaciones con privilegios mayores que lo mínimo imprescindible“, “No usarás sentencias SQL dinámicas con variables, sino queries parametrizadas“, “Usarás procedimientos almacenados con cuidado“, “No usaras nombres dinámicos de tablas, salvo en caso de extrema necesidad“…
—Cuando estas cosas hacen falta, vale la pena replantearse el diseño de la funcionalidad que quieres conseguir.
—Y con eso, ¿nos evitamos el riesgo?
—Lo reducimos, lo reducimos. Ya sabes que la seguridad absoluta no existe. Como decía Einstein, sólo hay dos cosas infinitas: el Universo y la estupidez humana… y, de lo primero, no estaba seguro.

XSS Cross-site Scripting (II)

()

—Perdona por la interrupción. Como te decía, desde el punto de vista de Alicia, hay poco que pueda hacer. Puede desactivar la ejecución de script en su navegador, lo que la dejará sin poder visitar muchas de las páginas que le interesan. Puede activarlo sólo para los sitios de confianza, asumiendo que éstos no son vulnerables a este tipo de ataques (lo que es mucho asumir) y, por supuesto, ser sanamente desconfiada para evitar la parte de ingeniería social del ataque. Y poco más. La responsabilidad está en quienes han desarrollado el sitio web vulnerable, que deben corregir la aplicación Web para que no lo sea.
—¿Se puede conseguir eso?
—Claro. El éxito del ataque se basa en que el sitio Web devuelve el código script que se le inyecta y que se ejecuta en el navegador de Alicia. Basta con no hacerlo.
—¿No devolver el script que luego se ejecuta?
—Ese es el enfoque que siguen muchos desarrolladores. Aplicar “html encoding“. ¿Sabes lo que significa?
—Sí, claro, se trata de “escapar” un carácter especial de un código html para que se muestre como tal, en lugar de ser interpretado por el navegador. Se utiliza siempre que se muestran ejemplos de html en un sitio Web.
—Exacto. Si quiero que en una página salga “<br />” en lugar de un salto de línea en el navegador, debo escribir “&lt;br /&gt;”, ya que esa secuencia tiene un significado especial. He de indicarle al navegador que no debe interpretarla, sino mostrarla, utilizando &lt; para “<" y lo mismo con el resto de caracteres. —Entonces, basta con “escapar" todos los caracteres especiales. —En principio. Claro que eso tiene el inconveniente de no permitir al usuario que introduzca negritas, cursivas o enlaces dentro de su texto. Quizás un inconveniente aceptable. —Bueno, se pueden permitir algunos de los caracteres especiales o, mejor dicho, determinadas combinaciones, como “<a href=", pero no otras, como “<script>". —Sí, claro. Es la táctica de detectar las entradas no deseables y eliminarlas o neutralizarlas. El problema es que hay más formas de introducir un script en un texto de manera que no se detecte con facilidad. Por ejemplo, se puede introducir “%3D%3C%73%63%72%69%70%74%3E", que es lo mismo que “<script>", como parte de una URL. Pero lo peor es que puedes estar protegiendo la aplicación frente a determinadas formas de introducir un script, pero luego aparecer en el futuro otras que no tenías previstas y no ser capaz de detectarlas. —Pero seguro que sabes una solución y me la vas a contar… —Pues la solución es obvia, si aplicamos una de las buenas prácticas de programación que cualquier buen desarrollador conoce: validar cualquier entrada del usuario contra una especificación de las entradas correctas. O sea, admitir lo que es correcto según las especificaciones del programa y rechazar cualquier otra cosa. —Usando expresiones regulares. —Es uno de los métodos más útiles, sí. —En resumen, que el XSS se evita controlando bien todas las entradas a la aplicación, validándolas según la especificación de lo que se considere una entrada correcta. —Ni más, ni menos.

La (in)seguridad del software

Hace unos meses leía en la web de Bruce Schneier un artículo en el que hablaba de la responsabilidad -o irresponsabilidad- de los generadores de software (por “generadores” me refiero a programadores, empresas de desarrollo, analistas, etc.) en la seguridad de la información. Bajo mi punto de vista, el software -en especial las aplicaciones- fallan. Fallan y mucho. Y demasiado. No únicamente desde el punto de vista de seguridad -que también-, sino incluso desde el punto de vista de la funcionalidad. Y lo peor, es que todos lo asumimos como algo habitual, como lo más normal del mundo, y como decía Schneier, incluso parcheamos nosotros mismos las aplicaciones (algo impensable con un coche, por ejemplo).

¿Por qué falla el software? Mi opinión es que en términos generales el software falla por cuatro grandes motivos; los comento, sin ningún orden particular:

La incultura de la seguridad
Muchos programadores (por programadores no me refiero únicamente a los que pican código, por supuesto) carecen de una cultura de seguridad a la hora de trabajar; simplemente no se tienen en cuenta los requisitos de seguridad de una aplicación, de un producto, ni en sus fases iniciales, ni en su implementación, ni en sus pruebas, ni en nada. El único objetivo es que funcione (hoy en día, ni siquiera que funcione rápido), que sea bonito (recuerden aquello de programa=algoritmo+marketing) y, en ocasiones, que sea tecnológicamente interesante. Poco más. ¿Seguridad? ¿Yesoqués?

El desconocimiento técnico
Incluso teniendo en cuenta la seguridad en el diseño o en la especificación de un programa, a la hora de implementarlo el desconocimiento técnico del programador hace que se cometan fallos garrafales en el código que, si no son corregidos a tiempo, acaban comprometiendo la seguridad de la información con la que tratan. No creo que valga la pena ahora hablar de errores habituales como buffer overflows o condiciones de carrera, pero alguna pregunta: ¿cuántos desarrolladores conocen el término TOCTTOU? ¿cómo se comprueban los datos que devuelve una orden del sistema? ¿qué alternativas a system() existen?

Las empresas de desarrollo
Una empresa siempre busca beneficios, y la seguridad es algo que no se ve. En ocasiones, los beneficios generados por un desarrollo seguro no se perciben desde la Dirección, por lo que en muchas empresas únicamente se busca la funcionalidad de las aplicaciones para obtener beneficios de las mismas. Dicho de otra forma, no se invierten los recursos necesarios en garantizar la calidad del software generado, únicamente se busca que la aplicación funcione y que se pueda liberar una nueva versión cuanto antes. Adicionalmente, una empresa de desarrollo no suele decir que no a nada. ¿Reprogramar la página web para poner una zona privada que enlaza con una base de datos externa? Para mañana. ¿Cifrado? Bah, no hace falta… Imaginad que necesitáramos un coche anfibio, con alas, reforzado, blindado y capaz de transportar 20 toneladas consumiendo menos de cinco litros. En un concesionario nos tomarían por locos, pero en una empresa de desarrollo nos dirían “Para mañana”. Ojo, un programa open source no suele tener la presión comercial detrás, y tampoco está libre de errores (le afectan por supuesto el resto de factores comentados aquí).

El error residual
Finalmente, incluso evitando todos los problemas anteriores, hay un porcentaje de errores que es inevitable; ese porcentaje es, a día de hoy -y de nuevo bajo mi punto de vista- demasiado alto en el desarrollo de software, y por supuesto debe reducirse a toda costa si queremos hablar de desarrollo seguro. Mientras no consigamos minimizar ese porcentaje de errores residuales, estaremos hablando de un problema serio, inimaginable en otros productos de uso masivo y diario.

¿Cómo evitar los problemas anteriores? No vamos a descubrir nada nuevo, obviamente, pero con algo tan sencillo como aplicar lo que ya sabemos, podríamos reducir, en un porcentaje muy significativo, el número de problemas de seguridad de las aplicaciones. En primer lugar, requerimos de formación e información; parece vergonzoso que en muchas facultades y escuelas de informática se hagan pocas referencias a la seguridad (si nuestra especialidad es Software, sustituyan el “pocas” por “ninguna”). Siendo así, ¿qué esperamos? Ni cultura de seguridad, ni conocimiento técnico, por supuesto. Y cuando hablamos de la dirección de la empresa, peor aún: la falta de cultura de la seguridad hace -no siempre, afortunadamente- que no se vean los beneficios que genera un desarrollo seguro. Si todos fuéramos conscientes de tales beneficios, otro gallo nos cantaría.

Finalmente, y hablando ya del error residual, creo que un factor decisivo para reducir el porcentaje de fallos es aplicar técnicas de ingeniería al desarrollo, algo que en la práctica se hace más bien poco (por mucho que en la carrera nos lo hayan explicado N veces). ¿Por qué? Eso sería seguramente material para muchos otros posts, más polémicos que este :)