# Seguridad

# Reportar Vulnerabilidades

Cuando una vulnerabilidad es reportada, se transforma inmediatamente en nuestra principal preocupación, con un contribuidor de tiempo completo deja todos al lado para trabajar solo en esta. Para reportar una vulnerabilidad, por favor envíe un email a security@vuejs.org.

Mientras el descubrimiento de nuevas vulnerabilidades es raro, también recomendamos siempre utilizar la última versión de Vue y sus librerías oficiales de complementos para aseguar que su aplicación mantenga lo más segura posible.

# Norma N°1: No utilice nunca plantillas que no son de confianza

La norma de seguridad más fundamental cuando se utiliza Vue es no utilice nunca contenidos que no son de confianza como la plantilla de su componente. Hacerlo es equivalente a permitir ejecución arbitraria de JavaScript en su aplicación, y peor, puede conducir a las brechas en el servidor si el código es ejecutido durante la renderización en el lado del servidor. Un ejemplo de tal uso:

Vue.createApp({
  template: `<div>` + userProvidedString + `</div>` // NUNCA HACERLO
}).mount('#app')
1
2
3

Las plantillas Vue son compilada a JavaScript, y expresiones dentro de plantillas son ejecutadas como un parte del proceso de la renderización. Aunque las expresiones son evauladas contra un contexto específico de renderización, debido a que la complejidad del entorno potencial de ejecución global, es impráctico para un framework como Vue para protegerle complementamente de las ejecuciones potenciales de códigos maliciosos sin incurrir sobrecarga de rendimiento irreal. La más directa manera para evitar esta categoría de problemas por completo es aseguarse que los contenidos de sus plantillas Vue son siempre confiables y controlados completamente por usted mismo.

# Que hace Vue para protegerle

# El contenido HTML

Pese a lo que se utiliza, tanto plantilla como función de render, el contenido será automáticamente escapado, lo que significa que en la siguiente plantilla:

<h1>{{ userProvidedString }}</h1>
1

si userProvidedString contiene:

'<script>alert("hi")</script>'
1

entonces sería escapada al siguiente HTML:

&lt;script&gt;alert(&quot;hi&quot;)&lt;/script&gt;
1

por lo tanto previene la inyección de script. Este escape es realizado utilizando las APIs nativos del navegador, como textContent, así una vulnerabilidad sólo puede existir si el navegador mismo es vulnerable.

# Las Vinculaciones de Atributos

De la misma manera, las vinculaciones dinámicas de atributos son también automáticamente escapadas. Lo que significa que en la siguiente plantilla:

<h1 :title="userProvidedString">
  hola
</h1>
1
2
3

si userProvidedString contiene:

'" onclick="alert(\'hi\')'
1

entonces sería escapado al siguiente HTML:

&quot; onclick=&quot;alert('hi')
1

por lo tanto previene que el cierre del atributo title inyecte nuevo, arbitrario HTML. Este escape es realizado utilizando las APIs nativos del navegador, como setAttribute, así una vulnerabilidad sólo puede existir si el navegador mismo es vulnerable.

# Peligros Potenciales

En cualquiera aplicación web, permitir la ejecución del contenido sin desinfectar, proporcionado por el usuario como HTML, CSS o JavaScript puede ser peligroso, por lo tanto, eso debe ser evitado siempre que sea posible. Pero también hay casos en que algunos riesgos pueden ser aceptables.

Por ejemplo, los servicios como CodePen y JSFiddle permite que el contenido proporcionado por el usuario sea ejecutado, pero eso ocurre en un contexto previsto, y en un entorno de recinto de seguridad (sandboxed) dentro de iframes. en los casos cuando una característica importante requiere alguno nivel de vulnerabilidad por naturaleza, depende de su equipo para evaluar la importancia de la característica contra los escenarios más peores que pueda provocar la vulnerabilidad.

# Inyectar HTML

Como ha aprendido anteriormente, Vue escapa automáticamente el contenido HTML, le previene de inyectar HTML ejecutable por accidente en su aplicación. Sin embargo, in casos dónde sabe que el HTML es seguro, puede renderizar el contenido HTML explícitamente:

  • Utiliando una plantilla:

    <div v-html="userProvidedHtml"></div>
    
    1
  • Utilizando un función render:

    h('div', {
      innerHTML: this.userProvidedHtml
    })
    
    1
    2
    3
  • Utilizando un función render con JSX:

    <div innerHTML={this.userProvidedHtml}></div>
    
    1

TIP

Note que el HTML proporcionado por el usuario no puede nunca considerado 100% seguro salvo que es en un entorno de recinto de seguridad (sandbox) dentro de iframe o en una parte de la aplicación dónde solo el usuario quién escribió aquel HTML puede ser expuesto a el. Además, permitir a los usuarios escribir sus propias plantillas Vue puede provocar los mismos riesgos.

# Inyectar URLs

En un URL como este:

<a :href="userProvidedUrl">
  hazme clic
</a>
1
2
3

Hay un problema potencial de seguridad si el URL no se ha "desinfectado (sanitized)" para prevenir ejecución de JavaScript utilizando javascript:. Hay librerías como sanitize-url (opens new window) para ayudar con esto, pero tenga en cuenta:

TIP

Si está realizando desinfección de URL en el lado frontend, ya tiene un problema de seguridad. los URLs proporcionados por el usuario deberían ser desinfectados por su backend incluso antes de guardarse en la base de datos. Entonces el problema es evitado para cada cliente conectado a su API, incluye las aplicaciones móviles nativas. También tenga en cuenta que incluso con los URLs desinfectados, Vue no puede garantizarle que apunten a direcciones seguras.

# Inyectar Estilos (Styles)

Mire el siguiente ejemplo:

<a
  :href="sanitizedUrl"
  :style="userProvidedStyles"
>
  Hazme clic
</a>
1
2
3
4
5
6

Asumamos que sanitizedUrl ya ha sido desinfectado, así que es definitivamente un URL real y no es JavaScript. Con userProvidedStyles, los usuarios maliciosos podrían todavía proporcionar CSS para "clickjacking (secuestro de clic)", por ejemplo, decorar el enlace como una caja transparente sobre el botón "Log in". Entonces si https://user-controlled-website.com/ es construido para asemejar la página de inicio de sesión de su aplicación, ya podrían haber capturado la información real de inicio de sesión de un usuario.

Podría ser capaz de imaginar cómo permitir contenido proporcionado por el usuario para un elemento <style> pueda provocar una vulnerabilidad más fuerte, dado que el usuario obtenga el control completo sobre cómo decorar la página entera. Eso es porque Vue previene la renderización de etiquetas de style dentro de plantillas, como esto:

<style>{{ userProvidedStyles }}</style>
1

Para mantener su usuarios completamente seguros de clickjacking, recomendamos solo permitir el control completo sobre CSS dentro de un iframe que forma un entorno de recinto de seguridad (sandboxed). Alternativamente, cuando proviene al usuario el control mediante una vinculación de estilos (style), recomendamos utilizar la sintaxis de objeto y solo permitir que los usuarios proporcionen valores para propiedades específicas que sean seguros para ellos para controlar, como esto:

<a
  :href="sanitizedUrl"
  :style="{
    color: userProvidedColor,
    background: userProvidedBackground
  }"
>
  Hazme clic
</a>
1
2
3
4
5
6
7
8
9

# Inyectar JavaScript

Desaconsejamos fuertemente renderizar un elemento <script> con Vue, debido a que plantillas y funciones de render deberían causar ninguno efecto secundario. Sin embargo, esta no es la única manera para incluir cadenas de caracteres que podrían ser evaluadas como JavaScript en tiempo de ejecución.

Cada elemento HTML tiene atributos con valores que aceptan cadenas de caracteres de JavaScript, por ejemplo, onclick, onfocus, y onmouseenter. Vincular JavaScript proporcionado por el usuario a cualquier de estos atributos de eventos es un riesgo potencial de seguridad, por lo tanto eso debe ser evitado.

TIP

Note que JavaScript proporcionado por el usuario no se puede considerar 100% seguro, salvo que dentro de un iframe que forma un entorno de recinto de seguridad o en una parte de la aplicación dónde solo el usuario quién escribió ese JavaScript puede ser expuesto a el.

A veces recibimos reportajes de vulnerabilidad sobre cómo es posible hacer cross-site scripting (XSS) en plantillas Vue. Por lo general, no consideramos que tales casos sean vulnerabilidades verdaderas, porque no hay maneras prácticas para protejer los desarrolladores de los dos escenarios que podrían permitir XSS:

  1. El desarrollador está pidiendo a Vue explícitamente renderizar el contenido sin desinfectar proporcionado por el usuario como plantillas Vue. Este es inseguro por naturaleza y no hay ninguna manera de que Vue pueda reconocer el origen.

  2. El desarrollador está montando Vue a una página HTML entera en que pasa a contener contenido renderizado por el servidor o proporcionado por el usuario. Eso es fundamentalmente el mismo problama como #1, pero a veces los desarrolladores podrían hacerlo sin darse cuenta. Eso puede provocar vulnerabilidades posibles dónde el atacante proporciona HTML que es seguro como HTML plano pero inseguro como una plantilla Vue. La mejor práctica es nunca montar Vue en nodos que pueda contener contenido renderizado por el servidor o proporcionado por el usuario.

# Prácticas Óptimas

La regla general es que si permite la ejecución de contenido sin desinfectar, proporcionado por el usuario (ya sea HTML, JavaScript u incluso CSS), se estaría exponiendo a los ataques. En realidad, este consejo mantiene válido tanto en el uso de Vue como con otro framework, o incluso con ninguno framework.

Más allá de las recomendaciones hechas arriba para peligros potenciales, también recomendamos familiarizarse usted mismo con estos recursos:

Luego utilice lo que ya ha aprendido para también revisar el código de fuente de sus dependencias por patrones potencialmente peligrosos. Si cualquier de ellas incluye componentes de tercera parte o influye lo que va a ser renderizado al DOM.

# Coordinación con Backend

Las vulnerabilidades de seguridad de HTML, como solicitudes falsas de sitios cruzados (CSRF/XSRF) y cross-site script inclusion (XSSI), son dirigidos principalmente al backend, por lo tanto son afuera de las preocupaciones de Vue. Sin embargo, es aún una buena idea para comunicar con su equipo de backend para aprender la mejor manera de interactuar con sus APIs, por ejemplo, enviar el formulario junto con el token CSRF.

# Renderización en el lado del Servidor (SSR)

Hay unas preocupaciones adicionales de seguridad cuando se utiliza SSR, así que asegúrese de seguir las mejores prácticas reseñadas a través de nuestra documentación de SSR para evitar las vulnerabilidades.