◇ OpenCyber Academy
Ingeniería · Capítulo 40 · Español

Capítulo 40 — Laboratorio de verificación II

Aprendizaje gratuito y abierto para quienes desean proteger a las personas y la tecnología. No se necesita una cuenta para estudiar ni consultar las respuestas.

Capítulo 40 — Laboratorio de verificación II

Mapa de la lección

Lección 40 publicada. Mapa, ejemplo, EX079.

flowchart TD
  N0["Resultados de aprendizaje y conexión"]
  N1["40.1 Inyección de fallos"]
  N2["40.2 Oráculos y clasificación"]
  N3["40.3 Semillas, tasas y cobertura"]
  N4["40.5 Actividad práctica: laboratorio 15"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5
  N5 --> EX["Ejemplo resuelto"]
  EX --> Q["Ejercicio EX079"]

Dibujo lógico

flowchart LR
  N0["Resultados de aprendizaje y conexión"]
  N1["40.1 Inyección de fallos"]
  N2["40.2 Oráculos y clasificación"]
  N3["40.3 Semillas, tasas y cobertura"]
  N4["40.5 Actividad práctica: laboratorio 15"]
  N5["Síntesis del capítulo"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX079"]
[Resultados de aprendizaje y conexión]
    |
    v
[40.1 Inyección de fallos]
    |
    v
[40.2 Oráculos y clasificación]
    |
    v
[40.3 Semillas, tasas y cobertura]
    |
    v
[40.5 Actividad práctica: laboratorio 15]
    |
    v
[Síntesis del capítulo]
    |
    v
[Ejemplo resuelto] --> [Ejercicio EX079]

Resultados de aprendizaje y conexión

Al terminar este capítulo, usted podrá (1) diseñar y ejecutar una campaña de inyección de fallos con semilla contra un control de seguridad; (2) clasificar los resultados y calcular las tasas de detección por clase de fallo; (3) encontrar las lagunas entre lo que detecta un control y lo que necesita un requisito; y (4) informar de una campaña de forma reproducible. Amplía el capítulo 30 a los fallos del entorno y a los ataques y prepara el proyecto final (capítulos 44–47).

40.1 Inyección de fallos

La inyección de fallos introduce deliberadamente fallos (mensajes corrompidos, descartados, retrasados, reproducidos o reordenados; reinicios de procesos; saltos de reloj; agotamiento de recursos) para observar cómo se comporta un sistema. Pone a prueba el tratamiento de errores al que las pruebas ordinarias rara vez llegan. Una campaña especifica el modelo de fallos (qué fallos y con qué tasas), el sistema bajo prueba, el oráculo (cuál es el comportamiento correcto ante cada fallo) y las mediciones. Para el TMRP, la campaña sobre el receptor de este capítulo inyecta corrupción, reproducción, retraso y descartes. Cada fallo tiene un oráculo. Los resultados se cuentan por clase.

40.2 Oráculos y clasificación

Para cada fallo inyectado, defina el resultado esperado: corrompido → rechazado como corrupto; reproducido → rechazado como reproducción; retrasado más allá de la ventana de frescura → rechazado como obsoleto; descartado → detectado como un hueco (o no, si el diseño no detecta huecos). Clasifique los resultados observados frente a los esperados. Un fallo que produce «ok» cuando debería haberse rechazado es un fallo silencioso, la clase más importante que hay que encontrar. Para el receptor del TMRP, la clase de descartes es aquella en la que el oráculo puso al descubierto una laguna: el diseño no tenía un resultado esperado para un mensaje perdido, porque nadie había preguntado qué debía ocurrir.

40.3 Semillas, tasas y cobertura

Fije la semilla del generador de fallos, regístrela e informe de los recuentos por clase de fallo. Elija tasas que produzcan suficientes eventos de cada clase para que sean significativos; una campaña de 500 mensajes con un 5 % por clase de fallo da unos 25 eventos de cada una, suficientes para encontrar fallos sistemáticos, pero no para estimar con precisión los raros. Amplíe la campaña para las clases que preocupen especialmente. La campaña del TMRP usa la semilla cuarenta, quinientos mensajes y un cinco por ciento por clase de fallo, de modo que cada clase produce suficientes eventos para mostrar un comportamiento sistemático. El proyecto final amplía la campaña a diez mil mensajes en siete clases de fallo, incluidos el reinicio y la reordenación.

40.4 Ejemplo resuelto: campaña sobre el receptor de telemetría (sintético)

El laboratorio 15 envía 500 mensajes con la semilla 40; cada uno tiene un 80 % de probabilidad de no tener fallo y un 5 % de cada uno de los siguientes: corrupción, reproducción de un mensaje válido anterior, un retraso de 120 s (ventana de frescura de 60 s) y descarte. Resultados: todos los mensajes corrompidos se rechazaron como corruptos; todas las reproducciones, como reproducción; todos los mensajes retrasados, como obsoletos; ningún fallo produjo un «ok» silencioso. Pero los descartes son invisibles para el receptor: se perdieron 21 mensajes y el receptor no señaló nada. La comprobación de contadores del receptor rechaza los contadores antiguos, pero no alarma ante los huecos. El requisito R7 (alarmas en 60 s) implica que la pérdida de los datos de una estación debe ser visible en sí misma. Cambio de diseño: alarmar cuando no llegue ningún mensaje válido de una estación durante 60 s y registrar los huecos de contador. La campaña se vuelve a ejecutar tras el cambio con la misma semilla.

40.5 Actividad práctica: laboratorio 15

# Lab 15 - fault-injection campaign against the telemetry receiver (synthetic, seeded, offline)
import random, hmac, hashlib, struct
KEY = b"k" * 32
def seal(c, lvl, ts):
    b = struct.pack(">QHI", c, lvl, ts); return b + hmac.new(KEY, b, hashlib.sha256).digest()[:16]
def receive(m, state, now, max_age=60):
    b, tag = m[:14], m[14:]
    if len(m) != 30 or not hmac.compare_digest(tag, hmac.new(KEY, b, hashlib.sha256).digest()[:16]): return "corrupt"
    c, lvl, ts = struct.unpack(">QHI", b)
    if c <= state["last"]: return "replay"
    if now - ts > max_age: return "stale"
    state["last"] = c; return "ok"
rng = random.Random(40); state = {"last": 0}; tally = {}; sent = []
for i in range(1, 501):
    now = 10 * i; m = seal(i, 300, now); fault = rng.choices(["none", "corrupt", "replay", "delay", "drop"], [80, 5, 5, 5, 5])[0]
    if fault == "corrupt": m = m[:5] + bytes([m[5] ^ 0x10]) + m[6:]
    if fault == "replay" and sent: m = rng.choice(sent)
    if fault == "drop": tally[("drop", "lost")] = tally.get(("drop", "lost"), 0) + 1; continue
    arrive = now + (120 if fault == "delay" else 1)
    out = receive(m, state, arrive)
    tally[(fault, out)] = tally.get((fault, out), 0) + 1
    if fault == "none": sent.append(m)
for k in sorted(tally): print(k, tally[k])

Salida esperada:

('corrupt', 'corrupt') 14
('delay', 'stale') 22
('drop', 'lost') 21
('none', 'ok') 419
('replay', 'replay') 24

Todos los mensajes corrompidos, reproducidos y retrasados acabaron en la clase que predecía su oráculo, y ningún fallo produjo una aceptación silenciosa. Los mensajes descartados son el hallazgo: se perdieron veintiuno y el receptor no señaló nada, porque las comprobaciones de contadores solo rechazan mensajes antiguos. Ese resultado dio lugar a la alarma de estación sin datos, que salta cuando no llega ningún mensaje válido de una estación durante sesenta segundos, y al hallazgo de revisión F2. Después, la campaña se vuelve a ejecutar con la misma semilla para confirmar el cambio.

40.6 Errores comunes y límites

La primera campaña del TMRP mostró el primer error: los descartes eran silenciosos porque los diseñadores nunca incluyeron la pérdida de datos entre los fallos que su receptor debía advertir. Volver a ejecutarla tras añadir la alarma de estación sin datos es la forma de confirmar la corrección. Su semilla está registrada, así que la nueva ejecución es comparable. La clase de descartes se mantiene ahora en todas las ejecuciones.

Ejercicios — capítulo 40

EX079 — Detección de huecos. Objetivo: cerrar la laguna de los descartes. Entradas: laboratorio 15. Pasos: añada la detección de huecos (un salto de contador mayor que 1 registra gap) y vuelva a ejecutar con la misma semilla; informe de cuántos eventos de hueco se registran y de por qué el número puede diferir del número de descartes. Evidencia esperada: código y salida. Rúbrica: 3 = implementado correctamente; explica que los descartes consecutivos producen un único evento de hueco y que las reproducciones y los mensajes rechazados también afectan a la continuidad de los contadores; 2 = implementado, sin explicación; 1 = no ejecutado; 0 = nada.

EX080 — Ampliar el modelo de fallos. Objetivo: añadir fallos. Entradas: laboratorio 15. Pasos: añada dos clases de fallo, la reordenación (intercambiar dos mensajes consecutivos) y el reinicio del receptor (restablecer state), defina los oráculos, ejecute e informe de los fallos silenciosos. Evidencia esperada: código, oráculos y resultados. Rúbrica: 3 = la reordenación hace que el mensaje anterior se rechace como reproducción (aceptable o no, de forma argumentada), el reinicio permite reproducciones (fallo silencioso) salvo que el estado se conserve; 2 = una clase; 1 = sin oráculo; 0 = nada.

Síntesis del capítulo

La inyección de fallos ejercita el tratamiento de errores que las pruebas ordinarias no alcanzan. Defina de antemano el modelo de fallos y el oráculo, fije la semilla y cuente, clasifique los resultados y busque los fallos silenciosos. El laboratorio 15 muestra el resultado típico: el control rechaza lo que se diseñó para rechazar y es ciego a lo que nadie incluyó en la lista, aquí la pérdida de datos.

Siga estudiando — capítulo 40 de 50

← Capítulo 39 · Índice de capítulos del curso · Capítulo 41 →

Continúe con la siguiente lección escrita.