El problema y cuándo aplica
Una aplicación comunitaria en React tiene tres rutas de renderizado:
- Los comentarios ordinarios se almacenan en una base de datos y deben aparecer exactamente como texto.
- Los anuncios de moderadores pueden usar un vocabulario limitado de texto enriquecido: párrafos, énfasis, listas y enlaces HTTPS.
- Una página de búsqueda lee
qdelocation.searchy muestra «Resultados para…» sin esperar una respuesta renderizada en el servidor.
Una revisión detecta que los comentarios ordinarios y las vistas previas de anuncios fluyen hacia dangerouslySetInnerHTML o innerHTML. El banner de búsqueda también concatena la consulta en una cadena HTML. Explica cómo encontrar cada ruta de origen a sink (source-to-sink), distinguir los ciclos de vida del ataque, elegir la codificación o sanitización para cada contexto y agregar controles que reduzcan el impacto de un sink omitido.
La respuesta básica cubre el renderizado en el navegador y la responsabilidad del frontend. La validación del lado del servidor, la autorización y el almacenamiento de contenido siguen siendo límites obligatorios, pero no hacen que un sink inseguro del DOM sea seguro. Esta es una pregunta de frontend porque la habilidad decisiva es comprender el análisis del navegador (browser parsing), los mecanismos de escape del framework (escape hatches), los sinks de inyección en el DOM, CSP y contratos de renderizado verificables.
Almacenado, reflejado y basado en DOM son etiquetas útiles, pero describen ejes diferentes. «Almacenado» y «reflejado» describen cómo los datos controlados por un atacante llegan a la víctima. «Basado en DOM» describe una ruta de ejecución del lado del cliente en la que JavaScript mueve datos hacia un sink de inyección. Un payload almacenado o reflejado aún puede ejecutarse a través de un sink del DOM, por lo que las etiquetas no siempre son mutuamente excluyentes.
Qué evalúa el entrevistador
La primera señal es si el candidato traza un límite en el flujo de datos antes de enumerar encabezados de seguridad. Una respuesta sólida identifica fuentes como campos de base de datos, parámetros de URL, fragmentos, postMessage y respuestas de terceros, y luego identifica sinks como innerHTML, outerHTML, insertAdjacentHTML, document.write, eval y temporizadores basados en cadenas. La pregunta pasa a ser: ¿pueden los datos controlados por un atacante llegar a un analizador que los trate como marcado, script o una URL de script?
La segunda señal es elegir la defensa a partir del tipo de dato previsto. Los comentarios planos son texto, por lo que deben llegar a un sink de texto o a una interpolación JSX normal. Los anuncios enriquecidos contienen HTML intencionalmente, por lo que la codificación de entidades rompería la funcionalidad; requieren un sanitizador de HTML con mantenimiento activo y una política estricta inmediatamente antes del límite de renderizado confiable. Los valores de URL necesitan validación de protocolo y destino además del contexto de salida correcto.
La tercera señal es si el candidato comprende los límites del framework. React escapa la interpolación de cadenas normal, pero dangerouslySetInnerHTML es un escape hatch explícito. Un framework no puede rescatar una cadena HTML sin procesar ni validar cada URL javascript: o data: suministrada a una propiedad peligrosa.
La señal final es la verificación por capas. CSP puede limitar qué scripts se ejecutan, y Trusted Types puede hacer que determinados sinks de inyección rechacen cadenas sin procesar. Ninguno de los dos controles repara una política de sanitizador permisiva ni una función de política insegura. Una respuesta sólida elimina los sinks evitables, restringe el sink restante, despliega controles en el navegador y demuestra el resultado con una revisión de origen a sink y pruebas con payloads hostiles.
Preguntas de aclaración antes de responder
- ¿Qué campos son texto y qué campos contienen HTML intencionalmente? Si todos los campos son texto, elimina todo renderizado
de HTML sin procesar. Si los anuncios necesitan formato, define una política exacta de etiquetas, atributos y URLs antes de elegir un sanitizador.
- ¿Quién puede crear anuncios? Que la entrada sea exclusiva de moderadores reduce la exposición, pero no la hace confiable. Una sesión
de moderador robada, una importación comprometida, una migración o un error en la API aún pueden persistir contenido malicioso.
- ¿Se permite que los enlaces de anuncios salgan del sitio? La solución base solo permite enlaces HTTPS. Permitir
correo, protocolos personalizados, imágenes, video o marcos incrustados requiere una política más amplia y aislamiento adicional.
- ¿Dónde se realiza la sanitización actualmente? La sanitización en el momento de la escritura puede rechazar entradas inválidas a tiempo, pero el
límite de renderizado todavía necesita garantizar que cada valor que llegue al sink de HTML sin procesar haya sido sanitizado por la política actual.
- ¿Qué navegadores deben soportarse? CSP es ampliamente útil. El soporte de Trusted Types y su comportamiento de despliegue deben
verificarse con la matriz real de navegadores; los clientes no compatibles aún dependen de sinks seguros y sanitización.
- ¿Qué scripts de terceros se requieren? Una política estricta de scripts es más fácil cuando la aplicación tiene un conjunto pequeño y
auditado de scripts. Los administradores de etiquetas (tag managers) y los snippets inline modifican el plan de migración de CSP y amplían el impacto de cualquier XSS exitoso.
- ¿Qué significa «solucionado» a nivel operativo? La respuesta debe incluir pruebas de regresión, monitoreo de violaciones de CSP,
actualizaciones del sanitizador, responsabilidad sobre los cambios de política y un método para detectar sinks recién introducidos.
Estructura de respuesta de 30 segundos
«Haría un inventario de fuentes no confiables y sinks ejecutables, y luego corregiría cada ruta según el tipo de valor previsto. Los comentarios ordinarios y la consulta de búsqueda son texto, por lo que la interpolación de React o textContent deberían renderizarlos sin procesar HTML. La funcionalidad de anuncios genuinamente necesita HTML limitado, por lo que la pasaría por un sanitizador con lista de permitidos mantenido y expondría un único renderizador de texto enriquecido restringido; los enlaces también reciben validación de protocolo. Eliminaría otras llamadas a innerHTML, desplegaría un CSP basado en nonces o hashes en modo report-only antes de aplicarlo, y usaría Trusted Types donde la matriz de navegadores lo soporte para rechazar cadenas sin procesar en los sinks del DOM. Finalmente, probaría payloads almacenados, controlados por URL, con marcado malformado, manejadores de eventos, SVG y URLs de scripts, verificando al mismo tiempo que el formato permitido siga funcionando».
Análisis detallado paso a paso
Paso 1: Mapear cada origen a cada sink de análisis
Comienza con una tabla pequeña de flujo de datos, no con una lista de cadenas de payload:
| Ruta | Origen controlado por atacante | Sink actual | Tipo previsto | Cambio requerido |
|---|---|---|---|---|
| Tarjeta de comentario | Cuerpo del comentario en BD | Renderizador de HTML sin procesar | Texto | Interpolación JSX o textContent |
| Anuncio | Cuerpo del anuncio en BD | Renderizador de HTML sin procesar | HTML limitado | Sanitización por lista de permitidos, luego un único sink revisado |
| Banner de búsqueda | location.search | Concatenación de cadenas HTML | Texto | textContent o un hijo React de texto |
| Enlace de anuncio | href de texto enriquecido | Atributo portador de URL | URL HTTPS | Analizar, validar protocolo y sanitizar atributo |
La revisión del repositorio debe buscar sinks directos y wrappers alrededor de ellos. Nombres como safeHtml no son una prueba; rastrea el valor hasta la transformación que lo generó. Inspecciona también los puntos de entrada indirectos: renderizadores de Markdown, editores de texto enriquecido, componentes de vista previa, mensajes de localización con marcado, llamadas al analizador del DOM, SVG, utilidades de plantillas, snippets de analítica y código que copia datos de URL o mensajes dentro de la página.
Clasifica los incidentes una vez conocida la ruta:
- Un comentario malicioso persistido en la base de datos y mostrado a otros usuarios tiene un ciclo de vida almacenado.
- Un parámetro de solicitud copiado en una respuesta inmediata del servidor tiene un ciclo de vida reflejado.
- Una consulta o fragmento leído por JavaScript del cliente y pasado a
innerHTMLtiene una ruta de ejecución basada en DOM.
Esta clasificación ayuda a la respuesta ante incidentes, pero la decisión de remediación sigue dependiendo del origen, del contexto de salida y del sink.
Paso 2: Hacer que el texto siga siendo texto
Los comentarios ordinarios y la etiqueta de búsqueda no necesitan marcado. Usa hijos normales de React:
function CommentBody({ body }: { body: string }) {
return <p>{body}</p>
}
function SearchSummary({ query }: { query: string }) {
return <p>Results for “{query}”</p>
}Fuera de React, usa un sink de texto:
summaryNode.textContent = queryEl navegador ahora recibe los datos como texto en lugar de volver a analizarlos como HTML. No «limpies» la cadena con una expresión regular para luego seguir asignándola a innerHTML; el análisis de HTML tiene demasiados elementos, atributos, codificaciones y reglas de recuperación ante entradas malformadas para que ese enfoque sea confiable.
El contexto sigue importando. La seguridad como texto no hace que un valor sea automáticamente seguro en un manejador de eventos, bloque de script, regla CSS o URL. Evita colocar valores no confiables en contextos ejecutables. Cuando un valor pertenezca a un atributo seguro, escribe el nombre del atributo de forma fija (hardcode) y usa la propiedad del framework o setAttribute solo después de aplicar la validación requerida por ese atributo.
Paso 3: Aislar la única funcionalidad que requiere HTML
El requerimiento de anuncios no puede usar texto plano porque ciertos formatos deben preservarse. Define la política antes de la implementación:
- Etiquetas permitidas: párrafo, énfasis fuerte, énfasis, listas ordenadas y no ordenadas, elementos de lista y enlaces.
- Atributos permitidos: únicamente
href,titley los atributos de enlace agregados por el renderizador. - Protocolo de enlace permitido en el escenario base: HTTPS.
- Contenido no permitido: scripts, atributos de manejadores de eventos, estilos inline, marcos (frames), formularios, SVG y medios arbitrarios.
Luego, centraliza el sink de HTML sin procesar:
function RichAnnouncement({ dirtyHtml }: { dirtyHtml: string }) {
const cleanHtml = sanitizeRichText(dirtyHtml, RICH_TEXT_POLICY)
return <div dangerouslySetInnerHTML={{ __html: cleanHtml }} />
}sanitizeRichText representa un sanitizador mantenido, basado en analizadores (parser-based) y configurado con dicha política. OWASP recomienda DOMPurify como una opción. La propiedad de seguridad proviene del sanitizador y su configuración, no del nombre de la variable ni del tipo de TypeScript.
Sanitiza inmediatamente antes del límite de renderizado revisado. La sanitización al escribir puede brindar una comprobación adicional, pero depender únicamente de ella deja brechas para filas antiguas, importaciones, migraciones, APIs alternativas y cambios de política. Si el sistema almacena la salida sanitizada por rendimiento, registra la versión del sanitizador y de la política para que el contenido antiguo pueda reprocesarse tras una actualización de seguridad.
No modifiques el HTML mediante concatenación de cadenas después de sanitizarlo. Agregar un enlace, resaltado o contenedor editando la cadena sanitizada puede reintroducir una construcción insegura. Construye la interfaz de usuario confiable fuera de la región de HTML sin procesar, o pasa el contenido final nuevamente por el sanitizador.
Paso 4: Tratar las URLs como entrada estructurada
La sanitización de HTML debe cubrir los atributos de enlaces, pero la política del producto también debe ser explícita. Analiza una URL candidata contra una base conocida, inspecciona el protocolo resultante y acepta solo los protocolos que la funcionalidad necesita. En este escenario, solo sobrevive HTTPS.
Codificar una URL peligrosa no hace que su esquema sea aceptable. Un valor puede estar correctamente codificado para un href y aún así usar un protocolo que ejecute scripts. La decisión sobre la URL y el contexto del atributo HTML son comprobaciones independientes. Para los enlaces externos que se abren en una nueva pestaña, agrega los atributos de relación apropiados a través del renderizador; eso limita el acceso a opener, pero no reemplaza la prevención de XSS.
Evita por completo las URLs de scripts controladas por el usuario. eval, Function, setTimeout basado en cadenas, setInterval basado en cadenas y la construcción dinámica de fuentes de scripts no deben recibir valores no confiables. Estas rutas necesitan eliminación o un mapeo predefinido reducido, no un sanitizador de propósito general.
Paso 5: Agregar CSP como segunda línea de defensa
Una CSP puede restringir la ejecución de scripts si se pasa por alto un sink. Prefiere un encabezado de respuesta y diseña una política alrededor de los recursos reales de la aplicación. Una dirección simplificada es:
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-{per-response-random-value}';
object-src 'none';
base-uri 'none'El nonce debe ser impredecible y único por respuesta, y solo los scripts aprobados lo reciben. Una política basada en hashes puede adecuarse al contenido inline estable. Evita debilitar la política con listas amplias de hosts o unsafe-inline solo para silenciar violaciones.
Comienza con Content-Security-Policy-Report-Only, recopila violaciones, elimina código inline no previsto y luego aplícala (enforce). El modo report-only proporciona evidencia para el despliegue pero no bloquea nada. CSP sigue siendo defensa en profundidad: los scripts permitidos siguen teniendo los privilegios de la página, el soporte del navegador difiere según la característica y una política permisiva puede dejar el exploit original en funcionamiento.
Paso 6: Usar Trusted Types para restringir la inyección en el DOM
Donde sea compatible, agrega la directiva CSP:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app-rich-textLa aplicación (enforcement) hace que los sinks de inyección en el DOM cubiertos rechacen cadenas ordinarias. La aplicación crea únicamente la política con nombre, y esa política delega la creación de HTML al sanitizador aprobado. Esto convierte una asignación insegura silenciosa en una excepción visible y facilita la detección de nuevos sinks de cadenas sin procesar en pruebas y monitoreo.
Una política que devuelve la entrada sin cambios anula el control. Una política por defecto amplia también puede ocultar rutas heredadas al convertir automáticamente cada cadena. Usa una política por defecto temporalmente durante la migración para fines de diagnóstico, y luego mueve a los llamadores a valores confiables explícitos y elimina los sinks evitables.
Trusted Types no cubre todas las formas posibles de ejecutar código, y es posible que los navegadores más antiguos carezcan de soporte para su aplicación. La base de referencia sigue siendo un renderizado seguro, sanitización estricta, validación de URLs y la eliminación de APIs de cadenas ejecutables.
Paso 7: Reducir el impacto fuera de la función de renderizado
Las cookies de sesión normalmente deben usar HttpOnly, Secure y una política apropiada de SameSite. HttpOnly puede evitar que el JavaScript inyectado lea directamente esa cookie, pero un XSS activo aún puede enviar solicitudes en nombre del usuario o leer datos disponibles para la página. Los atributos de cookies reducen el impacto; no cierran la ruta de inyección.
La autorización del servidor debe proteger cada acción sensible incluso cuando el frontend oculte un control. Sanitiza o valida en los límites del servidor donde sea apropiado, y mantén las entradas almacenadas de atacantes etiquetadas como no confiables. Los scripts de terceros se ejecutan con los privilegios de la página, por lo que se debe reducir su número, acotarlos a las rutas necesarias, auditar sus actualizaciones e incluirlos en el diseño de la CSP.
Paso 8: Verificar tanto la seguridad como el formato previsto
Construye un corpus de pruebas que cubra diferentes rutas del analizador:
<img src=x onerror=alert(1)>
<a href="javascript:alert(1)">open</a>
<svg onload=alert(1)></svg>
"><script>alert(1)</script>
malformed tags and mixed character encodingsUsa callbacks de prueba inertes en un entorno de pruebas aislado en lugar de comportamientos destructivos reales. Verifica:
- Que los comentarios planos muestren todos los caracteres y no creen elementos.
- Que los parámetros de búsqueda sigan siendo texto tras la navegación normal, URLs codificadas, historial del navegador e hidratación.
- Que las etiquetas permitidas de los anuncios se mantengan mientras que los scripts, manejadores de eventos, estilos, SVG, marcos y URLs inseguras
sean eliminados.
- Que la salida del sanitizador no sea mutada antes de llegar al sink de HTML sin procesar.
- Que se comprenda la telemetría de CSP en report-only y que luego la aplicación bloquee un sink de prueba introducido intencionalmente.
- Que la aplicación de Trusted Types lance un error ante una cadena sin procesar y acepte únicamente la salida de la política sanitizada aprobada.
- Que los fixtures existentes de texto enriquecido, enlaces, estructura para lectores de pantalla y comportamiento de copiar y pegar sigan funcionando.
Agrega revisión estática para nuevos sinks, pruebas unitarias para la política del sanitizador, pruebas de integración para cada ruta de renderizado y pruebas de navegador contra la matriz soportada. Mantén el sanitizador actualizado y vuelve a ejecutar el corpus hostil cuando cambien el navegador, el framework, el sanitizador, el editor o la política.
Ejemplo de respuesta de alta calidad
«Primero identificaría las fuentes no confiables y las APIs del navegador que las analizan. El cuerpo del comentario en la base de datos, el HTML del anuncio y q proveniente de location.search son fuentes. innerHTML, dangerouslySetInnerHTML y cualquier constructor de scripts o URLs de scripts son los sinks que rastrearía.
Los comentarios y el banner de búsqueda son funcionalidades de texto. Los renderizaría como hijos de React o asignando textContent, de modo que el navegador nunca interprete sus caracteres como marcado. El anuncio tiene un contrato diferente porque permite HTML limitado. Definiría una lista de permitidos reducida para párrafos, énfasis, listas y enlaces HTTPS, pasaría el valor final a través de un sanitizador mantenido basado en analizadores, y mantendría un único componente revisado de HTML sin procesar. El sanitizador también eliminaría manejadores de eventos, estilos, SVG, marcos y esquemas de URL inseguros. Ningún código concatenaría marcado después de ese paso.
Describiría el comentario malicioso guardado como un ciclo de vida almacenado y la ruta de la consulta de búsqueda como basada en DOM. Si el servidor copiara un valor de solicitud en su respuesta HTML inmediata, sería reflejado. Estas etiquetas ayudan a encontrar la exposición, mientras que la corrección proviene siempre del contexto de salida y del sink.
Como defensa en profundidad, desplegaría una CSP basada en nonces o hashes en modo report-only, eliminaría las violaciones y luego la aplicaría. Donde el soporte de navegadores lo permita, exigiría Trusted Types para los sinks de scripts y permitiría únicamente una política con nombre que llame al sanitizador aprobado. No usaría CSP, cookies HttpOnly ni una política de Trusted Types que retorne la entrada sin cambios como la corrección principal.
Mi verificación incluiría payloads almacenados, payloads en URL, marcado malformado, atributos de eventos, SVG y URLs de scripts. Afirmaría que las rutas de texto no creen elementos, que el formato permitido se preserve, que el contenido no permitido sea eliminado, que las asignaciones de cadenas sin procesar fallen bajo Trusted Types y que la CSP aplicada bloquee un sink de prueba introducido intencionalmente. También mantendría actualizado el sanitizador e integraría la detección de nuevos sinks de inyección como un punto de control en la revisión de código y el análisis estático».
Errores comunes
- Escapar cada valor de la misma manera → los navegadores analizan HTML, atributos, URLs, CSS y JavaScript bajo
reglas distintas → mantén los datos fuera de contextos ejecutables y aplica la defensa requerida por el sink exacto.
- Enviar texto plano a través de
innerHTMLtras eliminar etiquetas de script → atributos de eventos, marcado malformado,
SVG, esquemas de URL y comportamientos del analizador persisten → reemplaza el sink con renderizado de texto en JSX o textContent.
- Codificar texto enriquecido → el marcado aparece de forma literal y la funcionalidad se rompe → **usa un sanitizador de HTML
mantenido con una lista de permitidos estricta cuando el HTML sea un requisito explícito del producto.**
- Confiar en contenido exclusivo de moderadores → cuentas comprometidas, importaciones, migraciones y fallas en la API pueden persistir
marcado hostil → trata el contenido almacenado como no confiable en el límite de renderizado.
- Sanitizar y luego concatenar más HTML → la mutación posterior puede recrear una construcción ejecutable →
haz que la sanitización sea la transformación final antes del sink revisado.
- Validar un
hrefúnicamente mediante codificación HTML → un valor codificado aún puede portar un protocolo no aceptable →
analiza la URL y permite únicamente los esquemas y destinos requeridos.
- Tratar el auto-escape de React como universal → los escape hatches y las APIs directas del DOM evaden la interpolación
normal de cadenas → haz un inventario de cada ruta de HTML sin procesar y de cadenas ejecutables.
- Depender únicamente de CSP → políticas débiles, scripts permitidos o características no soportadas pueden dejar el sink
explotable → elimina primero los sinks inseguros y usa CSP como una barrera adicional.
- Crear una política de Trusted Types que devuelva su entrada intacta → el navegador ve un objeto confiable sin que haya existido
una transformación digna de confianza → restringe los nombres de las políticas y delega en el sanitizador revisado.
- Comprobar solo que el payload de alert dejó de funcionar → un único payload no cubre esquemas de URL, marcado malformado,
elementos alternativos ni regresiones en el formato permitido → mantén un corpus hostil variado y fixtures de texto enriquecido positivos.
Preguntas de seguimiento
Pregunta de seguimiento 1: ¿Cómo migrarías una aplicación heredada con cientos de asignaciones de innerHTML?
Haz un inventario de sinks y ordénalos según las fuentes no confiables alcanzables, la exposición del usuario y los privilegios. Reemplaza primero las rutas que son solo de texto. Introduce un único límite revisado de texto enriquecido para el HTML legítimo restante. Despliega CSP y Trusted Types en modo report-only o de diagnóstico para revelar rutas en tiempo de ejecución que la búsqueda estática pasa por alto. Una política predeterminada temporal de Trusted Types puede registrar llamadas heredadas, pero no debe aprobar silenciosamente cadenas sin cambios; migra los llamadores hacia políticas explícitas y elimina la ruta de compatibilidad temporal.
Pregunta de seguimiento 2: ¿Qué cambia si los anuncios deben permitir imágenes y video incrustado?
El contrato de confianza se amplía. Define los orígenes de imágenes permitidos, esquemas de URL, dimensiones, comportamiento de carga y reglas de privacidad. Hacer proxy de las imágenes puede reducir las solicitudes directas a terceros. El video incrustado debe usar una lista reducida de proveedores permitidos y un marco aislado (sandboxed frame) con solo las capacidades requeridas. La política del sanitizador, las directivas de CSP, el comportamiento de consentimiento y el corpus de pruebas cambian por completo. Marcos arbitrarios, estilos y HTML de proveedores no deben ingresar al renderizador de anuncios existente.
Pregunta de seguimiento 3: ¿Qué pasa si una CSP estricta rompe scripts de analítica y de tag managers?
Ejecuta la política propuesta en modo report-only y clasifica cada violación según el responsable del negocio y el propósito del script. Elimina scripts no utilizados, reemplaza snippets inline con módulos externos aprobados y asigna a los scripts requeridos un nonce por respuesta o un hash estable según corresponda. Un comodín amplio o unsafe-inline restaura la compatibilidad a costa de renunciar a gran parte del límite de seguridad. Si un tag manager puede inyectar scripts arbitrarios, documenta que sigue siendo una ruta de código privilegiada y restringe quién puede publicar a través de él.
Pregunta de seguimiento 4: El servidor ya sanitiza los anuncios. ¿Por qué mantener un límite en el frontend?
El componente de HTML sin procesar necesita un contrato de entrada verificable independientemente de dónde se ejecute la transformación. APIs alternativas, registros antiguos, importaciones, entradas en caché, migraciones o un cambio de política pueden eludir una suposición hecha en la escritura. Encapsula el sink para que los llamadores solo puedan proporcionar la salida del sanitizador actual, prueba ese contrato y versiona el contenido sanitizado almacenado si se reutiliza. La comprobación del servidor reduce la entrada de datos corruptos al sistema; el límite de renderizado evita que un valor no verificado llegue al analizador.
Pregunta de seguimiento 5: ¿Cómo investigarías un reporte de XSS en producción?
Conserva la URL reportada, el identificador de contenido, el navegador, el reporte de CSP y la versión de despliegue relevante sin ejecutar el payload en una cuenta normal. Reprodúcelo en un entorno aislado, rastrea la ruta exacta de origen a sink y determina si el payload fue almacenado, guiado por la solicitud o provisto por un tercero. Elimina o deshabilita la ruta de renderizado vulnerable, invalida el contenido malicioso almacenado donde sea necesario, rota las credenciales expuestas, revisa las acciones sensibles realizadas durante la ventana de exposición y luego agrega la clase del payload al corpus de regresión antes de restaurar la funcionalidad.