Vulnerabilidades en el código. ¿Cómo se puede distinguir un defecto peligroso de un error menor?

¿Cómo suele ser comprobar el código de la aplicación en busca de vulnerabilidades? El especialista en seguridad inicia el procedimiento, se escanea el código y se descubren miles de vulnerabilidades en la aplicación. Todos, tanto el encargado de seguridad como los desarrolladores, están conmocionados. La reacción natural del desarrollador: "¡Sí, seguramente la mitad son falsos positivos y las otras vulnerabilidades no críticas!"



En cuanto a los falsos positivos, todo es simple aquí: puede tomar y mirar directamente aquellos lugares del código donde se descubrieron vulnerabilidades con sospecha de falso positivo. De hecho, algunos de ellos pueden resultar falsos positivos (aunque obviamente no son la mitad del total).



Pero sobre lo que es crítico y lo que no lo es, me gustaría hablar de manera más sustantiva. Si comprende por qué ya no es posible utilizar SHA-1 y por qué escapar ";", tal vez este artículo no le abra algo nuevo. Pero si los resultados del análisis de las vulnerabilidades encontradas deslumbran, bienvenido debajo del corte: le diremos qué "agujeros" se encuentran con mayor frecuencia en las aplicaciones móviles y web, cómo funcionan, cómo solucionarlos y, lo más importante, cómo comprender lo que está frente a usted. - un agujero peligroso o un error menor en el código.







Implementación



Bueno, un tipo de vulnerabilidad tan común. Están incrustados en todas partes: en consultas SQL, LDAP, XML, XPath, XSLT, Xquery ... Todas estas inyecciones se distinguen por el uso de datos no confiables, gracias a los cuales un atacante obtiene acceso a información o cambia el comportamiento de la aplicación. Por ejemplo, con una entrada del usuario que no está suficientemente validada.



Según la clasificación internacional de vulnerabilidades OWASP , los ataques que utilizan el método de "inyección" ocupan el primer lugar en el nivel de criticidad de las amenazas a la seguridad de las aplicaciones web. Consideremos los tipos de implementaciones más típicas.



Inyección SQL . Los datos que no son de confianza ingresan en la consulta SQL a la base de datos.







Si la consulta a la base de datos no implementa la autenticación correcta de los datos de entrada, un atacante puede dañar la consulta SQL:



  • enviarle código malicioso;
  • agregue el símbolo "-" o ";" y terminar el comando SQL correcto: todo después del "-" se interpreta como un comentario y el carácter ";" marca el final de un comando;
  • adivine la contraseña ejecutando secuencialmente una serie de consultas SQL.


¿Cómo defenderse? Aquí hay algunas recomendaciones de OWASP :



  • Utilice una API que proporcione una interfaz parametrizada o herramientas de mapeo relacional de objetos (ORM).
  • Implemente un mecanismo de validación para los datos ingresados ​​por el usuario. Utilice una lista blanca de validación del lado del servidor.
  • Caracteres especiales de escape (";", "-", "/ *", "* /", "'"; la lista exacta depende de la base de datos).
  • Utilice procedimientos almacenados junto con un mecanismo de filtrado de sus parámetros para validar la entrada del usuario.


Inyección XML . Las aplicaciones usan XML para almacenar o intercambiar datos, por lo que pueden contener información valiosa.







Si un atacante puede escribir datos en un documento XML, entonces puede cambiar su semántica. En este caso, el escenario más inofensivo le permitirá inyectar etiquetas adicionales en el documento, como resultado de lo cual el analizador XML se cerrará con un error. Pero puedes enfrentarte a una incidencia más grave: por ejemplo, con la sustitución de datos de autenticación en la base de clientes o el precio en la base de datos de productos de la tienda. La inyección de XML también puede dar lugar a secuencias de comandos entre sitios (XSS), la inyección de código malicioso que se ejecuta en el navegador del usuario cuando se abre la página.



¿Qué podemos aconsejar?



  • No cree etiquetas y atributos cuyos nombres se deriven de datos de una fuente no confiable (por ejemplo, ingresados ​​por un usuario).
  • Codifique (codificación de entidad XML) los datos ingresados ​​por el usuario antes de escribirlos en un documento XML.


La inyección XQuery es una forma de inyección SQL clásica, pero en este caso el ataque se dirigirá a la base de datos XML y los datos que no sean de confianza terminarán en la expresión XQuery.



En el siguiente ejemplo, la aplicación crea y ejecuta una expresión XQuery basada en parámetros usernamey passworddesde una solicitud HTTP (fuente no confiable):



XQDataSource xqs = new XQDataSource();
XQConnection conn = xqs.getConnection();
String query = "for \$user in doc(users.xml)//user[username='" + request.getParameter("username") + "'and pass='" + request.getParameter("password") + "'] return \$user";
XQPreparedExpression xqpe = conn.prepareExpression(query);
XQResultSequence rs = xqpe.executeQuery();


Si los datos son correctos, la solicitud devolverá información sobre el usuario con el nombre y contraseña adecuados:



for \$user in doc(users.xml)//user[username='test_user' and pass='pass123'] return \$user


Si un atacante especifica una cadena que contiene caracteres especiales (por ejemplo, admin' or 1=1 or ''=') como parámetro , la semántica de la solicitud cambiará:



//user[username='admin']


La solicitud recibida devolverá datos sobre todos los usuarios.



Opción segura (usos prepared statements):



XQDataSource xqs = new XQDataSource();
XQConnection conn = xqs.getConnection();
String query = "declare variable $username as xs:string external; declare variable $password as xs:string external; for \$user in doc(users.xml)//user[username='$username' and pass='$password'] return \$user";
XQPreparedExpression xqpe = conn.prepareExpression(query);
xqpe.bindString(new QName("username"), request.getParameter("username"), null);
xqpe.bindString(new QName("password"), request.getParameter("password"), null);
XQResultSequence rs = xqpe.executeQuery();


La incrustación en XSLT (XML Document Transformation Language) es posible si la aplicación utiliza datos de una fuente que no es de confianza cuando trabaja con XSL.



Las aplicaciones utilizan XSL para transformar documentos XML. Los archivos de estilo XSL contienen funciones que describen la transformación y, si no se implementan correctamente, pueden incluir vulnerabilidades. Esto aumenta el riesgo de escenarios de ataque en los que un atacante cambia la estructura y el contenido del archivo de estilo XSL y, por lo tanto, el archivo XML correspondiente. ¿Qué podemos conseguir a la salida?



Primero, un ataque XSS: inyectar código malicioso en una página emitida por un sistema web e interactuar con este código con el servidor del atacante. En segundo lugar, el pirata informático obtiene acceso a los recursos del sistema. En tercer lugar, la ejecución de código arbitrario. Y de postre - Ataque XXE (XML eXternal Entity - inyección de una entidad externa en XML).



La incorporación del protocolo ligero de acceso a directorios ( LDAP) en los comandos puede provocar la pérdida o modificación de datos. En este caso, los datos que no son de confianza ingresan a la solicitud LDAP.



Inyección de un comando de intérprete malicioso.Los datos que no son de confianza van al comando del intérprete. Un atacante puede elegir dicha entrada para que el comando se ejecute con éxito y los permisos adicionales en la aplicación estén disponibles para él.



En el siguiente ejemplo, la aplicación ejecuta un script para crear una copia de seguridad de la base de datos. La aplicación toma el tipo de copia de seguridad como parámetro y ejecuta el script con privilegios elevados:



String btype = request.getParameter("backuptype");
String cmd = new String("cmd.exe /K
\"c:\\util\\rmanDB.bat "+btype+"&&c:\\utl\\cleanup.bat\"")
System.Runtime.getRuntime().exec(cmd);


El problema aquí es que el parámetro backuptypeno está validado. Por Runtime.exec()lo general , no ejecuta varios comandos, pero en este caso cmd.exe se inicia primero para ejecutar varios comandos invocando Runtime.exec(). Una vez que se inicia el shell de la línea de comandos, puede ejecutar varios comandos, separados por caracteres " &&". Si un atacante && del c:\\dbms\\*.*especifica la cadena " " como parámetro , la aplicación eliminará el directorio especificado.



Consejos para desarrolladores:



  • No permita que los usuarios controlen directamente los comandos que ejecuta la aplicación. Si el comportamiento de la aplicación debe depender de los datos ingresados ​​por el usuario, ofrezca al usuario una opción de una determinada lista de comandos permitidos.
  • , . , . , .
  • , , . . .


Carga de archivos insegura. En este caso, no solo los datos individuales provienen de una fuente no confiable, sino todo el archivo. Por lo tanto, un atacante puede cargar datos o códigos maliciosos en el servidor de destino. Por ejemplo, si los usuarios de una red corporativa pueden cargar archivos en directorios de acceso público, un pirata informático puede ejecutar de forma remota un código malicioso en el servidor de la empresa.



Inclusión insegura de archivo externo en HTML.Las vulnerabilidades de inclusión de archivos ocurren cuando el usuario ingresa la ruta a un archivo incluido. El hecho es que los lenguajes de secuencias de comandos modernos le permiten vincular dinámicamente código de archivos de terceros para reutilizarlo. Este mecanismo se utiliza para una apariencia uniforme de las páginas o para dividir el código en pequeños módulos. Sin embargo, un atacante puede aprovechar esta inclusión cambiando la ruta y conectando su archivo.



Recomendamos que los profesionales de seguridad de la información corporativa creen una "lista blanca" de rutas de conexión de archivos válidas para que los empleados puedan agregar archivos solo de acuerdo con los scripts de esta lista.



Marcadores



Los marcadores son partes que se introducen intencionalmente en el código de la aplicación, con la ayuda de las cuales, bajo ciertas condiciones, puede realizar acciones no incluidas en la aplicación. Consideremos los tipos de marcadores más comunes.



Cuentas especiales. Si la aplicación compara el valor de una contraseña o variable de inicio de sesión con un valor sin cambios, tenga cuidado: esta cuenta puede ser parte de un marcador. Veamos cómo sucede esto.







El desarrollador de la aplicación utiliza una cuenta especial (posiblemente con privilegios elevados) al depurar y deja las secciones correspondientes del código en la versión final, conservando el acceso a la aplicación. Un atacante puede restaurar el código original de la aplicación, extraer los valores constantes de la cuenta especial y obtener acceso a la aplicación.

Es categóricamente imposible almacenar inicios de sesión, contraseñas, claves en el código fuente de la aplicación.
Funcionalidad oculta (NDV). El código de funcionalidad oculta se ejecuta cuando se activa un determinado disparador. En las aplicaciones web, el disparador suele ser un parámetro de consulta "invisible". En ocasiones, además, se comprueba de qué IP procede la petición con el disparador, de forma que solo su autor pueda activar el marcador. Estos controles sirven como una señal para posibles marcadores.



Actividad de red indocumentada. Este tipo de actividad incluye: conectarse a recursos de terceros en segundo plano, escuchar en puertos no documentados, transferir información a través de SMTP, HTTP, UDP, ICMP.

Si encuentra una conexión sospechosa en el código con una dirección que no está en la lista de direcciones seguras conocidas, le recomendamos encarecidamente que la elimine.

Cambie la configuración de seguridad . La aplicación contiene código que cambia el valor de la variable que almacena el éxito de la autenticación. Un error común es usar asignación (=) en lugar de comparación (==). En los métodos que involucran autenticación, es especialmente peligroso porque puede ser parte de una puerta trasera:



if (isAuthenticated = true)
{
    someDangerousAction();
}


Disparador de tiempo (bomba de tiempo). Un marcador que se activa en un momento específico. La aplicación compara la fecha actual con un año, mes y día específicos: el 1 de enero de 2021, una sorpresa espera a todos:



Date now = java.util.Date();    // current time
if ((now.getYear() == 2021) && (now.getMonth() == 1) && (now.getDate() == 1))
{
    activateNewYearBackdoor();
}


O tal vez no ... En la práctica, cuando se buscan desencadenantes temporales, a menudo se producen falsos positivos. Por ejemplo, si la API de tiempo se utiliza para su propósito previsto: registro, cálculo del tiempo de ejecución, marcas de tiempo para las respuestas del servidor a las solicitudes HTTP.



¡Pero! Aún así, recomendamos no cerrar los ojos a todas estas alarmas, ya que conocemos ejemplos reales de tales vulnerabilidades.



Código muerto. Piezas de código inyectado que no hacen nada útil. El código muerto en sí mismo no es peligroso, pero puede ser parte de un marcador que se ha distribuido en varios archivos. O bien, se planea implementar el activador de marcadores más adelante. En cualquier caso, el código muerto debería ser sospechoso.



Falta de cifrado y uso de algoritmos de cifrado débiles



Los principales problemas con el cifrado son que no se utiliza en absoluto o se utilizan algoritmos débiles, y las claves y la sal son demasiado simples o se almacenan de forma insegura. La consecuencia de todas estas vulnerabilidades es la misma: es más fácil robar datos confidenciales.



El ejemplo muestra la inicialización del cifrado utilizando el algoritmo DES heredado:



Cipher cipher = Cipher.getInstance("DES");


Ejemplos de algoritmos de cifrado vulnerables: RC2, RC4, DES. Opción segura:



Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");


Según la clasificación internacional de OWASP , las vulnerabilidades como la “fuga de datos confidenciales” ocupan el tercer lugar en términos de la gravedad de las amenazas a la seguridad de las aplicaciones web.



Nuestra recomendación para los desarrolladores: asegúrese de utilizar el cifrado teniendo en cuenta la seguridad.



El uso del protocolo HTTP inseguro en lugar de HTTPS está plagado de un ataque de hombre en el medio.



El protocolo seguro HTTPS se basa en HTTP, pero también admite el cifrado a través de los protocolos criptográficos SSL / TLS. HTTPS encripta todos los datos transmitidos a través de él, en particular, las páginas de ingreso y entrada de contraseña o los datos de la tarjeta bancaria del usuario, protegiéndolos del acceso no autorizado y cambios. A diferencia de HTTP, que no protege los datos transmitidos. Como resultado, un atacante puede falsificar un sitio web informativo a través de HTTP y obligar al usuario a ingresar datos en una página falsa (ataque de phishing).



La clave de cifrado se especifica en el código fuente . Como resultado, dichas claves están disponibles para todos los desarrolladores de aplicaciones. Además, después de instalar la aplicación, solo puede eliminar la clave del código mediante una actualización.



En general, las cadenas de constantes se extraen fácilmente de un archivo ejecutable utilizando un programa de recuperación de código fuente (descompilador). Por lo tanto, un atacante no necesita tener acceso al código fuente para averiguar el valor de la clave que se está utilizando. En nuestra práctica, a menudo nos encontramos con casos en los que los desarrolladores especifican nulluna cadena vacía como valor clave , lo cual es simplemente inaceptable.



Nuestro consejo: Genere claves con generadores de números pseudoaleatorios (PRNG) criptográficamente fuertes y almacénelos usando módulos especiales.



Algoritmo de relleno inseguro para cifrado . Si se utiliza el algoritmo de cifrado RSA sin el relleno OAEP, los datos cifrados se vuelven vulnerables .



Se necesita el algoritmo OAEP para procesar mensajes antes de usar RSA. El mensaje se rellena primero a una longitud fija mediante OAEP y luego se cifra mediante RSA. Este esquema de cifrado se denomina RSA-OAEP y es parte del estándar actual .



Este es un ejemplo de cómo inicializar el cifrado RSA sin relleno:



rsa = javax.crypto.Cipher.getInstance("RSA/NONE/NoPadding");


Opción segura:



rsa = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");


Tamaño de clave de cifrado insuficiente . Si usa una clave corta, este cifrado es vulnerable a los ataques de fuerza bruta.



El criptoanálisis no se detiene, constantemente surgen nuevos algoritmos de ataque, las computadoras están ganando mayor poder. La configuración de cifrado que antes se consideraba segura está obsoleta y ya no se recomienda su uso. Por lo tanto, RSA con una longitud de clave de 1024 bits ya no se consideraba seguro en 2010-2015.



Algoritmo de hash débil . Por las razones descritas en el párrafo anterior, las funciones hash MD2, MD5, SHA1 son inseguras. No se requieren recursos importantes para encontrar colisiones para las funciones MD2 y MD5.



Para SHA1, hay ejemplos de dos archivos diferentes con los mismos hashes. Algoritmo de piratería sugeridoempleados de Google y del Centro de Matemáticas e Informática de Ámsterdam.







Si las contraseñas de los usuarios se almacenan como hashes, pero utilizando una función hash insegura, un atacante podría obtener acceso fácilmente a ellas implementando el siguiente escenario. Conociendo el hash de la contraseña y explotando la vulnerabilidad del algoritmo de hash, es posible calcular una cadena para la que el hash es el mismo que para la contraseña. El atacante se autentica utilizando la cadena calculada.



La función hash para almacenar contraseñas debe ser resistente a colisiones y no demasiado rápida para que no se pueda implementar un ataque de fuerza bruta. Deben utilizarse los algoritmos seguros PBKDF2, bcrypt, scrypt.



Algunos números interesantes: con PBKDF2la velocidad de búsqueda de claves se redujo a 70 piezas por segundo para Intel Core2 y alrededor de 1 mil para FPGA Virtex-4 FX60. En comparación, las funciones clásicas de hash de contraseña de LANMAN tienen una velocidad de búsqueda de alrededor de cientos de millones de opciones por segundo.



Algoritmo de cifrado débil . Al igual que con los algoritmos de hash, la seguridad de un algoritmo de cifrado está determinada por el tiempo y los recursos que se tendrán que gastar en descifrarlo. RC2, RC4, DES se consideran algoritmos vulnerables. Este último, debido a la pequeña longitud de la clave (56 bits), se puede descifrar mediante la fuerza bruta.



Un generador de números pseudoaleatorios débil (PRNG) genera secuencias predecibles. Un hacker puede eludir la autenticación y secuestrar la sesión de un usuario.



Profundicemos un poco más en la naturaleza de los PRNG. Generan cadenas de números en función del valor inicial del parámetro seed. Hay dos tipos de PRNG: estadístico y criptográfico.



Los PRNG estadísticos generan secuencias predecibles que son estadísticamente similares a las aleatorias. No se pueden utilizar con fines de seguridad.



El resultado de la operación de los PRNG criptográficos, por el contrario, no se puede predecir si el valor del parámetro se seedobtiene de una fuente con alta entropía. El valor de tiempo actual tiene poca entropía y tampoco es seguro en calidad seed. En Java, los PRNG de clases java.util.Randomy java.lang.Mathgeneran secuencias predecibles y no deben utilizarse con fines de seguridad de la información.



Semilla débil de un generador de números pseudoaleatorios . No es seedseguro utilizar un valor de una fuente que no es de confianza, ya que genera una secuencia predecible.



El trabajo de muchos algoritmos criptográficos se basa en el uso de un PRNG resistente al criptoanálisis. Algunos algoritmos pueden tomar un valor como argumento adicional seedy generar una secuencia predecible para cada valor de este parámetro. En este caso, la seguridad del sistema se basa en el supuesto de que los valores seedserán impredecibles.



La sal se especifica en el código fuente.... Recordemos para qué sirve la sal. Para descifrar una contraseña mediante el método de fuerza bruta, se utilizan tablas precompiladas con valores de funciones hash de contraseñas populares. Salt es una cadena arbitraria que se alimenta a la entrada de la función hash junto con la contraseña para dificultar dicho ataque.



Si la sal se almacena en el código fuente, surgen exactamente los mismos problemas que con las contraseñas y claves. El valor de la sal está disponible para los desarrolladores y los atacantes pueden obtenerlo fácilmente, y la sal se puede eliminar de la versión final de la aplicación solo con la próxima actualización de la aplicación.



Manipulación con registros



Varios errores en los registros están plagados de la introducción de código malicioso en las aplicaciones. Las vulnerabilidades más comunes asociadas con el registro son la manipulación de archivos de registro y el registro no estructurado.



La manipulación del archivo de registro se produce cuando una aplicación escribe datos que no son de confianza en el registro de eventos (registro). Un pirata informático puede falsificar entradas de registro o inyectar códigos maliciosos en ellas.



Normalmente, las aplicaciones escriben el historial de transacciones en el registro para su posterior procesamiento, depuración o recopilación de estadísticas. Los registros se pueden analizar de forma manual o automática.

Si los datos se escriben en el registro "tal cual", un atacante puede inyectar registros falsos en el registro, violar la estructura del archivo y hacer que el procesador de registros falle o inyectar código malicioso que explote vulnerabilidades conocidas en el procesador.



En este ejemplo, una aplicación web intenta leer un valor entero de un parámetro de solicitud. Si el valor ingresado no se pudo convertir a un número entero, la aplicación registra este valor junto con un mensaje de error:



String val = request.getParameter("val");
try {
    int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
    log.info("Failed to parse val = " + val);
}


Un atacante puede agregar una entrada arbitraria al registro, por ejemplo, la línea twenty-one%0a%0aINFO:+User+logged+out%3dbadguyse reflejará en el registro de la siguiente manera:



INFO: Failed to parse val=twenty-one
INFO: User logged out=badguy


De manera similar, se pueden incrustar registros arbitrarios en el registro.



Opción segura (usos NumberFormatException):



public static final String NFE = "Failed to parse val. The input is required to be an integer value."

String val = request.getParameter("val");
try {
    int value = Integer.parseInt(val);
}
catch (NumberFormatException nfe) {
    log.info(NFE);
}


El registro no estructurado , es decir, la salida de mensajes de error a las secuencias estándar de salida o error, es un método inseguro. En su lugar, se recomienda utilizar el registro estructurado. Este último le permite generar un registro con niveles, marcas de tiempo y formato estándar. Si el programa implementa un mecanismo de registro estructurado, pero los mensajes de error se envían a secuencias estándar, es posible que el registro no contenga información crítica.

La salida de mensajes de error a secuencias estándar es aceptable solo en las primeras etapas de desarrollo.



Manejo inseguro de cookies



Las vulnerabilidades asociadas con la recopilación de cookies de usuario son muy diversas.



Manejo inseguro de cookies . La aplicación incluye datos de una fuente que no es de confianza en la cookie, lo que puede provocar envenenamiento de caché, XSS (cross-site scripting) y ataques de división de respuesta.



Si se inyecta código malicioso (secuencias de comandos entre sitios) en una aplicación, un atacante puede modificar la cookie del usuario.



Debido a que las cookies se configuran en el encabezado de respuesta HTTP, la falta de reconocimiento de los datos incluidos en la cookie puede provocar un ataque de respuesta dividida. La "división de respuesta HTTP" es un ataque en el que un pirata informático envía una solicitud HTTP, cuya respuesta será aceptada por la víctima en dos respuestas HTTP a la vez (en lugar de la correcta).

Si el atacante especifica una authorcadena del formulario como parámetro Hacker \r\nHTTP/1.1 200 OK\r\n..., la respuesta se dividirá en dos de la siguiente manera:



HTTP/1.1 200 OK
...
Set-Cookie: author=Hacker

HTTP/1.1 200 OK
...


El contenido de la segunda respuesta está completamente bajo el control del atacante, lo que resulta en envenenamiento de caché, XSS, redireccionamientos maliciosos y otros ataques.



Cookies sin HttpOnly . La aplicación crea cookies sin bandera httpOnly. Si se httpOnlyincluye en el encabezado de la respuesta http, un atacante no podría obtener cookies utilizando código JavaScript. Y si un usuario abre una página con una vulnerabilidad de secuencia de comandos entre sitios (XSS), el navegador no revelará cookies a terceros. Si la bandera httpOnlyno está configurada, las cookies (generalmente cookies de sesión) se pueden robar usando un script.



Un ejemplo de creación de una cookie sin bandera httpOnly:



Cookie cookie = new Cookie("emailCookie", email);
response.addCookie(cookie);


Establezca la bandera httpOnlyal crear cookies. Sin embargo, httpOnlytenga en cuenta que hay formas de evitar los ataques, por lo que también debe encargarse de validar cuidadosamente la entrada.



Nota: Según la clasificación internacional de OWASP , las vulnerabilidades de "fuga de datos confidenciales" ocupan el tercer lugar en el nivel de criticidad de las amenazas a la seguridad de las aplicaciones web.



Cookies para un dominio demasiado general . Si el dominio de las cookies es demasiado general (por ejemplo .example.com), una vulnerabilidad en una aplicación expone a otras aplicaciones del mismo dominio a vulnerabilidades.



En el siguiente ejemplo, una aplicación web segura instalada en una dirección http://secure.example.comestablece una cookie con un valor de dominio .example.com:



Cookie cookie = new Cookie("sessionID", sessionID);
cookie.setDomain(".example.com");


Si http://insecure.example.comuna aplicación que contiene, por ejemplo, XSS está instalada en la dirección , entonces las cookies del usuario autorizado de la aplicación segura que fue a la dirección http://insecure.example.compueden verse comprometidas.



Un atacante también puede llevar a cabo un ataque de envenenamiento de cookies: las cookies con un dominio compartido creado http://insecure.example.comsobrescribirán la cookie http://secure.example.com.



Opción segura:



Cookie cookie = new Cookie("sessionID", sessionID);
cookie.setDomain("secure.example.com");


Cookies con parámetro demasiado generalpath . Si la ruta en la cookie es inexacta (por ejemplo, /), surge el mismo problema que con el dominio compartido: una vulnerabilidad en una aplicación pone en riesgo otras aplicaciones en el mismo dominio.



En el siguiente ejemplo, una aplicación instalada en una URL http://pages.example.com/forumestablece una cookie con la ruta /:



Cookie cookie = new Cookie("sessionID", sessionID);
cookie.setPath("/");


Entonces, una aplicación maliciosa instalada en la dirección http://pages.example.com/evilpuede comprometer las cookies del usuario. Un atacante también puede llevar a cabo un ataque de envenenamiento de cookies: una cookie con una ruta compartida creada /evilsobrescribirá la cookie /forum.



Opción segura:



Cookie cookie = new Cookie("sessionID", sessionID);
cookie.setPath("/forum");


Las cookies no son sobre SSL . La aplicación crea cookies sin secureigualar la bandera true. Estas cookies se pueden transmitir sin cifrar a través de HTTP. La vulnerabilidad "Uso del protocolo HTTP inseguro" se recuerda de inmediato.



En el siguiente ejemplo, la aplicación crea cookies sin bandera secure:



Cookie cookie = new Cookie("emailCookie", email);
response.addCookie(cookie);


Si la aplicación utiliza HTTPS y HTTP, entonces, en ausencia del indicador seguro, las cookies creadas como parte de la solicitud HTTPS se transmitirán sin cifrar en las solicitudes HTTP posteriores, lo que puede llevar a comprometer la aplicación. Esto es especialmente peligroso si la cookie contiene datos valiosos, en particular el ID de sesión.



Opción segura:



Cookie cookie = new Cookie("emailCookie", email);
cookie.setSecure(true);
response.addCookie(cookie);


Cookies con validez ilimitada . Si almacena cookies valiosas durante demasiado tiempo, un atacante puede acceder a ellas.



De forma predeterminada, se utilizan cookies no persistentes (de sesión), que no se guardan en el disco y se eliminan después de cerrar el navegador. Sin embargo, el desarrollador de la aplicación web puede especificar cuánto tiempo se guardan las cookies; en este caso, se escribirán en el disco y se guardarán entre el reinicio del navegador y el reinicio de la computadora. Esto le da al atacante mucho tiempo para desarrollar un plan de ataque.



Recomendaciones para desarrolladores: asegúrese de que la aplicación no cree cookies de larga duración:



Cookie cookie = new Cookie("longCookie", cookie);
cookie.setMaxAge(5*365*24*3600); // 5 !


Proporcione un límite de tiempo máximo razonable siguiendo las pautas de OWASP .



Fuga de información



Quizás el tipo de vulnerabilidad más sensible para los usuarios de aplicaciones.



Fuga de información externa a través de páginas de error . La aplicación utiliza páginas de error estándar, que pueden contener información sobre la configuración del sistema.



Los mensajes de error y la información de depuración se escriben en el registro, se muestran en la consola o se transmiten al usuario. A partir de los mensajes de error, un atacante puede conocer las vulnerabilidades del sistema, lo que le facilitará la vida. Por ejemplo, un error de la base de datos puede indicar inseguridad contra la inyección de SQL. La información sobre la versión del sistema operativo, el servidor de aplicaciones y la configuración del sistema facilitará que un pirata informático planifique un ataque a una aplicación.



Fuga externa de información valiosa... En este caso, estamos hablando de la filtración de información técnica sobre la aplicación al transferirla por la red a otra computadora. En general, las fugas externas son más peligrosas que las internas.







Fuga interna de información valiosa . El mecanismo operativo es similar a los dos tipos de fugas anteriores, pero en este caso la información sobre el sistema se escribe en el registro o se muestra en la pantalla del usuario.



Fuga de datos confidenciales . Los datos personales valiosos de los usuarios ingresan a la aplicación desde diferentes fuentes: desde el propio usuario, desde varias bases de datos, desde almacenamientos de terceros. A veces, estos datos no se marcan como confidenciales o resultan ser valiosos no en sí mismos, sino solo en un contexto determinado.



Este es el caso en el que la seguridad de las aplicaciones y la privacidad de los datos personales se contradicen. Por razones de seguridad, es recomendable registrar información detallada sobre la actividad en el sistema para detectar actividad maliciosa. Desde el punto de vista de la privacidad de los datos, por el contrario, al registrar información confidencial, el riesgo de su fuga es mayor. En general, garantizar la confidencialidad de los datos personales de los usuarios de la aplicación es una prioridad más alta.



Epílogo



Los tipos de vulnerabilidades considerados en este artículo cubren la mayoría de las brechas "universales" en aplicaciones escritas en diferentes lenguajes de programación. Sin embargo, algunos lenguajes tienen sus propias vulnerabilidades específicas. Pero este ya es un tema para otro artículo. Y finalmente, recuerde: al crear aplicaciones, no olvide seguir las recomendaciones anteriores, lea detenidamente la documentación y verifique las vulnerabilidades de las aplicaciones utilizando software especializado.



Autor: Elizaveta Kharlamova, jefa del departamento de análisis, Solar appScreener




All Articles