En el software, este tipo de medidas no se tiene siempre en cuenta...
Ejemplo: extracto de la documentación de BEA WebLogic (2004):
Since most security for Web applications can be implemented by a system administrator, application developers need not pay attention to the details of securing the application unless there are special considerations that must be addressed in the code. For programming custom security into an application, WebLogic Server application developers can take advantage of BEA-supplied Application Programming Interfaces (APIs) for obtaining information about subjects and principals (identifying information for users) that are used by WebLogic Server. The APIs are found in the
weblogic.securitypackage.
Muchos sistemas de software no se construyen con la seguridad en mente.
Las tecnologías reactivas como los cortafuegos pueden aliviar algunos ataques a los servidores, pero no abordan el problema principal: software mal hecho
Para poner en práctica la seguridad del software hay que:

¿Cuáles son los puntos más importantes de cara a la seguridad?
Esta asignatura trata sobre la seguridad en los siguientes puntos...
Vulnerabilidad provocada por no validar la entrada del usuario:
Implementación en Python:
def greet_user(name):
print(f"Hola {name}!")
# Supongamos que la entrada proviene de un parámetro web
user_input = "<script>alert('XSS')</script>"
greet_user(user_input)
Solución más segura:
import html
def greet_user(name):
safe_name = html.escape(name)
print(f"Hola {safe_name}!")
Provocado por ofrecer a los atacantes la posibilidad de escribir arbitrariamente en memoria.
Implementación en C:
void trouble() {
int a = 32; /* integer */
char line[128]; /* character array */
gets(line); /* read a line from stdin */
}
Solución más segura:
void trouble() {
int a = 32; /* integer */
char line[128]; /* character array */
fgets(line, sizeof(line), stdin); /* read a line from stdin */
}
Estructura en memoria:
0xNN es la dirección de comienzo de la pila (stack)trouble()...Marco de pila antes de la ejecución:

Marco de pila después de ejecución normal:

Marco de pila tras un ataque por buffer overflow:

¿A qué se debe este buffer overflow?
Buffer overflow provocado por el (mal) uso de APIs vulnerables:
gets(), strcpy(), etc.
¿Cómo evitar el mal uso de APIs vulnerables?
¿Todos los problemas de seguridad se pueden resolver
con análisis de código?
Menos del 50%
— según Chest & West: Secure Programming with Static Analysis, 2007 —
¿Qué otras actividades relacionadas con el desarrollo tienen implicaciones en la seguridad?
Arquitectura y diseño
Un servicio web que ejecuta consultas SQL directamente desde parámetros HTTP:
Implementación en Python:
@app.route('/user')
def user_info():
name = request.args['name']
query = f"SELECT * FROM users WHERE name='{name}'"
return db.execute(query)
¿Por qué el diseño es clave para la seguridad?
El diseño asegura la mantenibilidad
Ann Campbell: For secure code, maintainability matters
El 60% de las CWE no son exactamente vulnerabilidades...
La vista CWE-699: Software Development contiene debilidades de categorías diversas...
CWE Top 25 Most Dangerous Software Weaknesses
Al alza:
A la baja:


¿Qué requisito de seguridad puede verse incumplido
si no se cumple la CWE-581?
Disponibilidad
Robert C. Martin: La arquitectura de un sistema software es la forma dada al sistema por aquellos que lo construyen. La forma es la división del sistema en componentes, la disposición de esos componentes y la manera en que se comunican entre sí.
Para un enfoque completo a la seguridad del software hay que combinar revisiones de código y análisis arquitectónico
¿Qué tiene que ver la arquitectura en todo esto de la seguridad?
La arquitectura software decide los componentes que conforman un sistema software y sus interacciones
¿Son importantes otras actividades relacionadas con el desarrollo de software?
Mucho, pero no las trataremos aquí
No nos interesan (tanto)...
Sí nos interesan aquellos aspectos del desarrollo de software que, en principio, no parecen relacionados con la seguridad, pero que la ponen en riesgo si no se hacen bien.
¿Así que hay que saber programación y técnicas de desarrollo de software para poder garantizar la seguridad?
¿No hay un respiro para quienes no les gusta programar?
Threat modeling: diagramas y diseño de la arquitectura
Métodos de threat modeling en arquitectura software:
¿Conocéis Windsurf? ¿Github Copilot?
¿Es otro respiro para quienes no les gusta programar?
server-side-request.pytemporary-file-creation.pycryptographic-key-generation.pyGarantizar el comportamiento de todo elemento de una aplicación ante cualquier situación de uso por incorrecta o imprevisible que ésta pueda parecer
¿La programación defensiva garantiza un software seguro?
No lo garantiza, porque al hablar de seguridad se supone la existencia de un adversario
La seguridad del software significa crear programas que se comportan correctamente incluso en presencia de un comportamiento malicioso.
void printMsg(FILE* file, char* msg) {
fprintf(file, msg);
}
void printMsg(FILE* file, char* msg) {
fprintf(file, msg);
}
¿Cómo arreglamos el hecho de que algún argumento de la función pueda ser null? Aplicar programación defensiva...
Aplicando programación defensiva:
void printMsg(FILE* file, char* msg) {
if (file == NULL) {
logError("attempt to print message to null file");
} else if (msg == NULL) {
logError("attempt to print null message");
} else {
fprintf(file, msg);
}
}
NOTA: Hay alternativas mejores para el tratamiento de null, como los Optionals
¿Desde la perspectiva de la seguridad, esta solución que aplica programación defensiva es suficiente?
Desde la perspectiva de la seguridad, esta solución no es suficiente.
Un atacante podría especificar un string en un formato maligo,
pensado para provocar un buffer overflow.
Recordemos el marco de pila de una llamada a función...
...antes de la ejecución:

...tras un ataque por buffer overflow:

Las organizaciones que desarrollan software tienen grupos de ingenieros de calidad - Quality Assurance (QA) dedicados a escribir y ejecutar tests y evaluar sus resultados.
Es casi imposible mejorar la seguridad del software solo mejorando la QA
Los tests de funcionalidad sirven para asegurarse de que los usuarios típicos con las necesidades típicas estén contentos, pero no sirven para encontrar defectos de seguridad que no estén relacionados con características específicas de seguridad.
La mayor parte de las pruebas software sirven para comparar la implementación con los requisitos, enfoque no adecuado para encontrar problemas de seguridad.
Los problemas de seguridad no suelen ser violaciones de los requisitos, sino funcionalidades no deliberadas que hacen que un programa sea inseguro.
El software fiable hace lo que se supone que tiene que hacer.
El software seguro hace lo que se supone que tiene que hacer, y nada más.

<c:if test="${param.sayHello}">
<!-- Let's welcome the user ${param.name} -->
Hello ${param.name}!
</c:if>
¿alguna vulnerabilidad?
Es vulnerable a ataques de Cross-Site Scripting (XSS)
Ninguna cantidad de pruebas de caja negra llega a ser suficiente para revelar este problema.
Las pruebas de caja negra solo pueden comenzar cuando el sistema está terminado. Tras desplegarlo, los atacantes y los defensores están en situación de igualdad. Los atacantes pueden ahora estudiar el software.
La suma de horas de todos los posibles atacantes puede superar con creces la suma de horas de los defensores haciendo pruebas. Los atacantes pueden encontrar más vulnerabilidades.
Encontrar una prueba fallida es un signo de problemas, pero pasar una prueba con éxito no significa mucho.