FreeDom

Modelo de amenazas — Freedom

Hito 5 — Auditoría y doctrina anti-vigilancia. Documento vivo: se actualiza con cada módulo. Es el mapa entre qué tememos y qué lo mitiga en el código real.

1. Activos a proteger

  1. Confidencialidad del usuario: qué navega, su IP, su identidad, su huella (fingerprint).
  2. Integridad del cliente: que contenido remoto hostil no logre ejecución fuera del sandbox, exfiltración ni persistencia.
  3. Disponibilidad: que una página no pueda colgar ni agotar la memoria del navegador.
  4. Estado local: caché, marcadores, credenciales (cifrados en reposo — local_store + disk_store).

2. Adversarios considerados

3. Fronteras de confianza y mitigaciones (mapa a módulos)

Frontera Amenaza Mitigación Módulo
Red ↔ navegador A2 (MITM, HNDL) TLS 1.3 mínimo; KE híbrido PQ obligatorio (X25519MLKEM768); rechazo de RSA<3072/SHA-1; fail-closed secure_fetch
Red ↔ navegador A3 (terceros) Bloqueo de terceros por defecto (no representable permitirlos); eTLD+1 vía PSL completa (ICANN+PRIVATE) request_policy, psl_data
JS ↔ otro origen A1/A3 (exfiltración cross-origin / CORS) No hay lectura cross-origin para JS por construcción: sin fetch/XMLHttpRequest/WebSocket/sendBeacon/Image, sin iframe/contexto anidado, sin window.open/postMessage/opener; readback de canvas/audio envenenado (nunca píxeles reales); el worker no tiene red (CLONE_NEWNET+seccomp). document.cookie presente pero vacío (Zero Knowledge). Por eso la SOP clásica (leer la respuesta de otro origen) es estructuralmente imposible y CORS (cabeceras ACAO) es irrelevante (no hay petición cross-origin de JS que negociar). Los subrecursos de imagen (opt-in) sí pueden ser cross-origin (“cargar todo menos trackers”, rp_evaluate→píxel 1×1 bloqueado): es un faro de salida deliberado, no una fuga de confidencialidad (no hay dato sensible accesible). Test de regresión: typeof fetch === 'undefined' (etc.) — si alguien añade una API de red, falla y obliga a añadir CORS con ella. js_env, js_dom, request_policy, render_policy, tab
Lectura JS ↔ identidad A3 (fingerprint) Identidad normalizada (UA/locale/TZ/cores/mem), coarsening de relojes, bucketing de pantalla, perturbación de canvas/audio por sesión anti_fp
Bindings JS ↔ identidad A3 (fingerprint) Cableado de anti_fp a navigator/screen/performance (sellados, infalsificables) + Date.now engrosado + canvas/audio con readback envenenado por sesión js_env
Pestaña ↔ pestaña / UI A1 (post-explotación / fuga cross-pestaña) Worker por pestaña fork + exec (re-ejecuta /proc/self/exe): sin herencia COW del padre → un worker comprometido no ve el contenido de las otras pestañas (tab_slots[]), ASLR fresca, higiene de fds (close_range, solo los 2 pipes sobreviven); parseo + DOM + JS hostil en hijo confinado; IPC framed; el padre nunca toca los bytes y sobrevive a un hijo caído (TAB_ERR_DEAD), ignora SIGPIPE, valida longitudes tab
Contenido → DOM A1 (scripts/handlers) Árbol inerte: strip de <script> y on*; recorrido iterativo (anti stack-overflow); fuzzing html_parse, dom
DOM → motor JS A1 (escape de sandbox) Motor sin I/O (sin std/os/require); límites de memoria/pila/tiempo; superficie nativa mínima y handles validados (sin objetos vivos) js_sandbox, js_dom
Proceso ↔ kernel A1 (post-explotación) seccomp-bpf fail-closed: lista blanca de syscalls; sin open/socket/execve/ptrace. io_uring prohibido (io_uring_setup/enter/register fuera del allowlist → SIGSYS): es una primitiva de bypass de seccomp (sus IORING_OP_* no atraviesan el syscall entry que el BPF filtra), por eso —como Docker/ChromeOS/Android— jamás entra, ni “para E/S asíncrona”; la doctrina io_uring (§3) es solo del lado confiable. W^X (inspección de argumento: mmap/mprotect con PROT_EXEC denegados → sin shellcode nativo aun tras secuestro de control) + anti-volcado (PR_SET_DUMPABLE=0 + RLIMIT_CORE=0 → sin core ni ptrace ajeno que exfiltre secretos). x86_64 y aarch64 LE (BE excluido, fail-closed). Test de regresión: io_uring_setup ⇒ SIGSYS y os_policy_allows(__NR_io_uring_*)=0 — candadea la invariante deny-by-default os_sandbox
Proceso ↔ filesystem A1 (post-explotación) Landlock (niega todo el FS) como defensa en profundidad, antes de seccomp; best-effort (seccomp ya excluye open) os_sandbox, tab
Estado local ↔ disco A3 / robo del dispositivo Cifrado en reposo AES-256-GCM/ChaCha20-Poly1305 + Argon2id, fail-closed; escritura atómica con permisos 0600 local_store, disk_store
Navegador ↔ escritorio A4 (keylogging) Solo Wayland, nunca X11 (aislamiento de clientes por el compositor) ui
Disponibilidad A1 (DoS) Cuerpo HTTP acotado; entrada HTML acotada; presupuesto de tiempo/memoria en JS secure_fetch, html_parse, js_sandbox

4. Doctrina aplicada

5. Riesgo residual / trabajo pendiente

Cerrado desde la última revisión:

Pendiente:

6. Cómo se verifica

Cada mitigación tiene pruebas: make test (167 pruebas unitarias en 14 suites), make asan (ASan+UBSan limpio), fuzzing (make fuzz, make fuzz-js), e integración de red (make itest, negocia X25519MLKEM768 real). El aislamiento de tab ejercita QuickJS + Lexbor bajo seccomp en el hijo confinado. Ninguna garantía se declara “verificada” sin una prueba que la ejercite.