¿Qué significa, para un lenguaje de programación, ser seguro? ¿Por qué los desarrolladores dicen que Java es seguro? ¿Qué lenguajes de programación son realmente ‘seguros’?

No he oído a nadie describir Java como “seguro” antes. La gente ciertamente se refiere a Java como un “lenguaje seguro”. “Seguro” y “seguro” significan algo diferente aquí. Abordaré ambos en esta respuesta por si acaso, en particular porque están relacionados.


¿QUÉ SIGNIFICA QUE UNA LENGUA ES SEGURA?

Cardelli define “idiomas seguros” como idiomas en los que se garantiza que no se produce ningún error sin atrapar [1]. Es decir, es una propiedad del lenguaje donde cuando se produce algún error en su programa, deja de ejecutarse.

Considere la siguiente pieza de código:

int [5] números = [1, 2, 3, 4, 5];
int elegido = números [10];
pantalla (elegida);

Declara que `números` es una secuencia de 5 números. Luego selecciona el décimo número de esa secuencia y muestra ese número en la pantalla. El problema es que realmente no podemos elegir un décimo número en la secuencia porque dicha entrada no existe.

Un lenguaje que permita que la operación “números [10]” tenga éxito, leer datos desde fuera de la memoria que ocupan los “números” no es seguro. Este caso particular se llama Lectura fuera de límites [2], y es una vulnerabilidad de seguridad común que fue responsable de errores de software muy grandes, como Heartbleed [3], y puede hacer que un atacante pueda leer memoria privilegiada

Un lenguaje seguro detiene la ejecución del programa en la instrucción “números [10]”, por lo que es imposible que se pierda memoria privilegiada. Si ha visto una “Excepción fuera de límites”, “RangeError”, o una excepción similar que se planteó anteriormente, ese es un ejemplo de esta propiedad en acción.

Por supuesto, “seguro” es un término muy genérico, por lo que clasificamos la seguridad en muchas categorías diferentes. Un lenguaje puede ser “seguro para la memoria”, si asegura que el programador nunca pueda usar la memoria [4]. Puede ser “tipo seguro”, si asegura que todas las propiedades probadas por el sistema de tipos no pueden ser violadas durante el tiempo de ejecución [5].

La seguridad como propiedad se puede garantizar en tiempo de ejecución, con controles dinámicos. Esto es lo que generalmente hacen las excepciones. Cuando ve que se genera una excepción, se realizó una verificación dinámica para garantizar que las propiedades garantizadas por su idioma se mantengan y que no esté introduciendo vulnerabilidades en su código sin saberlo. La seguridad también se puede verificar en tiempo de compilación, utilizando herramientas de análisis. Algunos lenguajes tienen sistemas de tipos muy potentes que les permiten demostrar, por ejemplo, que su programa nunca puede hacer mal uso de un protocolo en particular al emitir las operaciones en el orden incorrecto [6]. Por cierto, este tipo de seguridad generalmente se denomina “seguridad estática”.

Un lenguaje inseguro es más difícil de escribir en programas seguros, pero no hay una manera simple de responder “cuánto más difícil”.

¿QUÉ SIGNIFICA QUE UNA LENGUA ES SEGURA?

Nunca antes había escuchado que este término se usara así, por lo que la siguiente definición es específica de esta respuesta: un lenguaje es seguro si garantiza que los usos de su semántica no pueden ser subvertidos / explotados por código no confiable en el lenguaje. Por ejemplo, en un idioma seguro, tiene la garantía de que si instala la Biblioteca A, escrita por algunas personas al azar, y la usa, esa biblioteca no puede hacer ciertas cosas en su programa.

Al igual que con la “seguridad”, la seguridad viene en diferentes categorías. Una categoría común aquí es “capacidad de lenguaje seguro”. En dicho lenguaje, tiene la garantía de que cualquier código en su programa tiene precisamente los derechos que le otorga, y nada más. El lenguaje más famoso de esta categoría es probablemente E [7], un lenguaje diseñado específicamente para esto (no inventó el concepto, pero hizo contribuciones importantes. Ver la tesis de Miller [8]). Pony [9], Newspeak [10] y mi propio idioma Purr también tienen capacidad segura. Es posible que haya escuchado el término “Seguridad de capacidad de objetos” antes, ese es un modo particular de este concepto. De lo contrario, debería leer esta página: Computación de capacidad

Java no es un lenguaje con capacidad segura. En Java, hay un espacio de nombres global, y todo el código tiene acceso a este espacio de nombres. Cualquier código que llame tiene acceso al sistema de archivos, por ejemplo. Cualquier código puede eliminar archivos en su HDD. Java proporciona un poco de seguridad a través de la Inspección de pila [11] [12], que evita que el código no privilegiado / no confiable llame a un código privilegiado, garantizando así que parte del sistema no se pueda subvertir desde adentro, a costa de verificar la pila para verificar si no se realizó una llamada desde un código no confiable.

¿QUÉ IDIOMAS DE PROGRAMACIÓN SON REALMENTE SEGUROS?

Esta es una pregunta mucho más difícil (no solo por el hecho de que parece estar preguntando acerca de un tipo diferente de “seguro” que el que describí anteriormente). Hay demasiados vectores de ataque para resolver este problema solo en el lenguaje.

E es un lenguaje seguro, en E esto significa que ningún código puede tener más privilegios que los que usted les otorga explícitamente. Esto es importante cuando se habla de la confianza en las bibliotecas externas, pero no ayuda a evitar fugas de datos de las políticas de datos que ha definido en su código.

Jeeves [13], por otro lado, ayuda a prevenir fugas de datos. Está diseñado para que pueda definir políticas para la privacidad de los datos, y el lenguaje hace cumplir esas políticas a través de su código y en los sistemas con los que interactúa. Sin embargo, Jeeves no lo ayudará a garantizar que las páginas web que genere en su servidor web estén libres de ataques XSS.

Los idiomas Yesod de Haskell [14] garantizan que sus páginas web no pueden caer en ataques XSS, pero no le ayuda a garantizar que una biblioteca externa que instaló no pueda ejecutar código peligroso que no quería / esperaba ( Sin embargo, Safe Haskell puede mitigar esto).

Espero que puedas ver lo difícil que es esto. En particular, si solo está considerando el lenguaje de programación en sí, y no sus bibliotecas, herramientas, la plataforma en la que se está ejecutando, los sistemas con los que está interactuando, …

La respuesta literal a esta pregunta sería “ninguna”. Sin embargo, tenemos muchos idiomas que se esfuerzan por hacer que las clases comunes de errores sean más difíciles de cometer y, por lo tanto, provoquen menos vulnerabilidades o vulnerabilidades menos críticas. Se podría decir que esos idiomas son “más seguros” en esos aspectos particulares.

Notas al pie

[1] http://lucacardelli.name/Papers/…

[2] CWE-125: lectura fuera de límites

[3] Insecto sangrante

[4] Es hora de una intervención de seguridad de memoria • Tony Arcieri

[5] Tipo de seguridad – Wikipedia

[6] edwinb / Protocolos

[7] De los objetos a las capacidades

[8] Hacia un enfoque unificado para el control de acceso y el control de concurrencia

[9] Pony – Pony

[10] Newspeak

[11] http://sip.cs.princeton.edu/pub/…

[12] Permisos en el Kit de desarrollo de Java (JDK)

[13] https://projects.csail.mit.edu/j…

[14] Plantillas de Shakespeare

Es un poco descuidado describir un lenguaje de programación como seguro. La experiencia muestra que ninguna tecnología es completamente segura y, desde luego, cualquier cosa conectada a Internet debe tratarse como un punto de vulnerabilidad potencial.

Podemos hablar sobre las características que los lenguajes tienen como objetivo ayudar a las personas a diseñar, desarrollar y probar programas de seguridad o qué características o vulnerabilidades tienen que lo hacen más difícil.

Piensa por un momento en los autos. Ningún automóvil es completamente seguro e incluso si los autos autónomos súper confiables eventualmente eliminan el factor de error humano, nunca habrá un automóvil completamente seguro. Eso no impide que las personas agreguen características de seguridad a los automóviles y no invalida que podamos hablar de que algunos automóviles son más seguros o menos seguros.

Mirando hacia atrás a la programación, considere una famosa vulnerabilidad de seguridad llamada Heartbleed. En esencia, un servidor puede enviar a otro servidor un mensaje de “¿aún estás vivo?” Para confirmar que el otro servidor está en un nivel básico en ejecución.

Por lo tanto, el servidor A envía un mensaje que equivale a algún texto (por ejemplo, “¿Estás ahí?” Pero podría ser cualquier cosa) y el servidor B envía “¿Estás allí?”. Ahora hay 14 caracteres en “¿Estás ahí?” Y se suponía que el servidor A enviaba un mensaje que (en efecto) decía “Aquí hay 14 caracteres (¿Estás ahí?), Por favor envíalos de nuevo para confirmar que estás corriendo”. Pero resultó que un servidor malicioso A podría enviar “Aquí hay 1000 caracteres (¿Estás ahí?) Por favor envíalos de vuelta para confirmar que estás corriendo”.

La vulnerabilidad era que el código en el servidor B no validaba que se le hubieran enviado 1000 caracteres, pero aún así había devuelto 1000. Lo que devolvió también incluido fue lo que había en su memoria para los 986 caracteres después de “¿Estás ahí?”.

¿Cómo es eso una vulnerabilidad? Depende de lo que ocurra en esos 986 caracteres y las personas que escribieron el código en el Servidor B no esperaban esto, por lo que podría ser cualquier cosa. Hay un par de ‘exploits’ enumerados en esa página de Wikipedia donde los piratas informáticos obtuvieron las contraseñas de los usuarios y, en otro caso, los números de seguridad social al elegir los datos adicionales enviados de vuelta.

Una vulnerabilidad es una debilidad y un exploit es algo útil que alguien ha descubierto que puede hacer con esa debilidad.

Recuperar datos extra no deseados es un día feliz para un pirata informático, pero una vulnerabilidad aún más grave es cuando pueden hacer que un programa sobrescriba partes de su memoria que el programador no esperaba. Cuando el programa lee la memoria sobreescrita, puede fallar (lo que los hackers ven como una victoria) o, peor aún, hacer algo inesperado y, de hecho, dar el control al hacker.

Ahora hay una función eliminada que los viejos estándares C llamaban gets() que es notoriamente vulnerable a ese tipo de sobreescritura. Si un programador cree que nunca le enviará un archivo con líneas de más de 100 caracteres, pero envía 200 gets () simplemente sobrescribirá áreas inesperadas de memoria con los 100 caracteres adicionales y quién sabe cómo podría explotarse.

gets() es un caso raro en el que el Comité Estándar de C decidió que era tan vulnerable que lo eliminó del lenguaje. Normalmente, las personas ‘desprecian’ (desalientan el uso) de características potencialmente vulnerables y proporcionan alternativas (normalmente) más seguras. Pero para gets() la vista, sin duda, correcta era que es tan vulnerable que tuvo que eliminarse. Se eliminó del estándar C en 2011 y C ++ en 2014. Durante años, la gente había reconocido que era malo, pero aún así se usó y estoy seguro de que hay una gran cantidad de bases de código que lo usan. Por lo general, lleva décadas que las cosas se ejecuten desde la base de código instalada.

Debido a que le da al programador tanto control, C no verifica implícitamente este tipo de problemas de lectura / escritura de memoria fuera de los límites y una mayor responsabilidad de identificar dónde podrían suceder y protegerse contra ellos recae en los desarrolladores de aplicaciones individuales.

Entonces es justo decir que C tiene una vulnerabilidad potencial significativa. Todos los programadores de C competentes son muy conscientes de este problema, pero los sistemas son complejos y aún es posible que las vulnerabilidades no se aborden y lleguen al código en vivo. Ese error HeartBleed es un ejemplo perfecto.

Lo que no es justo es que C ‘no es seguro’. Casi todos los sistemas operativos del mundo (ciertamente por cuota de mercado) y casi todo el software de mensajería y seguridad de bajo nivel también está escrito en C (o posiblemente C ++) con un posible guión de ensamblador. Pero (generalmente) se ha escrito (si no es basura) para evitar exponer esas vulnerabilidades. No es justo decir que C es inseguro si eso significa que simplemente no es posible escribir programas seguros en él.

Entonces, ¿qué pasa con Java siendo seguro? Java tiene algunas características que significan que tales riesgos están mucho menos expuestos. Se ejecuta en una ‘máquina virtual’ (Java Virtual Machine o JVM), lo que significa que no se supone que el programa de aplicación corra el riesgo de sobrescribir la memoria que no debería o devolver datos que no deberían de la misma manera. La forma en que la cadena “¿Estás ahí?” Se almacenaría y accedería en Java hace que (en papel) sea imposible enviar 1000 caracteres. Incluso, al intentarlo, sería difícil codificar HeartBleed en Java de una manera que fuera fácil en C.

Pero no es justo decir que Java es seguro si seguro significa que es imposible para un hacker explotar un servidor que ejecuta un programa Java.

Podría haber (al menos en principio) vulnerabilidades en la JVM o en el sistema operativo en el que se basa la JVM. De hecho, cualquier código Java que se ejecute en un servidor con la vulnerabilidad HeartBleed sería exactamente tan vulnerable como cualquier código escrito en cualquier otro idioma. De hecho, al saber cómo funciona la JVM, es probable que sea más fácil de interpretar y explotar un bloque de su memoria.

También hay muchos otros tipos de vulnerabilidad que estos problemas de lectura / escritura de memoria. Algo llamado vulnerabilidad de ‘Inyección SQL’ es donde al usar mal la interfaz de usuario, algunos logran ejecutar comandos esencialmente arbitrarios en la base de datos de back-end. Cualquier lenguaje que permita a los programadores pasar instrucciones ‘crudas’ a una base de datos es potencialmente vulnerable y nuevamente los desarrolladores deben abordarlo ellos mismos. Java tiene varias bibliotecas de bases de datos que les ayudan a hacerlo, pero no les impide codificar tales errores.

¡Un ataque de inyección SQL podría ser tan banal como ingresar algo como ' OR 1=1 en un cuadro de contraseña y sin conocer la contraseña para acceder a ninguna cuenta!

Sin quitar la capacidad de emitir instrucciones SQL de los programadores que se protegen contra un exploit de inyección SQL, seguirá siendo responsabilidad del equipo de desarrollo para cada aplicación.

Y ahí radica el desafío. A mayor potencia y menor nivel se les da a los programadores de acceso más formas de pasar por alto las cosas y dejar vulnerabilidades en el código. C y Assembler son de muy bajo nivel y dejan mucha responsabilidad al programador. Java es, en comparación, un nivel superior y protege mejor al programador de algunos de ellos “listos para usar”.

No creo que un profesional de seguridad de software deba ir más allá de decir:

Java tiene una serie de características que ayudan a los desarrolladores a escribir código seguro. C, por otro lado, deja más de esa responsabilidad a los equipos de desarrollo individuales. Ninguno de los dos debe describirse con soltura como seguro o inseguro.

En el nivel más básico, la programación segura significa que un sistema no permite que las transiciones de estado de una entidad se desvíen de lo que se especifica en su código fuente, y que ninguno de los estados de una entidad está disponible para nada fuera de él que no esté previsto en su código fuente. Un lenguaje puede imponer reglas que no permiten algunas acciones que probablemente sean inseguras.

Hablando en términos de principios, cualquier lenguaje puede crear un sistema seguro, ya que la idea es que todas las acciones de un procesador son deterministas y se llevan a cabo exactamente como se especifica, con efectos secundarios conocidos (si los hay).

Ningún lenguaje evita errores de programador, o un mal diseño crea una programación insegura. Las reglas impuestas por un lenguaje solo pueden ayudar al programador a crear un sistema seguro. No lo aseguran. Las vulnerabilidades en el sistema operativo generalmente están fuera del control de un lenguaje de aplicación. Entonces, no importa qué tan bien un lenguaje promueva prácticas seguras; No importa cuán bien diseñado esté un sistema programado, los recursos del sistema aún pueden explotarse maliciosamente si el sistema operativo subyacente permite que ocurran esas vulnerabilidades.

No creo que haya un lenguaje “seguro”. Los idiomas facilitan o dificultan la creación de sistemas seguros. La etiqueta “lenguaje seguro” es marketing, que puedo decir caritativamente connota el hecho de que el lenguaje contiene algunas reglas que hacen que algunas prácticas de seguridad sean más fáciles de implementar, pero repito, solo si se usan bien. La cuestión es que las prácticas de seguridad promovidas por un lenguaje solo pueden ser de utilidad limitada contra las amenazas que enfrenta un sistema. Por lo tanto, algunos lenguajes, o de mayor importancia, algunas arquitecturas de tiempo de ejecución, promueven mejores prácticas de seguridad que otros.

No voy a recomendar ningún lenguaje, pero en términos de principios arquitectónicos, la programación real orientada a objetos (no lo que se llama “OOP” con Java, C ++, C #, etc.) es bastante segura, porque las entidades en dicho sistema existen independientemente uno del otro, aíslan su estado de todo lo demás, no hacen que su implementación sea un factor en la ejecución del todo más amplio y no permiten que otras entidades alteren esa implementación. Solo responden a los mensajes, pueden identificar a los remitentes de esos mensajes y pueden negarse a responder a los mensajes en función de cualquier criterio, incluidas las entidades que los envían. En segundo lugar, el principio de programación a interfaces hace posible cambiar la implementación de tal manera que los objetos “extraños” puedan introducirse en un sistema, se les presente una interfaz de sistema completa que proteja de él los objetos operativos del sistema de nivel inferior, pero aún permita para llevar a cabo su programación completamente aislada de todo lo demás, de modo que no cause daño al sistema que lo ejecuta.

Mark S. Miller (sin relación) ha trabajado mucho en el diseño de esquemas seguros de relación de objetos para varios escenarios, para maximizar la seguridad del sistema (aunque esto no es seguridad total, como él admite fácilmente, dados los problemas de seguridad con el diseño subyacente del sistema operativo) . Ha escrito sobre su trabajo en línea y ha realizado presentaciones sobre el mismo, que se han publicado en videos en línea. Es posible que desee examinarlos detenidamente.

A2A

P: ¿Qué significa, para un lenguaje de programación, ser seguro?

En la práctica, muy poco. Es principalmente un reclamo de marketing y, a menudo, no tiene fundamento.

P: ¿Por qué los desarrolladores dicen que Java es seguro?

Java tiene una larga historia de vulnerabilidades de seguridad, por lo que son mentirosos o ignorantes.

P: ¿Qué lenguajes de programación son realmente “seguros”?

Probablemente ninguno. Es difícil proporcionar seguridad en una gran superficie, como la que proporciona un lenguaje, un entorno de ejecución y bibliotecas. Es más fácil (y, por lo tanto, es más probable que sea seguro) proporcionar seguridad a través de algún tipo de mecanismo de encapsulación, varias de las cuales están disponibles:

  • Contenedores (Linux).
  • Máquinas virtuales completas.
  • Sistema de seguridad de llamadas (SELinux).
  • NaCl (no estrictamente de contención, pero aún externo al lenguaje).

Aquí hay un código en C que lee una línea y devuelve el primer carácter.

// este es un código incorrecto EN PROPÓSITO, hay formas seguras de hacerlo
char readLine () {
texto de char [80];
scanf (“% s”, texto);
texto de retorno [0];
}

Aquí está el equivalente en java:

clase pública MyClass {
public static char readLine () {
Scanner sc = nuevo escáner (System.in);
Texto de cadena = sc.nextLine ();
return text.charAt (0);
}
}

En aras de la discusión, digamos que ambos están leyendo datos de la red.

Veamos la versión C.

Este código no es bueno en absoluto. ¿Qué pasaría si la línea de texto contiene 80 caracteres o más? el búfer es lo suficientemente grande como para contener 79 caracteres. Según el estándar C, este es un comportamiento indefinido y la aplicación puede hacer lo que quiera. Esto se llama desbordamiento de búfer.

En la práctica, la función scanf escribe felizmente sobre lo que está después del text la matriz. En nuestro mundo x86: la dirección de retorno de la función. Una cadena larga, por lo tanto, puede hacer que la función regrese a direcciones aleatorias. Un atacante puede usar ese comportamiento para ejecutar código arbitrario y obtener acceso al sistema. Esto se llama “programación orientada al retorno”.

Existen problemas similares con otros comportamientos indefinidos, punteros colgantes, variables dobles libres no inicializadas.

Veamos la versión de Java.

No importa qué tan larga sea la línea, Java asigna suficiente memoria para contener el resultado, no puede haber desbordamiento de búfer.

Todavía hay un error aquí. Si la línea está vacía, la función charAt intentará leer un valor fuera de rango. Esto arrojará una StringIndexOutOfBoundsException . Si nadie atrapa la excepción, el hilo morirá. Por lo general, no hay forma de usar eso para obtener acceso al sistema. Puede hacer que la aplicación se bloquee, que generalmente es lo peor que puede suceder.

Si la entrada está cerrada, nextLine devolverá nulo. La text.charAt(0) arrojará una NullPointerException . De manera similar, generalmente no es posible explotar eso para obtener acceso al sistema.

Es imposible usar punteros colgantes o hacer un doble libre en Java ya que no libera memoria, el recolector de basura lo hace y solo después de que ya no lo esté usando.

Por lo tanto, Java se conoce como “memoria segura”.

La propia JVM está escrita en C y tiene una larga historia de vulnerabilidades de seguridad.

Hay otros tipos de vulnerabilidades contra las que Java no puede protegerlo, como secuencias de comandos de sitios cruzados, inyección de SQL, denegación de servicio, rastreo de red, hombre en el medio, etc. Puede escribir código vulnerable en cualquier idioma.

Si revisa la base de datos de CVE, verá muchas vulnerabilidades causadas por desbordamientos del búfer, punteros colgantes, doble acceso de memoria libre y sin inicializar. Java ha incorporado protección contra todo esto, por lo que la gente dice que es “seguro”. Pero no hay una bala de plata cuando se trata de seguridad. Ningún lenguaje puede defenderse de un mal programador.

Creo que, en este contexto, “lenguaje seguro” significa “lenguaje que evita que los piratas informáticos exploten errores en las aplicaciones debido a una mala implementación (normalmente desbordamiento de búfer, ataque de cadena de formato …) y tal vez permita a los desarrolladores estar libres de preocupaciones.

Honestamente, no creo que tal cosa exista. Java en sí puede no ser vulnerable al desbordamiento del búfer, pero la JVM sí (se implementa en C / C ++). Una vulnerabilidad en la JVM puede comprometer potencialmente todas las aplicaciones Java (y la peor parte es que no puede hacer nada al respecto hasta que Oracle realice un parche de seguridad).

Otro ejemplo es la llamada de comando del sistema (típicamente system () o execve () en C) que permite que una aplicación ejecute comandos de shell. Incluso si no soy desarrollador de Java, puedo decir que debes tener mucho cuidado con esto. Tal llamada de comando del sistema puede ser secuestrada fácilmente por un hacker sin importar el idioma que use.

En conclusión: un lenguaje con características de verificación de seguridad no significa que un desarrollador pueda iniciar un código desordenado y no tener preocupaciones.

Si bien es cierto que ningún lenguaje de programación evita todas las vulnerabilidades de seguridad, algunos lenguajes previenen más vulnerabilidades que otros. En este sentido, algunos idiomas pueden ser “más seguros”, pero no absolutamente seguros.

La enumeración de debilidad común (CWE / SANS 2011, los 25 errores de software más peligrosos) enumera las vulnerabilidades de software más comunes. Mirando la lista, solo unos pocos son abordados por lenguajes de programación. El resto depende únicamente de las prácticas de ingeniería de software.

Muchos lenguajes, como Java, C #, Pascal y Ada evitan y / o detectan accesos de matriz fuera de los límites. Algunos, como Ada, detectan el desbordamiento o subdesbordamiento del valor escalar. Si bien estos lenguajes pueden ser “más seguros” que C o Assembly, no controlan los 25 problemas identificados en el CWE Top 25.

La seguridad en nuestra profesión es en gran medida una propuesta de gestión de riesgos. No puede declararse en bancarrota en gastos de seguridad. En gran medida, lo que está haciendo es hacerlo más difícil con la esperanza de que un hacker busque una selección más fácil en otro lugar.

Java tiene algo más de características de seguridad, que tienen más que ver con la plataforma que con el lenguaje. Tiene algunas características diseñadas para proteger de los desbordamientos de memoria que puede tener con el código C. La plataforma está diseñada para crear un dígito de verificación a partir de su código de bytes como parte de la compilación. Y la JVM vuelve a comprobar esto.

Pero nada es realmente seguro. Todo lo que está haciendo es reducir su riesgo. Sería difícil enfrentarse a un enemigo determinado. Particularmente, un estado nación. Es por eso que la interferencia electoral rusa es un gran problema.

A2A

Los lenguajes seguros son los que evitan (o reducen la probabilidad) de que un programador se dispare en el pie. Los ejemplos son memoria administrada, sandboxing, incapacidad para tener desbordamientos de búfer, poco acceso a las partes del sistema operativo de bajo nivel como el kernel, etc.

No hay idiomas verdaderamente seguros, pero algunos son más seguros que otros. En términos generales, los idiomas más nuevos son más seguros ya que han identificado las debilidades en los idiomas más antiguos y han desarrollado formas de lidiar con ellos. Por ejemplo, Java es una mejora con respecto a C ++ porque se compila en bytecode, que puede guardarse fácilmente, y tiene recolección de basura, lo que reduce los problemas de memoria.

La JVM puede imponer limitaciones estrictas a la ejecución del código si así lo desea.

Un método solo puede acceder a los objetos y la memoria a los que tiene acceso, o accede a través de llamadas a la biblioteca.

Esto no es cierto en C ++. En C ++ puede escanear la memoria de trabajo de la aplicación y disparar al azar bytes de corrupción de datos por todo el lugar.

Con la falta de punteros de memoria sin procesar, Java tiene una especificación que proporciona mayor seguridad dentro de una única base de código.

La seguridad no tiene casi nada que ver con el idioma.

Todos los lenguajes de computadora son igualmente “seguros”, de acuerdo con cualquier definición razonable de “seguro”. Un ejecutable se parece mucho a cualquier otro.

La única excepción real es JavaScript, ya que se usa más comúnmente, es decir, dentro de un navegador. Esto se debe a que todo el código fuente de Javascript se descarga e interpreta localmente, y realmente puede ver el código fuente.

Pero C, Java, C #, C ++, ensamblaje, etc. son todos igualmente seguros. O inseguro

Ningún idioma es realmente seguro. Existe una compensación entre permitir que los programadores controlen lo que pueden tocar y estar seguros. Java evita algunos agujeros de seguridad al no permitir el acceso a ciertas cosas (como el acceso directo a punteros). Hay otras cosas permitidas que pueden arruinar una computadora a la que todavía tiene acceso completo.

Java es un lenguaje fuerte de uso frecuente que puede ser muy seguro y evita algunos problemas de seguridad. Sin embargo, cualquier cosa que le permita controlar la computadora no puede evitarlos.

No es una cuestión de lenguaje en sí, sino de su implementación.

Si crea un formulario PHP para acceder a una base de datos y luego codifica las contraseñas, un atacante puede omitir la autenticación.

Eso no significa que PHP o Java u otro lenguaje sean inseguros, solo que el desarrollador se equivocó al crear esa página.