Al construir infraestructuras WebRTC a gran escala, la mayoría de los problemas en producción no se deben a un cifrado defectuoso ni a fallos en la negociación. Surgen de desajustes sutiles de estado entre componentes que, aunque funcionan correctamente por separado, acaban perdiendo sincronización con el paso del tiempo.
Uno de estos casos que investigamos recientemente implicaba errores intermitentes de autenticación SRTP durante el reenvío RTP en Janus. A primera vista parecía un problema criptográfico. En realidad, se trataba de una desincronización del contador de rollover provocada por la reutilización del SSRC por parte del navegador y solo se manifestaba tras varios minutos de transmisión continua de medios.
En este artículo te explicamos qué ocurrió, por qué sucede y cómo puedes solucionarlo de forma fiable en sistemas en producción.
Índice
-
El escenario
-
SRTP y el número de secuencia de 16 bits
-
Por qué el problema solo aparece tras varios minutos
-
Por qué el reenvío RTP es especialmente vulnerable
-
Cómo diagnosticar el problema
-
La solución práctica: forzar un nuevo SSRC
-
Por qué no intentar la resincronización del ROC
-
Consideraciones operativas
-
Lecciones para infraestructuras WebRTC
-
Reflexión final
El escenario
En un despliegue típico, Janus actúa como una unidad de reenvío selectivo (SFU), recibiendo medios cifrados de los participantes y reenviándolos a otros participantes, a sistemas externos, a flujos de grabación o a endpoints de difusión.
En condiciones normales, la cadena de medios funciona de forma fluida y predecible. Los flujos de audio y vídeo cifrados circulan de manera segura a través de SRTP, el reenvío RTP se establece con un SSRC claramente definido y los paquetes entrantes se autentican y descifran sin problemas. Mientras el estado del transporte se mantenga coherente en ambos extremos, el sistema conserva la integridad, la confidencialidad y una entrega estable de los medios durante toda la sesión.
Sin embargo, en determinadas circunstancias, el reenvío empezaba a fallar de forma repentina con errores similares a: SRTP unprotect error: srtp_err_status_auth_fail.
Curiosamente, esto no ocurría justo después de que un participante se uniera. Tampoco sucedía de forma constante en todas las sesiones. El fallo solo aparecía después de que el participante hubiera tenido la cámara o el micrófono activados durante varios minutos, los desactivara y posteriormente los volviera a activar, mientras el reenvío RTP seguía utilizando el SSRC original.
La clave para entender el problema está en cómo SRTP realiza el seguimiento de la integridad de los paquetes.
SRTP y el número de secuencia de 16 bits
SRTP protege los flujos RTP frente a ataques de repetición utilizando un índice de paquete construido a partir de dos elementos: el número de secuencia RTP de 16 bits y un contador de rollover (ROC).
El encabezado RTP incluye un número de secuencia de 16 bits que se incrementa en uno por cada paquete enviado. Esto permite al receptor detectar pérdida de paquetes, reordenar los que llegan fuera de orden e identificar duplicados. Sin embargo, al estar limitado a 16 bits, vuelve a cero tras 65.536 paquetes, lo que hace necesario un mecanismo de seguimiento del rollover en sesiones de medios más largas.
Ahí es donde entra el rollover counter. Cada vez que el número de secuencia de 16 bits se reinicia, el ROC se incrementa, ampliando el índice efectivo del paquete que SRTP utiliza para autenticación y protección frente a repeticiones. El número de secuencia y el ROC juntos forman un índice de 48 bits que se emplea para verificar la integridad de cada paquete.
Este diseño es sólido, pero introduce estado. Tanto el emisor como el receptor deben mantener la misma comprensión de la progresión actual de la secuencia y de cuántas veces se ha producido el rollover. Si no coinciden en el valor del ROC, la autenticación falla debido a suposiciones distintas sobre el índice real del paquete.
Un detalle clave es que, como el número de secuencia es de 16 bits, el primer rollover —y por tanto el primer incremento del ROC— no ocurre de inmediato. Con tasas habituales de paquetes en vídeo, pueden pasar varios minutos de transmisión continua antes de que el contador se reinicie.
Ese matiz temporal fue lo que hizo que este problema resultara especialmente sutil.
Por qué el problema solo aparece tras varios minutos
Durante la fase inicial de una sesión, el número de secuencia aumenta pero todavía no se reinicia. El ROC permanece en cero. Si en ese momento un participante desactiva y vuelve a activar su cámara, el comportamiento de la secuencia puede reiniciarse o desplazarse, pero la alineación del ROC suele seguir siendo recuperable porque ambos extremos siguen operando dentro de la primera ventana de 16 bits.
Sin embargo, una vez que se han transmitido suficientes paquetes como para que el número de secuencia se reinicie, tanto el emisor como el receptor incrementan su rollover counter al detectar que el contador de 16 bits ha vuelto a cero. A partir de ese momento, la autenticación SRTP depende de que ambos mantengan exactamente el mismo valor de ROC para calcular el índice de paquete.
Si más adelante el navegador reinicia los medios y restablece su estado interno de SRTP, pero reutiliza el mismo SSRC, el ROC del lado emisor vuelve a cero. Mientras tanto, el reenvío en Janus puede seguir asumiendo el valor anterior del ROC. Desde ese instante, la autenticación de paquetes empieza a fallar.
Por eso el problema no se manifiesta de inmediato. Es necesario que los medios permanezcan activos el tiempo suficiente como para que se produzca al menos un reinicio del contador de 16 bits, que el navegador reinicie el flujo, que el SSRC no cambie y que el reenvío continúe utilizando el contexto SRTP previo. Solo cuando coinciden todas esas condiciones se hace visible el desajuste.
Comportamiento del navegador: reutilización del SSRC
Los navegadores modernos están diseñados para preservar la continuidad de la sesión siempre que sea posible. Cuando un usuario desactiva y más tarde vuelve a activar su cámara o micrófono, la pila WebRTC suele mantener el mismo SSRC para conservar la identidad del flujo. Al mismo tiempo, puede reiniciar internamente la numeración de paquetes y volver a inicializar su estado SRTP como si el flujo comenzara de nuevo.
Desde la perspectiva del navegador, este comportamiento es completamente válido. La identidad del flujo de medios sigue siendo la misma, la señalización no necesariamente renegocia el SSRC y los componentes aguas abajo pueden tratarlo como si fuera el mismo flujo.
Sin embargo, la protección frente a repeticiones en SRTP es dependiente del estado. Si el reenvío en Janus continúa utilizando el contexto SRTP asociado a ese SSRC, conservará el valor anterior del ROC, esperará una progresión de secuencia coherente con los paquetes previos y rechazará los nuevos paquetes como no autenticados.
El resultado final es el error srtp_err_status_auth_fail.
Por qué el reenvío RTP es especialmente vulnerable
Dentro de la propia sala, Janus gestiona los flujos de los participantes de forma dinámica. Tiene mayor flexibilidad para reaccionar ante eventos de renegociación y para seguir las transiciones internas de estado.
El reenvío RTP, en cambio, suele configurarse una sola vez al inicio de la sesión y tratarse como una canalización estable y de larga duración. Normalmente se asume que el SSRC permanecerá constante, que el contexto SRTP asociado se mantendrá durante toda la vida del flujo y que el seguimiento del rollover continuará sin interrupciones. Este diseño funciona bien en condiciones estables, cuando los medios fluyen de manera continua y no se reinicia ningún estado interno a mitad de sesión.
La dificultad aparece cuando el navegador reinicia los medios pero conserva el mismo SSRC. La capa de reenvío mantiene su estado previo de protección frente a repeticiones sin ninguna señal de que el emisor ha reiniciado sus contadores internos. Desde la perspectiva del emisor, el flujo ha comenzado de nuevo; desde la perspectiva del reenvío, se trata de una transmisión continua. Como consecuencia, el índice de paquete calculado empieza a divergir y la autenticación SRTP falla porque las expectativas de rollover en cada extremo ya no coinciden.
Cómo diagnosticar el problema
Este comportamiento puede resultar confuso en entornos de producción porque no aparece de inmediato, sino tras varios minutos de transmisión continua de medios. Además, depende de una interacción concreta del usuario, como desactivar y volver a activar la cámara o el micrófono, y puede parecer intermitente. En muchos casos, reiniciar el reenvío hacia otro contexto del plugin de streaming de Janus —por ejemplo, utilizando otro puerto— hace que el problema desaparezca.
Una pista diagnóstica clave es el momento en que se produce el fallo. Si los errores solo aparecen después de una actividad prolongada de medios y no en sesiones cortas, el rollover del número de secuencia debería convertirse inmediatamente en un posible sospechoso. Otro indicador sólido es que reiniciar el reenvío soluciona el problema sin necesidad de renegociar las claves de cifrado. Eso apunta claramente a una desincronización de estado, y no a un desajuste de claves.
La solución práctica: forzar un nuevo SSRC
La solución más robusta y segura desde el punto de vista operativo es sencilla: cuando se reinicien los medios, detén el reenvío RTP y vuelve a iniciarlo con un nuevo SSRC.
Asignar un nuevo SSRC al reiniciar el reenvío crea, en la práctica, un límite limpio para el flujo. Se inicializa un contexto SRTP nuevo, el contador de rollover comienza de nuevo desde su estado inicial y tanto el emisor como el receptor reconstruyen sus índices de paquete a partir de una base común. Con esta realineación, la autenticación SRTP vuelve a funcionar con normalidad, ya que deja de existir cualquier discrepancia en el historial de rollover o en la numeración de paquetes.
En términos prácticos, esto implica detectar los momentos en los que cambia el ciclo de vida de los medios, como la sustitución de una pista, la reactivación de la cámara o el micrófono, o un evento de renegociación del publicador. Cuando se produzca uno de estos cambios, debes detener la sesión de reenvío RTP actual e iniciar una nueva asignando explícitamente un SSRC diferente. De este modo, evitas arrastrar un estado obsoleto de protección frente a repeticiones y garantizas que los contextos de cifrado permanezcan sincronizados entre los distintos componentes.
Por qué no intentar la resincronización del ROC
En teoría, podrías intentar detectar una divergencia del ROC y resincronizarlo dinámicamente. En la práctica, este enfoque es complejo y arriesgado.
La protección frente a repeticiones en SRTP está diseñada para evitar la inyección y repetición de paquetes. Relajar las reglas de validación para adaptarse a un estado incierto del rollover debilita las garantías de seguridad.
Inferir el valor correcto del ROC en mitad del flujo no es trivial, ya que la detección del rollover depende de una progresión precisa de la secuencia y de supuestos temporales que pueden dejar de cumplirse tras un reinicio de medios. Cualquier intento de reconstruir ese estado exige analizar cuidadosamente el flujo de paquetes sin introducir ambigüedades.
Además, un error en esa reconstrucción puede provocar que paquetes válidos sean rechazados o, peor aún, que paquetes repetidos superen la verificación. Ninguno de estos escenarios es aceptable en sistemas en producción donde la fiabilidad y la seguridad deben ir de la mano.
A esto se suma que el comportamiento varía entre navegadores e implementaciones, ya que las distintas pilas WebRTC gestionan la reutilización del SSRC y la reinicialización de SRTP de manera ligeramente diferente. Esta falta de uniformidad hace que una lógica de recuperación genérica sea difícil de implementar con garantías en entornos heterogéneos.
En sistemas en producción, una reinicialización determinista es mucho más segura que una reparación basada en heurísticas.
Consideraciones operativas
En despliegues WebRTC a gran escala, los reinicios de medios forman parte del funcionamiento habitual y no son un caso excepcional. Los usuarios activan y desactivan con frecuencia la cámara y el micrófono, las fluctuaciones de red pueden desencadenar eventos de renegociación y dispositivos como webcams o auriculares pueden desconectarse y volver a conectarse durante una sesión activa. Estos comportamientos normales introducen transiciones constantes en el ciclo de vida que la infraestructura debe gestionar de forma elegante, sin asumir una continuidad ininterrumpida de los medios.
Por ello, las canalizaciones de reenvío deberían tratar los reinicios de medios como límites de identidad. Aunque el SSRC permanezca igual en origen, el contexto de reenvío no debería dar por sentada la continuidad tras una reconfiguración del dispositivo.
Un enfoque práctico consiste en supervisar los cambios a nivel de pista, registrar la progresión de la secuencia con fines de diagnóstico y forzar la rotación del SSRC cuando se produzcan eventos de reinicio. De este modo, el reenvío se mantiene sólido incluso ante comportamientos imprevisibles del cliente.
Lecciones para infraestructuras WebRTC
Este caso pone de relieve varios principios de ingeniería más amplios.
En primer lugar, los tamaños de campo heredados siguen importando. El número de secuencia RTP de 16 bits es una decisión de diseño con décadas de antigüedad, pero sus limitaciones afloran en escenarios modernos de vídeo con alto bitrate, donde el reinicio del contador puede producirse relativamente rápido. Incluso campos pequeños en la cabecera pueden generar comportamientos inesperados cuando el estado persiste a través de reinicios.
En segundo lugar, la gestión de estado exige disciplina en el ciclo de vida. Los contextos de cifrado no son contenedores sin estado; acumulan supuestos sobre el orden de los paquetes y los rollovers. Cuando cambia el ciclo de vida de un flujo, el estado criptográfico debe revisarse, aunque la señalización parezca estable.
Por último, la continuidad en una capa no implica continuidad en otra. Los navegadores optimizan la continuidad a nivel de aplicación, los servidores de medios priorizan la integridad del transporte y las canalizaciones de reenvío suelen asumir persistencia de identidad. Estos objetivos no siempre se alinean automáticamente. Una gestión explícita del ciclo de vida es lo que permite cerrar esa brecha.
Reflexión final
Los fallos de autenticación SRTP suelen interpretarse como anomalías criptográficas. En realidad, muchos son problemas de gestión de estado provocados por comportamientos perfectamente válidos en otra capa.
En este caso, la combinación de un contador de paquetes de 16 bits, el incremento del ROC tras varios minutos, la reutilización del SSRC por parte del navegador y contextos de reenvío persistentes creó una condición de fallo muy concreta pero reproducible.
La solución no fue modificar el cifrado ni debilitar la protección frente a repeticiones, sino simplemente tratar el reinicio de medios como un límite claro y rotar el SSRC en consecuencia.
En sistemas WebRTC en producción, la estabilidad a menudo depende de reconocer cuándo la identidad debe cambiar, aunque todo aguas arriba parezca indicar lo contrario. Comprender estas interacciones sutiles del protocolo es esencial cuando operas unidades de reenvío selectivo a gran escala. A veces, la solución más segura no es un algoritmo complejo, sino un reinicio limpio en el momento adecuado.
En Digital Samba seguimos perfeccionando nuestra infraestructura de medios para ofrecer comunicación por vídeo fiable y segura a gran escala. Retos de ingeniería como este recuerdan que los sistemas en tiempo real exigen tanto conocimiento profundo de los protocolos como un diseño cuidadoso del ciclo de vida.