El desarrollo seguro no es posible sin obedecer a unas buenas prácticas de programación, por lo que vamos a ver algunas de estas técnicas:
Añadir trazas al código: Durante el desarrollo y las pruebas del programa, utilizar asset y trazas en el código proporciona pistas sobre la ubicación y el motivo de errores que ocurren en el programa en ejecución. También proporcionan estadísticas para la ejecución. Las trazas de un programa nos ayudan durante la fase de desarrollo, también proporcionan mecanismos para medir la calidad del producto y permite un análisis cuando se produce un bug.
Usar técnica de “eliminación de código muerto” para crear versiones de depuración. Algunas variables estáticas finales deben ser usadas con trazas para marcar si son usadas o no.
Independencia de la base de datos: las aplicaciones escritas con la API JDO son independiente de la base de datos subyacente. Las implementaciones JDP soportan diferentes tipos de almacenamiento de datos incluyendo base de datos relacionales, XML, archivos planos…
Alto rendimiento: las aplicaciones delegan los detalles de la persistencia a la implementación JDO, que puede optimizar patrones de acceso a daros para un optimo rendimiento. Por ejemplo:
Public finalclassDebugConstants{
publicfinalboolean assertionEnabled = true;
publicfinalint traceLevel = 3;
}
publicclassDemo{
voidexampleMethod(){
//Codigo assert, que solo sera compilado si las constantes//DebugConstants.assertionEnabled es cierta.if (DebugConstants.assertionEnabled) {/* .... */}
//Traza de debug, que sera compilado si// DebugConstants.traceLevel es al menos de nivel 2.if (DebugConstants.traceLevel >= 2){
System.err.out("Traza Debug traceLevel 2 o superior");
}
}
}
Usando variables estáticas globales se permite generar diferentes versiones de código, simplemente cambiando los valores de las variables estáticas y recompilando el código. En la versión final, no puede contener ninguna traza, haciendo el código lo más pequeño posible y ocultado la información que puede ser valiosa para un atacante.
Objetos Mutables: Siempre que sea posible los objetos deben ser inmutables. Los objetos inmutables una vez construidos no pueden cambiar su valor. Nunca debe guardarse referencias a objetos mutables de alguna variable miembro si dicha referencia es un parámetro de un constructor público o método. Tampoco se debe devolver una referencia de objetos mutables desde métodos públicos.
Nunca se deben de utilizar variables estáticas públicas. Se deben de recompilar todas las clases si alguna variable estática final se ha cambiado.
Herencia: Siempre que sea posible hacer los métodos y clases finales. Tenga en cuenta que una clase podría ser extendida por otra. Esto puede conducir a código inestable o incluso puede abrir alguna posibilidad para que el atacante extendiendo una clase produzca algún fallo.
Cuando se implementa algunos métodos públicos, primero se deben de comprobar todas las pre-condiciones previas (datos de entrada), entonces implementar rutinas esenciales y por último comprobar las post-condiciones antes de finalizar.
Acceso a las variables y métodos: Se tienen que declarar métodos y variables privadas siempre que se pueda, ya que es una buena practica limitar el acceso lo máximo posible. Para hacer publico el valor de una variable o cambiar su valor se debe realizar por medio de los métodos Getters y Setters.
A continuación, voy a mencionar algunas prácticas específicas para Java:
Para recolectar objetos que no van a ser utilizados en el futuro, se les establece una referencia a null. Una de las principales características del lenguaje Java es el hecho de que la asignación de memoria y destrucción de esta es llevada acabo por el motor de ejecución Java. Sin embargo, el consumo de memoria se puede monitorizar por una aplicación, Si se esta preocupado por el consumo de una determinada aplicación, se deberá asignar solo la memoria que sea necesaria y dar al recolector de basura la oportunidad de liberar memoria mediante el establecimiento de referencia a objeto null.
Nunca se debe de escribir try/catch con el bloque catch vacío. Java proporciona una manera fácil para la manipulación de los errores con la clase exception, para no encontrarte con situaciones erróneas, Aunque no se esperen excepciones en un bloque try, es una buena práctica de programación segura añadir algo de código por si es un caso excepcional ocurre algo, por ejemplo, añadiendo printStackTrace. Se deben de usar bloques finally para liberar recursos que han sido reclamados en un bloque try. Si los recursos del sistema se asignan en un bloque try, se tiene que garantizar que estos recursos se liberen si se produce una excepción. Esto se hace por medio de bloques finallly.
No se deben serializar variables directamente que contienen información sensible. Cuando comienza una serialización, el objeto sale de control de JVM y puede ser vulnerable a una modificación, por lo que, si los datos son sensibles, un paso previo a la serialización es cifrar los datos. Se deben de implementar comprobaciones en el método readObject para la serialización. Este método contiene bastantes parámetros, por lo que todos deben de ser chequeados para garantizar una integridad en los datos. Se debe usar la palabra “transient” para los campos que contienen identificadores directos a los recursos. Cuando se escriben los métodos para la serialización se debe tener cuidado con no usar DataOutput o DataInput para no exponer los arrays de bytes a código malicioso.
Solo deben ser usadas con las librerías nativas. Java proporciona la interfaz de programación nativa para interoperar con aplicaciones y librerías escritas en otro lenguaje de programación. JNI puede abrir un programa que tenga vulnerabilidades escritas en otros lenguajes de programación. Las aplicaciones nativas deben ser escritas bajo ciertas directrices de programación, para el lenguaje especifico en particular. Las evaluación de estas librerías y aplicaciones se han de hacer con mucho cuidado.