Trece reglas para desarrollar aplicaciones Java seguras

La seguridad es uno de los aspectos más complejos, amplios e importantes del desarrollo de software. La seguridad del software también se pasa por alto con frecuencia o se simplifica en exceso a solo unos pocos ajustes menores al final del ciclo de desarrollo. Podemos ver los resultados en la lista anual de las principales violaciones de seguridad de datos, que en 2019 ascendieron a más de 3 mil millones de registros expuestos. Si le puede pasar a Capital One, te puede pasar a ti.

La buena noticia es que Java es una plataforma de desarrollo de larga data con muchas características de seguridad integradas. El paquete Java Security se ha sometido a pruebas de batalla intensivas y se actualiza con frecuencia para detectar nuevas vulnerabilidades de seguridad. La API de seguridad Java EE más reciente, lanzada en septiembre de 2017, aborda las vulnerabilidades en las arquitecturas de nube y microservicios. El ecosistema de Java también incluye una amplia gama de herramientas para crear perfiles y reportar problemas de seguridad. 

Pero incluso con una plataforma de desarrollo sólida, es importante mantenerse alerta. El desarrollo de aplicaciones es una tarea compleja y las vulnerabilidades pueden esconderse en el ruido de fondo. Debería pensar en la seguridad en cada etapa del desarrollo de la aplicación, desde las características del lenguaje a nivel de clase hasta la autorización del punto final de la API.

Las siguientes reglas básicas ofrecen una buena base para crear aplicaciones Java más seguras.

Regla de seguridad de Java n. ° 1: escriba código Java limpio y sólido

A las vulnerabilidades les encanta esconderse en la complejidad, así que mantenga su código lo más simple posible sin sacrificar la funcionalidad. El uso de principios de diseño probados como DRY (no lo repitas) te ayudará a escribir un código que sea más fácil de revisar en busca de problemas.  

Exponga siempre la menor cantidad de información posible en su código. La ocultación de los detalles de la implementación admite un código que se puede mantener y es seguro. Estos tres consejos ayudarán en gran medida a escribir código Java seguro:

  • Haga un buen uso de los modificadores de acceso de Java . Saber cómo declarar diferentes niveles de acceso para clases, métodos y sus atributos contribuirá en gran medida a proteger su código. Todo lo que pueda hacerse privado debe serlo. 
  • Evite la reflexión y la introspección . Hay algunos casos en los que se merecen estas técnicas avanzadas, pero en su mayor parte debes evitarlas. El uso de la reflexión elimina la escritura fuerte, que puede introducir puntos débiles e inestabilidad en su código. La comparación de nombres de clases como cadenas es propensa a errores y puede conducir fácilmente a una colisión de espacios de nombres.
  • Defina siempre las superficies de interfaz y API más pequeñas posibles . Desacople los componentes y haga que interactúen en el área más pequeña posible. Incluso si un área de su aplicación está infectada por una infracción, otras estarán seguras. 

Regla de seguridad de Java n. ° 2: evitar la serialización

Esta es otra sugerencia de codificación, pero es lo suficientemente importante como para ser una regla propia. La serialización toma una entrada remota y la transforma en un objeto completamente dotado. Prescinde de constructores y modificadores de acceso, y permite que un flujo de datos desconocidos se convierta en código en ejecución en la JVM. Como resultado, la serialización de Java es profunda e inherentemente insegura.

El fin de la serialización de Java

Si no se ha enterado, Oracle tiene planes a largo plazo para eliminar la serialización de Java. Mark Reinhold, arquitecto jefe del grupo de plataformas Java de Oracle, ha dicho que cree que un tercio o más de todas las vulnerabilidades de Java implican la serialización.

En la medida de lo posible, evite la serialización / deserialización en su código Java. En su lugar, considere usar un formato de serialización como JSON o YAML. Nunca, nunca exponga un extremo de red desprotegido que reciba y actúe sobre un flujo de serialización. Esto no es más que una alfombra de bienvenida para el caos.

Regla de seguridad de Java n. ° 3: nunca exponga credenciales no cifradas o PII

Es difícil de creer, pero este error evitable causa dolor año tras año.

Cuando un usuario ingresa una contraseña en el navegador, se envía como texto sin formato a su servidor. Esa debería ser la última vez que vea la luz del día. Usted debe cifrar la contraseña a través de un cifrado unidireccional antes de que persiste a la base de datos, y luego hacerlo de nuevo cada vez que la comparación contra ese valor.

Las reglas para las contraseñas se aplican a toda la información de identificación personal (PII): tarjetas de crédito, números de seguro social, etc. Cualquier información personal confiada a su solicitud debe tratarse con el más alto nivel de cuidado.

Las credenciales no cifradas o PII en una base de datos son un enorme agujero de seguridad, a la espera de que un atacante lo descubra. Asimismo, nunca escriba credenciales sin procesar en un registro ni las transmita a un archivo o red. En su lugar, cree un hash salado para sus contraseñas. Asegúrese de investigar y utilizar un algoritmo hash recomendado.

Saltando a la Regla # 4: siempre use una biblioteca para el cifrado; no enrolle el suyo.

Regla de seguridad de Java n. ° 4: use bibliotecas conocidas y probadas

Deleite sus ojos con esta pregunta y respuesta sobre cómo implementar su propio algoritmo de seguridad. La lección tl; dr es: use bibliotecas y marcos conocidos y confiables siempre que sea posible. Esto se aplica en todo el espectro, desde el hash de contraseñas hasta la autorización de la API REST.

Afortunadamente, Java y su ecosistema te respaldan aquí. Para la seguridad de las aplicaciones, Spring Security es el estándar de facto. Ofrece una amplia gama de opciones y la flexibilidad de adaptarse a cualquier arquitectura de aplicación, e incorpora una variedad de enfoques de seguridad.

Su primer instinto al abordar la seguridad debe ser investigar. Investigue las mejores prácticas y luego investigue qué biblioteca implementará esas prácticas para usted. Por ejemplo, si está considerando usar JSON Web Tokens para administrar la autenticación y la autorización, mire la biblioteca de Java que encapsula JWT y luego aprenda cómo integrar eso en Spring Security.

Incluso usando una herramienta confiable, es bastante fácil estropear la autorización y autenticación. Asegúrese de moverse despacio y vuelva a verificar todo lo que hace.

Regla de seguridad de Java n. ° 5: Sea paranoico con las entradas externas

Ya sea que provenga de un usuario que escribe en un formulario, un almacén de datos o una API remota, nunca confíe en la entrada externa.

La inyección de SQL y las secuencias de comandos entre sitios (XSS) son solo los ataques más comúnmente conocidos que pueden resultar de un mal manejo de la entrada externa. Un ejemplo menos conocido, uno de muchos, es el "ataque de mil millones de risas", mediante el cual la expansión de entidades XML puede provocar un ataque de denegación de servicio.

Cada vez que reciba una entrada, debe verificar su cordura y desinfectarla. Esto es especialmente cierto para cualquier cosa que pueda presentarse a otra herramienta o sistema para su procesamiento. Por ejemplo, si algo pudiera terminar como un argumento para una línea de comandos del sistema operativo: ¡cuidado!

Una instancia especial y conocida es la inyección SQL, que se trata en la siguiente regla.

Regla de seguridad de Java n. ° 6: utilice siempre declaraciones preparadas para manejar parámetros SQL

Cada vez que crea una declaración SQL, corre el riesgo de interpolar un fragmento de código ejecutable.

Sabiendo esto, es una buena práctica usar siempre la clase java.sql.PreparedStatement para crear SQL. Existen instalaciones similares para tiendas NoSQL como MongoDB. Si está usando una capa ORM, la implementación usará PreparedStatements para usted debajo del capó.

Regla de seguridad de Java n. ° 7: no revele la implementación a través de mensajes de error

Los mensajes de error en producción pueden ser una fuente fértil de información para los atacantes. Los seguimientos de pila, especialmente, pueden revelar información sobre la tecnología que está usando y cómo la está usando. Evite revelar seguimientos de pila a los usuarios finales.

Las alertas de inicio de sesión fallido también se incluyen en esta categoría. En general, se acepta que un mensaje de error debe aparecer como "Error de inicio de sesión" frente a "No se encontró ese usuario" o "Contraseña incorrecta". Ofrezca la menor ayuda posible a los usuarios potencialmente nefastos.

Idealmente, los mensajes de error no deberían revelar la pila de tecnología subyacente para su aplicación. Mantenga esa información lo más opaca posible.

Regla de seguridad de Java n. ° 8: mantenga las versiones de seguridad actualizadas

A partir de 2019, Oracle implementó un nuevo esquema de licencias y un calendario de lanzamiento para Java. Desafortunadamente para los desarrolladores, la nueva cadencia de lanzamiento no facilita las cosas. No obstante, usted es responsable de verificar con frecuencia las actualizaciones de seguridad y aplicarlas a su JRE y JDK.

Asegúrese de saber qué parches críticos están disponibles revisando regularmente la página de inicio de Oracle para obtener alertas de seguridad. Cada trimestre, Oracle ofrece una actualización de parche automatizada para la versión LTS (soporte a largo plazo) actual de Java. El problema es que ese parche solo está disponible si está pagando por una licencia de soporte de Java.

Si su organización está pagando por dicha licencia, siga la ruta de actualización automática. Si no es así, probablemente estés usando OpenJDK y tendrás que hacer el parche tú mismo. En este caso, puede aplicar el parche binario, o simplemente puede reemplazar su instalación de OpenJDK existente con la última versión. Alternativamente, puede utilizar un OpenJDK con soporte comercial como Azul's Zulu Enterprise.

¿Necesita todos los parches de seguridad?

Si observa atentamente las alertas de seguridad, es posible que descubra que no necesita un conjunto determinado de actualizaciones. Por ejemplo, la versión de enero de 2020 parece ser una actualización crítica de Java; sin embargo, una lectura detallada muestra que la actualización solo corrige los agujeros en la seguridad del subprograma Java y no afecta a los servidores Java.

Regla de seguridad de Java n. ° 9: busque vulnerabilidades de dependencia

Hay muchas herramientas disponibles para escanear automáticamente su base de código y dependencias en busca de vulnerabilidades. Todo lo que tienes que hacer es usarlos.

OWASP, Open Web Application Security Project, es una organización dedicada a mejorar la seguridad del código. La lista de OWASP de herramientas confiables de escaneo de código automatizado de alta calidad incluye varias herramientas orientadas a Java.

Verifique su base de código con regularidad, pero también esté atento a las dependencias de terceros. Los atacantes se dirigen a bibliotecas de código abierto y cerrado. Esté atento a las actualizaciones de sus dependencias y actualice su sistema a medida que se lanzan nuevas correcciones de seguridad.

Regla de seguridad de Java n. ° 10: supervisar y registrar la actividad del usuario

Incluso un simple ataque de fuerza bruta puede tener éxito si no supervisa activamente su aplicación. Utilice herramientas de seguimiento y registro para vigilar el estado de la aplicación.

Si desea estar convencido de por qué la supervisión es importante, simplemente siéntese y observe los paquetes TCP en el puerto de escucha de sus aplicaciones. Verá todo tipo de actividad, mucho más allá de las simples interacciones del usuario. Parte de esa actividad serán los robots y los malhechores que buscan vulnerabilidades.

Debe estar registrando y monitoreando los intentos fallidos de inicio de sesión y desplegando contramedidas para evitar que los clientes remotos ataquen con impunidad.

El monitoreo puede alertarlo sobre picos inexplicables, y el registro puede ayudar a desentrañar qué salió mal después de un ataque. El ecosistema de Java incluye una gran cantidad de soluciones comerciales y de código abierto para el registro y la supervisión.

Regla de seguridad de Java n. ° 11: tenga cuidado con los ataques de denegación de servicio (DoS)

Siempre que esté procesando recursos potencialmente costosos o realizando operaciones potencialmente costosas, debe protegerse contra el uso descontrolado de los recursos.

Oracle mantiene una lista de posibles vectores para este tipo de problema en su documento de Pautas de codificación segura para Java SE, bajo el título "Denegación de servicio".

Básicamente, siempre que vaya a realizar una operación costosa, como descomprimir un archivo comprimido, debe monitorear el uso explosivo de recursos. No confíe en los manifiestos de archivos. Confíe solo en el consumo real en el disco o en la memoria, controle y evite los excesos de poner el servidor de rodillas.

De manera similar, en algunos procesos es importante estar atento a los bucles permanentes inesperados. Si un bucle es sospechoso, agregue un protector que garantice que el bucle está progresando y cortocircuite si parece que se ha vuelto zombi.

Regla de seguridad de Java n. ° 12: considere usar el administrador de seguridad de Java

Java tiene un administrador de seguridad que se puede utilizar para restringir los recursos a los que tiene acceso un proceso en ejecución. Puede aislar el programa con respecto al acceso a disco, memoria, red y JVM. Al reducir estos requisitos para su aplicación, se reduce la huella de posibles daños de un ataque. Dicho aislamiento también puede ser un inconveniente, por SecurityManagerlo que no está habilitado de forma predeterminada.

Tendrá que decidir por sí mismo si SecurityManagervale la pena aplicar una capa adicional de protección a sus aplicaciones para trabajar con opiniones sólidas. Consulte los documentos de Oracle para obtener más información sobre la sintaxis y las capacidades del administrador de seguridad de Java.

Regla de seguridad de Java n. ° 13: considere usar un servicio de autenticación en la nube externo

Algunas aplicaciones simplemente deben poseer sus datos de usuario; por lo demás, un proveedor de servicios en la nube podría tener sentido.

Busque y encontrará una variedad de proveedores de autenticación en la nube. El beneficio de dicho servicio es que el proveedor es responsable de proteger los datos confidenciales del usuario, no usted. Por otro lado, agregar un servicio de autenticación aumenta la complejidad de la arquitectura de su empresa. Algunas soluciones, como la autenticación FireBase, incluyen SDK para integrarse en toda la pila.

Conclusión

He presentado 13 reglas para desarrollar aplicaciones Java más seguras. Estas reglas están probadas y son verdaderas, pero la regla más importante de todas es la siguiente: sospeche. Aborde siempre el desarrollo de software con cautela y una perspectiva de seguridad. Busque vulnerabilidades en su código, aproveche las API y los paquetes de seguridad de Java y utilice herramientas de terceros para monitorear y registrar su código en busca de problemas de seguridad.

Aquí hay tres buenos recursos de alto nivel para mantenerse al tanto del panorama de seguridad de Java en constante cambio:

  • Top 10 de OWASP
  • CWE Top 25
  • Directrices de código seguro de Oracle

Esta historia, "Trece reglas para desarrollar aplicaciones Java seguras" fue publicada originalmente por JavaWorld.