O que significa quando dizem que o React é protegido por XSS?

109

Eu li isso no tutorial React. O que isto significa?

Reagir é seguro. Não estamos gerando strings HTML, então a proteção XSS é o padrão.

Como funcionam os ataques XSS se o React for seguro? Como essa segurança é alcançada?

user1210233
fonte

Respostas:

179

ReactJS é bastante seguro por design, uma vez que

  1. Variáveis ​​de string em visualizações são escapadas automaticamente
  2. Com JSX, você passa uma função como o manipulador de eventos, em vez de uma string que pode conter código malicioso

então um ataque típico como este não 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>

mas ...

❗❗❗Aviso❗❗❗

Ainda existem alguns vetores de ataque XSS que você precisa controlar no React!

1. XSS via dangerouslySetInnerHTML

Quando você usa, dangerouslySetInnerHTMLvocê precisa se certificar de que o conteúdo não contém nenhum javascript. React não pode fazer nada aqui por você.

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 via atributo a.href

Exemplo 1: usando javascript: code

Clique em "Executar snippet de código" -> "Meu site" para ver o 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>

Exemplo 2: usando dados codificados em base64:

Clique em "Executar snippet de código" -> "Meu site" para ver o 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 por meio de props controlados pelo invasor

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>

Aqui estão mais recursos

CyberPanda Consulting
fonte
13
Essa resposta é incrível! Com os trechos de código e as referências no final ...! Obrigado!
Ioanna de
Algum dos exemplos acima foi cuidado pelo React desde que esta resposta foi escrita? Eu estou pedindo, desde que li na seguinte slideshre: slideshare.net/kseniadmitrieva/... tela número 20, que adereços controlado pelo usuário, onde fixados em Reagir 0,14 em 15' de novembro
omer
@omer no, e react decidiu não cuidar desses vetores de ataque no nível React. Aqui estão alguns bons comentários, explicando por que eles não estão sendo processados ​​no nível 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, o problema que você está se referindo era um bug de segurança e foi corrigido, mas o ponto 3 que listei não está relacionado a esse, você ainda pode verificar o trabalho do terceiro ponto executando meu código em qualquer versão de reação.
CyberPanda Consulting
60

O React escapa automaticamente as variáveis ​​para você ... Impede a injeção de XSS via string HTML com Javascript malicioso. Naturalmente, as entradas são higienizadas junto com isso.

Por exemplo, digamos que você tenha esta string

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

se você tentar renderizar esta string em reação

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

você verá literalmente na página toda a string, incluindo o <span> tag elemento. também conhecido como no navegador, você verá<img src="javascript:alert('XSS!')" />

se você visualizar o código HTML, verá

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

Aqui estão mais alguns detalhes sobre o que é um ataque XSS

O React basicamente faz com que você não possa inserir marcação a menos que crie você mesmo os elementos na função de renderização ... dito que eles têm uma função que permite tal renderização é chamada dangerouslySetInnerHTML... aqui estão mais alguns detalhes sobre isso


Editar:

Poucas coisas a serem observadas, há maneiras de contornar o que o React escapa. Outra maneira comum é quando os usuários definem adereços para seu componente. Não estenda nenhum dado da entrada do usuário como suporte!

John Ruddell
fonte
13
Escapa de tudo? Realmente? O React NÃO é seguro por padrão, há muitas coisas que você precisa fazer manualmente e os vetores de ataque que você precisa entender. Tudo o que o React faz é escapar do html para string quando você está tentando inseri-lo com {html}. Mas há um milhão de outras maneiras de permitir XSS, contra as quais o React NÃO protege. <a href="{...}" />, <img src = {...} />, <iframe src = "{...} /> e toneladas de outros adereços que permitem injetar javascript executável. E há as injeções de script CSS por meio de style = {...} prop. A resposta abaixo por @Marty Aghajanyan realmente descreve os possíveis riscos.
andree
@andree obrigado por apontar meu erro de digitação. É um post de 3 anos. Obviamente, existem maneiras de contornar o que o React escapa e cada desenvolvedor deve estar cansado disso.
John Ruddell
Obrigado por editar sua resposta @John Ruddell. Sem ofensa, mas sua resposta fez React parecer mais seguro do que realmente é, e como sua resposta é uma das primeiras que surge sobre o assunto, eu só queria destacar isso. Infelizmente, esse é um tema comum que vejo na segurança geral do front-end (não apenas no React) - as coisas parecem seguras ou facilmente protegíveis na superfície, mas quando você se aprofunda, descobre que há grandes buracos. As perguntas básicas de segurança devem ter respostas fáceis de encontrar e resumidas em algum lugar, infelizmente essa não é minha experiência ultimamente.
andree
Bem ... com o tempo, a documentação sai conforme a segurança é testada. Respostas que já fomos úteis não são tão úteis. A parte difícil é manter todas as respostas atualizadas com a tecnologia em mudança
John Ruddell