Recientemente leí sobre el tema $.
P: ¿Por qué un lenguaje de programación tiene inseguridad trivial incorporada? ¿O ... fue solo en los viejos tiempos? ¿Cómo podría ser esto?
Recientemente leí sobre el tema $.
P: ¿Por qué un lenguaje de programación tiene inseguridad trivial incorporada? ¿O ... fue solo en los viejos tiempos? ¿Cómo podría ser esto?
C se diseñó en un momento en que la potencia de CPU disponible era un recurso escaso, y también se hizo mucho menos programación. Los tiempos modernos han cambiado el contexto:
Hoy en día, la mayor parte del tiempo de computación en una CPU se gasta en esperar la RAM, porque la velocidad de la CPU ha aumentado mucho más rápido que la latencia de la RAM. Por lo tanto, la CPU tiene algún "tiempo libre" y, por lo tanto, puede permitirse controles adicionales, por ejemplo. controles de límites en matrices.
Se realiza mucha más programación en estos días, lo que significa que hay mucho más programadores involucrados, y la competencia promedio ha disminuido mecánicamente.
La competencia promedio de atacante , por otro lado, ha aumentado bastante. Las explotaciones de desbordamiento de búfer han pasado, desde la década de 1970, de "debilidad teórica" a "ataque genérico que puede ajustarse automáticamente y programarse".
Esta es la razón por la que casi todos los lenguajes de programación más nuevos incluyen "protecciones" inherentes contra los desbordamientos del búfer, pero también ataques de tipificación cruzada (cuando algunos bytes se interpretan con un tipo diferente, por ejemplo, haciendo que un código considere un entero como si era un puntero) y problemas de asignación de memoria ("use-after-free"). Para desbordamientos de búfer, la protección es doble:
Desafortunadamente, tales protecciones no se pueden devolver de forma genérica a C. Por ejemplo, la especificación de C permite escribir un valor de puntero en un archivo y, luego, leerlo nuevamente, y el puntero DEBE seguir siendo válido. Es matemáticamente inviable escribir un recolector de basura que puede manejar este caso. hay un GC para C y C ++ , pero (por naturaleza) no puede realmente admitir todos los programas C "legales".
En otras palabras, si "modificas" C para que sea más robusto contra los desbordamientos de búfer, entonces ya no es "C", sino otra cosa (que puedes llamar "Java" o "C #"). La C original todavía se usa ampliamente, a veces por una buena razón técnica (por ejemplo, para escribir código en una plataforma muy pequeña, como una tarjeta inteligente), pero en su mayoría fuera de la tradición y para una integración más fácil con todas las bibliotecas existentes.
C es un lenguaje simple que es bastante fácil de traducir al lenguaje de ensamblador / máquina (en comparación con los idiomas modernos) cuando descuidas las optimizaciones.
C no es tan defectuoso con las inseguridades, es solo que C no te obliga a hacer las cosas siempre de una manera más segura como otros idiomas modernos. Un programa que se ejecuta en un Bell Labs PDP-10 en la década de 1970 por ingenieros calificados tenía requisitos diferentes a los de un servidor web moderno conectado a Internet que puede ser atacado por adversarios expertos. En ese entonces, usted quería que el lenguaje fuera rápido y simple, y que el programador dejara tantas comprobaciones simples de cordura.
Una de las partes principales 'inseguras' de C es la falta de verificación de límites. Si desea copiar una cadena de caracteres en una nueva matriz, la función strcpy
copiará una cadena de un búfer a otro búfer hasta que vea un byte NULO que indica el final de la primera cadena. Esto permite ataques de desbordamiento de búfer si intenta comprimir 500 caracteres de entrada en un búfer de 256 bytes (el programa seguirá copiando hasta que alcance el carácter nulo). La memoria después de esa cadena puede haber tenido datos importantes para la ejecución de los programas, posiblemente permitiendo que un atacante inyecte nuevos comandos de nivel de máquina en el programa. Sin embargo, hay formas más seguras de programar dentro de C, por ejemplo, usar strlcpy que toma como un parametrice el tamaño del búfer de destino y solo copia hasta tantos caracteres (y luego la cadena termina en nulo).
(Además, los sistemas operativos modernos brindan ayuda a través de funciones como no ejecución, bits de no escritura y asignación aleatoria del espacio de direcciones).
Por supuesto, todavía es posible que los programadores cometan errores.
Cuando C se diseñó a principios de los 70, eran tiempos diferentes.
Debido a estas circunstancias, el alto rendimiento era una preocupación mucho mayor que la seguridad. Es por eso que C omite muchos controles de seguridad en las operaciones y espera que los programadores se implementen ellos mismos cuando sientan la necesidad de ellos y puedan ahorrar los recursos que cuestan.
Pero hoy en día, la situación ha cambiado
Pero, por otro lado, los recursos de hardware se han vuelto mucho más abundantes. Los mejores supercomputadores de los años 70 tenían una potencia de procesamiento que era varias magnitudes por debajo de la de los teléfonos móviles actuales .
Por estas razones, el enfoque de los lenguajes de programación ha cambiado de eficiencia a seguridad.
Lea otras preguntas en las etiquetas buffer-overflow c