¿Qué significa cuando dicen que React está protegido por XSS?

109

Leí esto en el tutorial de React. ¿Qué significa esto?

React es seguro. No estamos generando cadenas HTML, por lo que la protección XSS es la predeterminada.

¿Cómo funcionan los ataques XSS si React es seguro? ¿Cómo se logra esta seguridad?

usuario1210233
fuente

Respuestas:

179

ReactJS es bastante seguro por diseño ya que

  1. Las variables de cadena en las vistas se escapan automáticamente
  2. Con JSX, pasa una función como controlador de eventos, en lugar de una cadena que puede contener código malicioso

por lo que un ataque típico como este no funcionará

const username = "<img onerror='alert(\"Hacked!\")' src='invalid-image' />";

class UserProfilePage extends React.Component {
  render() {
    return (
      <h1> Hello {username}!</h1>
    );
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

pero ...

❗❗❗Advertencia❗❗❗

¡Todavía hay algunos vectores de ataque XSS que debes manejar tú mismo en React!

1. XSS a través de dangerouslySetInnerHTML

Cuando lo use dangerouslySetInnerHTML, debe asegurarse de que el contenido no contenga JavaScript. React no puede hacer nada por ti.

const aboutUserText = "<img onerror='alert(\"Hacked!\");' src='invalid-image' />";

class AboutUserComponent extends React.Component {
  render() {
    return (
      <div dangerouslySetInnerHTML={{"__html": aboutUserText}} />
    );
  }
}

ReactDOM.render(<AboutUserComponent />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

2. XSS a través del atributo a.href

Ejemplo 1: uso de javascript: código

Haga clic en "Ejecutar fragmento de código" -> "Mi sitio web" para ver el resultado.

const userWebsite = "javascript:alert('Hacked!');";

class UserProfilePage extends React.Component {
  render() {
    return (
      <a href={userWebsite}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Ejemplo 2: uso de datos codificados en base64:

Haga clic en "Ejecutar fragmento de código" -> "Mi sitio web" para ver el resultado.

const userWebsite = "data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGFja2VkISIpOzwvc2NyaXB0Pg==";

class UserProfilePage extends React.Component {
  render() {
    const url = userWebsite.replace(/^(javascript\:)/, "");
    return (
      <a href={url}>My Website</a>
    )
  }
}

ReactDOM.render(<UserProfilePage />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

3. XSS a través de accesorios controlados por atacantes

const customPropsControledByAttacker = {
  dangerouslySetInnerHTML: {
    "__html": "<img onerror='alert(\"Hacked!\");' src='invalid-image' />"
  }
};

class Divider extends React.Component {
  render() {
    return (
      <div {...customPropsControledByAttacker} />
    );
  }
}

ReactDOM.render(<Divider />, document.querySelector("#app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

Aquí hay más recursos

Consultoría CyberPanda
fuente
13
¡Esta respuesta es asombrosa! ¡Con los fragmentos de código y las referencias al final ...! ¡Gracias!
Ioanna
¿React se ha ocupado de alguno de los ejemplos anteriores desde que se escribió esta respuesta? Estoy preguntando, ya que leí en la siguiente presentación de diapositivas: slideshare.net/kseniadmitrieva/… diapositiva n. ° 20 que los accesorios controlados por el usuario se arreglaron en React 0.14 el 15 de noviembre '
omer
@omer no, y React decidió no hacerse cargo de estos vectores de ataque en el nivel React. Aquí hay algunos buenos comentarios que explican por qué no se manejan en el nivel React github.com/facebook/react/issues/3473 ( github.com/facebook/react/issues/3473#issuecomment-91349525 , github.com/facebook/react / issues / 3473 # issuecomment-90594748 )
CyberPanda Consulting
1
@omer, el problema al que se refiere fue un error de seguridad y se solucionó, pero el punto 3 que he enumerado no está relacionado con ese, aún puede verificar ese trabajo del tercer punto ejecutando mi código en cualquier versión de reacción.
CyberPanda Consulting
60

React escapa automáticamente de las variables por usted ... Evita la inyección de XSS a través de HTML de cadena con JavaScript malicioso. Naturalmente, las entradas se desinfectan junto con esto.

Por ejemplo, digamos que tienes esta cadena

var htmlString = '<img src="javascript:alert('XSS!')" />';

si intentas renderizar esta cadena en reaccionar

render() {
    return (
        <div>{htmlString}</div>
    );
}

literalmente verá en la página la cadena completa, incluida la <span>etiqueta del elemento. también conocido como en el navegador verá<img src="javascript:alert('XSS!')" />

si ve el código fuente html, verá

<span>"<img src="javascript:alert('XSS!')" />"</span>

Aquí hay más detalles sobre qué es un ataque XSS

React básicamente lo hace para que no pueda insertar marcado a menos que cree los elementos usted mismo en la función de renderizado ... dicho esto, tienen una función que permite tal renderizado, se llama dangerouslySetInnerHTML... aquí hay más detalles al respecto


Editar:

Pocas cosas a tener en cuenta, hay formas de evitar lo que React escapa. Una forma más común es cuando los usuarios definen accesorios para su componente. ¡No extienda ningún dato de la entrada del usuario como accesorios!

John Ruddell
fuente
13
¿Se escapa de todo? De Verdad? React NO es seguro por defecto, hay muchas cosas que tienes que hacer manualmente y atacar vectores que tienes que entender. Todo lo que React hace es escapar de html a una cadena cuando intentas insertarlo con {html}. Pero hay un millón de otras formas de permitir XSS, contra las cuales React NO protege. <a href="{...}" />, <img src = {...} />, <iframe src = "{...} /> y muchos otros accesorios que permiten inyectar javascript ejecutable. Y luego están las inyecciones de script CSS a través de style = {...} prop. La respuesta a continuación de @Marty Aghajanyan en realidad describe los posibles riesgos.
andree
@andree gracias por señalar mi error tipográfico. Es un post de 3 años. Obviamente, hay formas de evitar lo que React escapa y cada desarrollador debería estar cansado de eso.
John Ruddell
Gracias por editar tu respuesta @John Ruddell. No se ofenda, pero su respuesta hizo que React pareciera más seguro de lo que realmente es, y dado que su respuesta es una de las primeras que surge sobre el tema, solo quería señalarlo. Desafortunadamente, este es un tema común que veo en la seguridad general de la interfaz (no solo en React): las cosas parecen seguras o fácilmente asegurables en la superficie, pero cuando profundizas, resulta que hay grandes agujeros. Las preguntas básicas de seguridad deben tener respuestas fáciles de encontrar que se resumen en alguna parte, desafortunadamente esa no es mi experiencia últimamente.
andree
Bueno ... con el tiempo la documentación sale a medida que se prueba la seguridad. Las respuestas que alguna vez fuimos útiles no son tan útiles. La parte difícil es mantener todas las respuestas actualizadas con la tecnología cambiante
John Ruddell