01 · Proteger el sistema completo
Qué debe proteger un dispositivo IoT
Los temas anteriores conectaron sensores, APIs, órdenes y un gemelo de estado. Cada función abre una posibilidad de uso y una responsabilidad de protección. Una lectura falsa puede ocultar un incidente; una credencial compartida puede permitir suplantar otro equipo; un servicio sin límites puede impedir que el firmware siga adquiriendo.
| Objetivo | Pregunta | Ejemplo en el curso |
|---|---|---|
| Confidencialidad | ¿Quién puede conocer la información? | Evitar exponer credenciales o datos de otro cliente |
| Integridad | ¿Quién puede modificarla y cómo se detectan cambios? | No aceptar una configuración alterada o un firmware no autorizado |
| Disponibilidad | ¿El servicio necesario sigue funcionando? | La adquisición y el control local no se paralizan por una ráfaga de solicitudes |
| Trazabilidad | ¿Qué evidencia queda de las decisiones? | Quién pidió un cambio y por qué se admitió o rechazó |
La seguridad se diseña junto con el comportamiento del producto. Ante una conexión no confiable, el equipo puede rechazar nuevas órdenes y conservar el control local previsto. El rechazo no debe activar una salida por defecto ni borrar silenciosamente su configuración válida.
Una referencia de diseño es NIST IR 8259A, publicada en 2020: reúne capacidades de identificación, configuración, protección de datos, acceso lógico a interfaces, actualización y conocimiento del estado de ciberseguridad. Este tema las aplica como preguntas de ingeniería; ejecutar sus ejemplos no constituye una certificación.
El tema 41 profundiza cifrado, TLS y certificados; el 42, credenciales y aprovisionamiento. Aquí construimos el mapa general y las comprobaciones que deben seguir existiendo aunque se use un transporte cifrado.
02 · Preguntar antes de elegir controles
Un modelo de amenazas pequeño
Un modelo de amenazas describe qué querés proteger, quién podría afectar eso y por qué camino. No hace falta empezar con una lista interminable: una tabla de tu sistema concreto suele revelar decisiones importantes.
| Activo | Situación que importa | Control a revisar |
|---|---|---|
| Identidad del equipo | Otro dispositivo publica como cámara 07 | Credencial individual y vínculo entre identidad y recurso |
| Órdenes de salida | Un lector de telemetría intenta activar | Permisos por operación y validaciones locales |
| Configuración | Se cambia un umbral fuera de su rango | Autorización, validación y versión aplicada |
| Disponibilidad | Mensajes enormes o demasiadas solicitudes | Límites de tamaño, frecuencia, cola y tiempo |
| Firmware y secretos | Se reemplaza software o se extraen credenciales | Cadena de actualización, almacenamiento y protección física apropiada |
| Operación y soporte | Se filtra una credencial o se retira el equipo | Revocación, rotación y baja verificable |
Distinguir capacidades del adversario
No es igual alguien en Internet, alguien dentro de la red local, un usuario autenticado con permisos insuficientes o alguien que accede físicamente a la placa. Un dispositivo comprometido también puede tener credenciales válidas. Autenticarlo no vuelve confiables todos sus datos ni le concede autoridad sobre la flota.
Considerá fallas no deliberadas: un firmware que reintenta sin límite, un reloj perdido o un cliente que manda una carga mal formada pueden producir efectos parecidos a un abuso. Los controles de validación y recursos ayudan en ambos casos.
Priorizá por consecuencias y exposición: qué acción puede afectar el proceso, qué secretos abren otros recursos y qué entradas quedan accesibles. La etiqueta «solo es un sensor» no describe su acceso a la red, a la plataforma ni a las credenciales.
03 · Menos entradas innecesarias
Superficie de ataque y exposición
La superficie de ataque es el conjunto de interfaces y comportamientos por los que se puede interactuar con el sistema. Incluye servicios de red, configuración inicial, actualizaciones, puertos de depuración, archivos, dependencias y canales de soporte.
- Servicios de red: servidor web, MQTT, BLE de configuración y cualquier puerto de administración.
- Entradas de datos: JSON, tópicos, rutas, tamaños de archivo, parámetros y mensajes retenidos.
- Interfaces físicas: consola serial, depuración y almacenamiento extraíble según el hardware.
- Cadena de software: bibliotecas, firmware descargado y herramientas que publican actualizaciones.
- Plataforma: API, broker, base de datos, panel y cuentas administrativas.
Inventariá qué necesita estar activo en operación. Una consola abierta para desarrollo no tiene por qué seguir expuesta en un equipo desplegado. Un modo de configuración puede tener una activación local, duración limitada y permisos propios, en lugar de quedar disponible indefinidamente.
Una red privada no sustituye los controles
Estar detrás de NAT o en una Wi-Fi con contraseña reduce ciertos accesos, pero no verifica quién publica una orden en el broker ni qué puede hacer un equipo interno. Segmentación y reglas de red limitan caminos; identidad y autorización limitan acciones.
Si el producto solo necesita iniciar conexiones hacia un servicio, no se abre automáticamente un puerto entrante del router para administrarlo. La arquitectura de control del tema 37 funciona con conexiones iniciadas por el dispositivo y un servicio que aplica permisos.
La revisión también incluye versiones y dependencias. Se registra qué software contiene la imagen y cómo se sabrá que una vulnerabilidad aplicable requiere actualización. El inventario se mantiene durante el soporte, no solo el día de fabricación.
04 · Saber quién se presenta
Identidad y credenciales por defecto
Un nombre de dispositivo es un identificador; no es una prueba de identidad. El campo device="07", una dirección MAC o un tópico elegido por el emisor no reemplazan una credencial verificada.
Una contraseña conocida de fábrica o una misma clave incrustada en todas las unidades amplía el impacto de una filtración. Si todos actúan como la misma cuenta con acceso a la flota, conocer el secreto de un equipo puede dar autoridad sobre otros.
Credenciales por equipo y permisos pequeños
Cada unidad debería poder identificarse de manera individual y revocarse sin retirar las credenciales de todas las demás. El servicio liga esa identidad con recursos concretos. El mecanismo puede usar certificados o tokens apropiados al entorno; su emisión, protección y rotación se desarrollan en el tema 42.
device_id = aux07
credential_ref = identidad-aprovisionada-07
publish_allowed = sitioA/07/tel
subscribe_allowed = sitioA/07/cmd
La referencia indica dónde obtener la credencial.
No contiene una contraseña ni una clave privada.El firmware no necesita llevar la cuenta administrativa del broker ni de la base. Las credenciales de dispositivos, usuarios y servicios cumplen funciones distintas. Tampoco se colocan claves privadas en código publicado, HTML del panel, mensajes de diagnóstico o ejemplos que luego se copian a producción.
Revocar también cambia el servicio
La revocación debe traducirse en una política efectiva: impedir nuevas autenticaciones y resolver sesiones ya abiertas según el mecanismo usado. Borrar un texto en el panel no garantiza que una conexión autenticada anterior haya perdido acceso.
El almacenamiento local depende del equipo y del riesgo físico. Guardar un secreto en un archivo con otro nombre no lo cifra. Las capacidades de protección del microcontrolador y su proceso de aprovisionamiento deben evaluarse antes de prometer resistencia a extracción.
05 · Identidad no equivale a autoridad
Autenticación y autorización
Autenticar establece una identidad mediante un mecanismo verificado. Autorizar decide si esa identidad puede hacer una operación sobre un recurso. Un equipo 08 correctamente autenticado no debería publicar datos como 07 ni enviarle órdenes.
| Identidad | Permiso | No incluye |
|---|---|---|
| equipo07 | Publicar en sitioA/07/tel | Órdenes o recursos de equipo08 |
| equipo08 | Publicar en sitioA/08/tel | Suplantar la telemetría de 07 |
| operador | Solicitar en sitioA/07/cmd | Otros sitios o administración de identidades |
El servicio niega por defecto y comprueba el permiso en cada operación relevante, incluyendo API, broker y acceso a resultados. Un ID difícil de adivinar no reemplaza esa comprobación. La guía de autorización de OWASP desarrolla privilegio mínimo, denegación por defecto y verificación por solicitud.
El alcance sale del contexto confiable
Los permisos se obtienen de la identidad autenticada y de la política del servicio. No se aceptan porque la carga diga "role":"admin". La ruta o el tópico solicitado se contrasta con esa política; si el cuerpo también trae destinatario, ambos deben ser coherentes.
Una ACL de MQTT se revisa en ambas direcciones: publicación y suscripción. Un comodín amplio puede permitir acceder a todos los dispositivos o recibir órdenes de otros. El ejemplo usa recursos exactos para que el alcance sea visible; una política real también cubre los canales de estado, resultados y configuración necesarios.
Las restricciones locales del tema 37 siguen siendo necesarias. Un operador autorizado para solicitar ON no obtiene por eso permiso para ignorar un interbloqueo o superar la duración máxima.
06 · Proteger el canal y el significado
Proteger datos y validar mensajes
La conexión debe proteger confidencialidad e integridad y comprobar la identidad del extremo. Cifrar mientras se acepta cualquier servidor permite conectar con uno que no corresponde. La verificación de certificados, nombre y cadena de confianza se estudia en el tema 41.
Un canal autenticado tampoco valida automáticamente el contenido. Un equipo legítimo puede mandar datos fuera de rango o un comando mal formado. Se comprueban tipos, campos, unidad, longitud, operación y coherencia con el recurso autorizado.
| Comprobación | Ejemplo | Qué evita |
|---|---|---|
| Tamaño real de entrada | Máximo 512 bytes antes de interpretar JSON | Reservas de memoria sin límite |
| Esquema y tipos | Versión entera 1; duración entera, no booleano | Interpretaciones ambiguas |
| Lista de operaciones permitidas | set_output con argumentos definidos | Ejecutar instrucciones arbitrarias recibidas como texto |
| Rango y coherencia | Entre 1 y 10 segundos, equipo correcto | Acciones fuera de contrato |
| Identidad y vigencia | Reintento conocido o solicitud nueva todavía admisible | Reaplicar o admitir órdenes viejas |
Se interpreta el formato con un parser y se valida el resultado, en lugar de evaluar texto recibido como código. La guía de validación de OWASP distingue validación sintáctica y semántica y recomienda especificar entradas permitidas.
La deduplicación del tema 38 no autentica un comando: alguien que no tiene permiso no debe consultar su resultado ni provocar trabajo de ejecución. Para una identidad conocida con el mismo contenido se puede recuperar el resultado, incluso después del plazo de admisión original. Una solicitud nueva vencida no se aplica.
Un CRC detecta ciertas alteraciones accidentales, pero no prueba quién creó los datos: quien puede cambiarlos puede recalcularlo. Autenticación criptográfica, cifrado y comprobación de errores tienen propósitos diferentes.
07 · Poder seguir funcionando
Disponibilidad y límites de recursos
Un microcontrolador tiene memoria, CPU, conexiones y almacenamiento acotados. El sistema limita cargas, solicitudes simultáneas, colas, tiempo de espera, reintentos y registros. Una ráfaga no debería dejar sin oportunidad de ejecución a la adquisición y al control local.
- Tamaño: revisar bytes realmente recibidos antes de reservar o interpretar una carga grande.
- Frecuencia: cuotas por identidad, recurso y servicio, con ventanas y respuestas definidas.
- Concurrencia y tiempo: limitar tareas pendientes y conexiones que no progresan.
- Colas: capacidad, prioridad y descarte explícitos; reservar atención para eventos importantes.
- Registros: tamaño y retención para que una repetición de errores no llene la flash.
El laboratorio usa una cuota de tres admisiones nuevas por diez segundos y un máximo de 512 B. Son límites didácticos, no valores universales. Las consultas de resultados, los duplicados y la autenticación también necesitan sus propios presupuestos; una cuota de comandos nuevos no protege todo el trabajo del servidor.
La respuesta al límite no activa nada ni reinicia un temporizador de salida. Se conserva el estado local previsto y se informa la causa cuando el canal lo permite. Los reintentos del cliente respetan la política de espera, en lugar de aumentar la carga inmediatamente.
Disponibilidad con comportamiento previsible
Un error de seguridad o una caída de la nube no elimina las reglas locales del proceso. El equipo define cómo continuar o desactivar según su función. Esa decisión se verifica con las condiciones eléctricas y físicas del producto, además del software de comunicaciones.
08 · Mantener la protección
Firmware, mantenimiento y recuperación
La seguridad incluye instalar, operar, actualizar y retirar el dispositivo. Un producto necesita saber qué versión tiene cada equipo, cómo reconocer software autorizado, cómo recuperar una actualización fallida y hasta cuándo recibirá mantenimiento.
En plataformas ESP32, las funciones disponibles dependen de la variante y del entorno. La visión de seguridad de ESP-IDF organiza protección del software, identidad, almacenamiento y comunicación. Secure Boot verifica autenticidad de software; el cifrado de flash tiene otro propósito. Ninguno sustituye la autorización de una orden.
Estas opciones se planifican junto con generación y custodia de claves, recuperación, depuración y fabricación. Algunas configuraciones de hardware son definitivas; no se activan como una receta genérica sin revisar la variante y el proceso. Los temas de OTA y actualización segura profundizan esa etapa.
Registrar decisiones sin filtrar secretos
Se puede registrar identidad verificada, recurso, operación, resultado, causa y tiempo. No se guardan contraseñas, tokens completos, claves privadas ni cargas enteras por costumbre. Los registros tienen permisos y retención; el soporte no necesita todos los secretos para explicar un rechazo.
Un intento anónimo se registra como identidad no verificada, aunque su cuerpo diga «operador». Una auditoría que copia ese texto como si fuese una identidad autenticada también puede inducir a error.
Responder a una credencial comprometida
La operación debe poder localizar el alcance, revocar o limitar la identidad, revisar cambios y aprovisionar una sustitución. Al retirar un equipo se revocan accesos y se resuelven datos y secretos que queden en su almacenamiento. Una restauración de fábrica no basta si la credencial sigue autorizada en el servicio.
09 · Una barrera concreta
Un validador ejecutable en Python
Este bloque valida una orden de demostración. El destinatario esperado viene de una ruta ya autorizada, no de un rol afirmado por el cuerpo. La función solo comprueba formato y coherencia: no autentica, no cifra, no ejecuta y no reemplaza el registro de comandos.
Python en el navegador. Los dos bloques son independientes y no acceden a una red ni a dispositivos. Podés editarlos y ejecutarlos con Pyodide o con Python 3 local.
import json
import re
def objeto_sin_duplicados(pares):
resultado = {}
for clave, valor in pares:
if clave in resultado:
raise ValueError("Clave JSON repetida")
resultado[clave] = valor
return resultado
def constante_invalida(valor):
raise ValueError("Constante JSON no admitida")
def validar_orden(raw, destino_autorizado):
if type(raw) is not bytes or len(raw) > 512:
raise ValueError("Tipo o tamaño de entrada inválido")
d = json.loads(raw.decode("utf-8"), object_pairs_hook=objeto_sin_duplicados,
parse_constant=constante_invalida)
campos = {"v", "id", "target", "op", "duration_s", "expires_s"}
if type(d) is not dict or set(d) != campos:
raise ValueError("Campos no admitidos")
if type(d["v"]) is not int or d["v"] != 1:
raise ValueError("Versión inválida")
if type(d["id"]) is not str or not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", d["id"]):
raise ValueError("Identidad de comando inválida")
if type(d["target"]) is not str or d["target"] != destino_autorizado:
raise ValueError("Destinatario incompatible con el recurso autorizado")
if d["op"] != "set_output":
raise ValueError("Operación no admitida")
if type(d["duration_s"]) is not int or not 1 <= d["duration_s"] <= 10:
raise ValueError("Duración inválida")
if type(d["expires_s"]) is not int or d["expires_s"] <= 0:
raise ValueError("Vencimiento inválido")
return d
valida = dict(v=1, id="cmd-demo", target="07", op="set_output", duration_s=5, expires_s=20)
raw = json.dumps(valida).encode("utf-8")
assert validar_orden(raw, "07")["duration_s"] == 5
invalidas = [
json.dumps(dict(valida, duration_s=True)).encode(),
json.dumps(dict(valida, target="08")).encode(),
json.dumps(dict(valida, role="admin")).encode(),
b'{"id":"A","id":"B"}',
b" " * 513,
b'{"duration_s":NaN}',
bytes([255])
]
for entrada in invalidas:
try:
validar_orden(entrada, "07")
except ValueError:
pass
else:
raise AssertionError("Se aceptó una entrada inválida")
print("8 comprobaciones superadas.")
print("Una orden estructuralmente válida todavía necesita identidad, permiso y admisión.")El límite se calcula con la longitud real de raw, antes de interpretar JSON. No se confía en un campo de la carga que afirme «mido 120 bytes». En un servidor se acota también lo que se recibe del transporte, para no acumular primero un cuerpo ilimitado.
Se usa type(x) is int porque en Python un booleano también puede pasar ciertas comprobaciones basadas en enteros. Los nombres duplicados y las constantes no válidas se rechazan para evitar interpretaciones diferentes entre componentes.
expires_s usa un reloj relativo solo para esta demostración. Comprobar su vencimiento corresponde a la admisión de una orden nueva con una referencia temporal confiable, después de reconocer si existe un resultado de esa identidad. Un resultado guardado puede consultarse sin volver a ejecutar.
10 · Decisiones por capas
Modelo de controles por capas
El siguiente modelo reúne comprobaciones del cliente, del servicio y del protocolo de comandos. Las identidades y la verificación del servidor son resultados simulados de mecanismos externos: en producción salen de bibliotecas y credenciales verificadas, nunca de booleanos que un cliente escribe en su JSON.
Cada fila es un caso independiente, con contexto previo definido. La fila de cuota indica que ya hubo tres admisiones en esa ventana; la de reentrega trae un registro conocido. No se genera tráfico ni se prueban hosts. El rastro de decisiones reúne las distintas capas del modelo: una conexión detenida por el cliente antes de enviar no produciría por eso un registro de solicitud en el servidor real.
def casos():
base = dict(principal="equipo07", autenticada=True, revocada=False, servidorValido=True,
recurso="sitioA/07/tel", tipo="tel", bytes=120, valor=41, duracion=5,
vence=20, anteriores=0, conocida=False, igual=True, legitima=False)
def caso(nombre, **cambios):
return dict(base, nombre=nombre, **cambios)
operador = dict(principal="operador", recurso="sitioA/07/cmd", tipo="cmd")
return [
caso("Telemetría propia", legitima=True),
caso("Orden autorizada", **operador, legitima=True),
caso("Emisor anónimo", **operador, autenticada=False),
caso("Equipo 08 publica como 07", principal="equipo08"),
caso("Un sensor publica una orden", recurso="sitioA/07/cmd", tipo="cmd"),
caso("Credencial revocada", revocada=True),
caso("Orden nueva vencida", **operador, vence=9),
caso("Valor fuera de rango", valor=5000),
caso("Carga demasiado grande", **operador, bytes=4096),
caso("Cuota de ventana agotada", anteriores=3),
caso("Servidor no verificado", **operador, servidorValido=False),
caso("Reentrega legítima conocida", **operador, conocida=True, legitima=True),
caso("Mismo ID, otro contenido", **operador, conocida=True, igual=False),
caso("Operador fuera de su sitio", **dict(operador, recurso="sitioB/07/cmd"))
]
def evaluar(tls=True, autenticacion=True, autorizacion=True, validacion=True,
limites=True, deduplicacion=True, auditoria=True):
permisos = {"equipo07": ["sitioA/07/tel"], "equipo08": ["sitioA/08/tel"],
"operador": ["sitioA/07/cmd"]}
filas, registros = [], []
for i, c in enumerate(casos()):
permitido = nueva = False
confiable = autenticacion and c["autenticada"] and not c["revocada"]
if tls and not c["servidorValido"]:
barrera, resultado = "TLS", "No iniciar intercambio con servidor no verificado"
elif limites and c["bytes"] > 512:
barrera, resultado = "Tamaño", "Carga supera 512 B"
elif autenticacion and (not c["autenticada"] or c["revocada"]):
barrera = "Autenticación"
resultado = "Credencial revocada" if c["revocada"] else "Identidad no verificada"
elif autorizacion and (not confiable or c["recurso"] not in permisos.get(c["principal"], [])):
barrera, resultado = "Autorización", "Sin permiso sobre este recurso y operación"
elif validacion and ((c["tipo"] == "tel" and not -400 <= c["valor"] <= 1250) or
(c["tipo"] == "cmd" and not 1 <= c["duracion"] <= 10)):
barrera, resultado = "Validación", "Datos fuera del contrato"
elif deduplicacion and c["conocida"] and not c["igual"]:
barrera, resultado = "Identidad de comando", "Conflicto: no reemplazar el contenido original"
elif deduplicacion and c["conocida"]:
permitido = True
barrera, resultado = "Resultado guardado", "Reentrega reconocida sin nueva aplicación"
elif validacion and c["tipo"] == "cmd" and c["vence"] <= 10:
barrera, resultado = "Vigencia", "No admitir una orden nueva vencida"
elif limites and c["anteriores"] >= 3:
barrera, resultado = "Cuota", "Ventana de 10 s: tres admisiones ya consumidas"
else:
permitido, nueva = True, c["tipo"] == "cmd"
barrera = "Admisión"
resultado = "Nueva aplicación simulada" if nueva else "Telemetría admitida"
filas.append(dict(nombre=c["nombre"], permitido=permitido, nueva=nueva,
barrera=barrera, resultado=resultado, legitima=c["legitima"],
reaplicacion=nueva and c["conocida"]))
if auditoria:
registros.append(dict(intento=i+1, principal=c["principal"] if confiable and barrera not in ("TLS", "Tamaño") else "no_verificada",
recurso=c["recurso"], decision="permitir" if permitido else "denegar", etapa=barrera))
return dict(filas=filas, registros=registros,
admitidas=sum(f["permitido"] for f in filas),
bloqueadas=sum(not f["permitido"] for f in filas),
indebidas=sum(f["permitido"] and not f["legitima"] for f in filas),
reaplicaciones=sum(f["reaplicacion"] for f in filas),
legitimasBloqueadas=sum(not f["permitido"] and f["legitima"] for f in filas))
base = evaluar()
for f in base["filas"]:
print(f'{f["nombre"]:30} {"ADMITIDA" if f["permitido"] else "BLOQUEADA":9} {f["barrera"]}')
assert (base["admitidas"], base["bloqueadas"], base["indebidas"]) == (3, 11, 0)
assert base["reaplicaciones"] == 0
assert base["legitimasBloqueadas"] == 0
assert len(base["registros"]) == 14
assert evaluar(autorizacion=False)["indebidas"] == 3
assert evaluar(validacion=False)["indebidas"] == 2
assert evaluar(limites=False)["indebidas"] == 2
assert evaluar(deduplicacion=False)["reaplicaciones"] == 2
assert evaluar(tls=False)["indebidas"] == 1
assert evaluar(autenticacion=False)["legitimasBloqueadas"] == 3
assert evaluar(autenticacion=False, autorizacion=False)["indebidas"] == 5
assert evaluar(auditoria=False)["registros"] == []
print("\n12 comprobaciones superadas.")Con todas las barreras se admiten dos solicitudes nuevas legítimas y una reentrega conocida sin reaplicar. Se bloquean once casos y se producen catorce registros de decisión. Las doce comprobaciones terminan sin errores.
El campo bytes del modelo representa el tamaño observado por el simulador, no un dato confiado al emisor. Las banderas de identidad y servidor tampoco implementan criptografía. El validador anterior muestra una comprobación real sobre bytes; autenticación y TLS se integran con mecanismos adecuados a la plataforma.
El modelo muestra la primera barrera que detuvo cada caso. Eso no significa que las siguientes dejaran de ser necesarias. Una implementación verifica todo lo requerido antes de producir efectos y no confía en que otra capa siempre habrá filtrado el problema.
11 · Exploración interactiva
Decisiones de seguridad por escenario
Evaluá los catorce casos y quitá una barrera por vez. La comparación incluye usos legítimos para detectar también una política que bloquea todo. Cada ejecución es local; no usa contraseñas, certificados ni conexiones reales.
Política de una instalación de dos equipos
Preparando evaluación.
Decisiones de los casos
| Caso | Decisión | Etapa | Explicación |
|---|
Registro de decisiones simulado
| Intento | Identidad verificada | Recurso | Decisión | Etapa |
|---|
Recorrido guiado
- Con todo activo hay tres casos admitidos y once bloqueados. Los admitidos son telemetría propia, una orden autorizada y una reentrega que devuelve resultado sin aplicar otra vez.
- Quitá solo autorización. Se admiten tres casos indebidos: otro equipo publica como 07, un sensor publica órdenes y un operador accede a otro sitio. Todos podían tener una identidad válida.
- Restaurá y quitá validación. La orden nueva vencida y la temperatura fuera de rango pasan. Una credencial válida no convierte esos datos en correctos.
- Restaurá y quitá límites. Se admiten una carga de 4096 B y una solicitud cuando la cuota de admisiones ya estaba agotada.
- Restaurá y quitá deduplicación. La reentrega legítima vuelve a aplicar y el ID con contenido cambiado deja de detenerse en ese control. Hay dos reaplicaciones en estos casos independientes.
- Restaurá y quitá la verificación del servidor. El caso con servidor no verificado ya no se detiene. No hay una conexión real: el ejercicio muestra la decisión de confianza que faltaría.
- Quitá solo autenticación. La autorización conserva la exigencia de una identidad confiable y bloquea incluso los tres casos legítimos. Si también quitás autorización, pasan solicitudes anónimas o revocadas. Menos rechazos no significa mejor funcionamiento.
- Restaurá y quitá auditoría. Las decisiones no cambian, pero desaparece el registro de decisiones. La tabla de casos permanece porque pertenece al simulador, no porque existan logs reales.
La tabla enumera escenarios elegidos, no todos los ataques posibles. La protección física, el almacenamiento de secretos, la calidad de la implementación TLS y la recuperación de firmware no se prueban mediante estas casillas.
¿Por qué no se resume todo en una puntuación de seguridad?
Porque dos políticas con igual número de casos bloqueados pueden tener consecuencias distintas. Bloquear usuarios legítimos, admitir órdenes ajenas o perder trazabilidad son problemas diferentes. Se revisan las propiedades requeridas y sus pruebas, no solo un porcentaje.
12 · Un proceso de trabajo
Método y confusiones frecuentes
- Inventariá activos e interfaces: datos, salidas, secretos, servicios, puertos y dependencias.
- Definí actores y alcance: identidades distintas y acciones permitidas sobre recursos concretos.
- Reducí exposición: quitar funciones que no necesita el equipo en operación.
- Protegé el canal: verificar el extremo y mantener claves fuera del alcance que no las necesita.
- Validá antes del efecto: tamaños, esquema, semántica, identidad de comando y admisión.
- Acotá recursos: frecuencia, memoria, concurrencia, colas y retención de registros.
- Planificá el ciclo de vida: actualización, revocación, recuperación y retiro.
- Probá casos permitidos y prohibidos: también equipos de otro sitio, credenciales revocadas y entradas inválidas.
- Revisá la operación real: logs sin secretos, versiones conocidas y procedimientos que se puedan ejecutar.
«Está en mi Wi-Fi, así que puedo confiar en todo lo que mande»
La red puede contener clientes comprometidos o mal configurados. El servicio verifica identidad, permiso y contenido en cada operación relevante.
«TLS resuelve también los permisos de los usuarios»
Protege el canal y puede participar en la autenticación, pero la aplicación todavía decide qué recurso y operación autoriza a esa identidad.
«Un ID o una MAC difíciles de adivinar son una credencial»
Son identificadores. No prueban posesión de un secreto o de una clave verificada. Conocerlos no debería otorgar permisos.
«Una clave común simplifica todo sin cambiar el alcance de una filtración»
Si varias unidades comparten una identidad con autoridad amplia, comprometer una puede afectar a otras. La identidad individual y los permisos acotados permiten limitar y revocar por unidad.
«El parser aceptó JSON, entonces el comando es válido»
La sintaxis no valida tipo, unidad, rango, destinatario ni vigencia. Un objeto JSON perfectamente formado puede pedir una acción no permitida.
«Cuantos más datos guardo en logs, más seguro es el soporte»
Registrar secretos o cargas completas puede crear otra exposición y llenar el almacenamiento. Se guarda evidencia suficiente, con permisos y retención definidos.
«Revocar significa borrar la contraseña que muestra el panel»
La plataforma debe dejar de aceptar esa identidad y tratar las sesiones existentes según su política. El cambio de una pantalla no demuestra que el acceso haya terminado.
13 · Práctica guiada
Predecí antes de comprobar
1. Equipo autenticado, recurso equivocado
El equipo 08 tiene una credencial válida y publica en el tópico de telemetría de 07. ¿Qué control debe detenerlo?
Ver solución
La autorización por recurso y operación. La autenticación solo establece quién es; no lo autoriza a actuar como otro equipo.
2. Una clave compartida
Cien unidades usan la misma cuenta, que puede publicar en todos los tópicos. Se filtra el secreto de una. ¿Qué alcance tiene el problema y qué diseño lo limita?
Ver solución
Puede afectar a toda la autoridad de esa cuenta. Credenciales individuales y permisos por unidad reducen el alcance y permiten revocación selectiva, aunque cada equipo todavía requiere protección propia.
3. Longitud declarada
Una carga afirma medir 100 bytes, pero el transporte entrega 4096. El límite es 512. ¿Qué longitud se verifica?
Ver solución
Los bytes realmente recibidos, acotados durante la recepción y antes de interpretar la carga. El campo declarado por el emisor no controla el presupuesto de memoria.
4. Duración booleana
La operación exige un entero entre 1 y 10. El JSON trae "duration_s":true. ¿Se admite porque Python puede tratar true como 1?
Ver solución
No. El contrato requiere un entero, no un booleano. La comprobación de tipo debe reflejar esa distinción antes de usar su valor.
5. Canal cifrado con servidor no verificado
El dispositivo cifra, pero acepta cualquier servidor. ¿Qué propiedad falta antes de enviar credenciales?
Ver solución
Verificar la identidad del extremo mediante el mecanismo previsto: cadena de confianza, nombre y demás comprobaciones aplicables. Cifrar no demuestra que el destinatario sea el correcto.
6. Cuota agotada
La política admite tres solicitudes nuevas por ventana de diez segundos. Ya admitió tres. ¿Qué hace con una cuarta dentro de esa misma ventana?
Ver solución
La rechaza o difiere según la política explícita, sin ejecutar primero. Consultas y duplicados también necesitan límites propios para que no agoten otros recursos.
7. Auditoría de un anónimo
Una carga sin autenticación dice que pertenece al administrador. ¿Qué identidad queda en el registro confiable?
Ver solución
Identidad no verificada, junto con metadatos apropiados del intento. El texto afirmado por el cuerpo no se registra como una autenticación exitosa.
8. Retirar un dispositivo
Se restaura una placa a fábrica, pero su credencial sigue autorizada en el broker. ¿La baja está completa?
Ver solución
No. Se revoca el acceso en la plataforma y se trata el material que pueda seguir existiendo en el equipo o sus copias. Reiniciar la configuración local no elimina la autorización remota.
14 · Síntesis
Ideas para recordar
- La seguridad protege datos, identidad, operaciones y disponibilidad durante todo el ciclo de vida.
- Un modelo de amenazas relaciona activos, actores, entradas y consecuencias antes de elegir controles.
- Reducir servicios y permisos innecesarios limita la exposición y el alcance de una filtración.
- Identificar, autenticar y autorizar son tareas diferentes. Un identificador o una carga JSON no prueban identidad.
- Credenciales individuales permiten revocar y limitar por equipo; los secretos no se publican en código, paneles ni logs.
- El canal verificado no sustituye validación, vigencia, deduplicación ni límites locales.
- Las cargas, frecuencias, colas y registros tienen presupuestos explícitos para preservar disponibilidad.
- El laboratorio admite tres casos legítimos y bloquea once con todas las barreras; es una prueba de decisiones, no de la seguridad completa del producto.
¿Listo para el tema 41?
Antes de avanzar, dibujá las entradas de tu dispositivo y asigná identidad, permiso y límite a cada una. Revisá cómo se revoca una unidad, qué servicios siguen activos y qué información queda en los registros.
En el próximo tema, Cifrado, TLS y certificados, profundizamos cómo proteger las comunicaciones y verificar el extremo con el que habla el microcontrolador.