Três erros comuns de segurança que todo desenvolvedor de reagentes deve conhecer

A autora do artigo, cuja tradução estamos publicando hoje, diz que React é sua biblioteca favorita para criar interfaces interativas. O React é fácil de usar e razoavelmente bem protegido. No entanto, isso não significa que os aplicativos React sejam completamente invulneráveis. É muito fácil cair na calma injustificada, tendo decidido que você não pode se preocupar com ataques de XSS devido ao fato de o projeto usar o React.

As vulnerabilidades no React ocorrem com mais freqüência quando um desenvolvedor pensa que está usando os mecanismos de proteção desta biblioteca, embora na verdade aconteça que isso não é verdade. Portanto, é importante avaliar corretamente os recursos do React e saber quais tarefas um programador precisa resolver sozinho.



Hoje falaremos sobre vulnerabilidades típicas do React, como encontrá-las durante uma revisão de código e como se defender contra elas.

Primeiro exemplo de script entre sites (muito curto)


O script entre sites (XSS) é uma vulnerabilidade do cliente que pode levar a problemas sérios. Os ataques XSS ocorrem quando um invasor consegue enganar um site e forçá-lo a executar código JavaScript arbitrário nos navegadores de seus usuários.

O ataque XSS refletido é realizado por meio de um link contendo informações textuais processadas pelo navegador na forma de código. Por exemplo, este é um campo de formulário no qual, no lado do cliente, um texto de solicitação especial é inserido.

Um ataque XSS armazenado é uma situação em que um invasor tem acesso ao servidor e quando o código executado no servidor gera o que chega à página da web do cliente. Vetores típicos de tais ataques estão enviando comentários e imagens para os servidores.

O worm Samy explorou a vulnerabilidade do MySSpace XSS. Foi um dos vírus que se espalhou mais rapidamente de todos os tempos.

Sites vulneráveis ​​podem expor seus usuários a roubo de senhas ou dados pessoais. E esta é a maneira usual de explorar outras vulnerabilidades. Os scripts maliciosos costumam ser usados ​​para enviar spam e redirecionar usuários para sites fraudulentos. Isso pode prejudicar a reputação e o desempenho de SEO de um site atacado com sucesso.

Vulnerabilidade # 1: controle sobre o estado inicial da página, usado durante a renderização do servidor


Às vezes, quando formamos o estado inicial de uma página, nós, o que é perigoso, criamos um documento com base em uma string JSON. Essa vulnerabilidade no código se parece com isso:

<script>window.__STATE__ = ${JSON.stringify({ data })}</script> 

Isso é perigoso porque o método JSON.stringify() , sem "pensar" em nada, converte todos os dados fornecidos na forma de string (desde que sejam dados JSON válidos), que é o que será exibido na página. Se { data } tiver campos que um usuário não confiável possa editar, como um nome de usuário ou informações do usuário, algo como o seguinte poderá ser incorporado nesses campos:

 { username: "pwned", bio: "</script><script>alert('XSS Vulnerability!')</script>" } 

Esse padrão é frequentemente usado na renderização do lado do servidor de aplicativos React que usam Redux. Ele estava presente na documentação oficial do Redux e, como resultado, muitos tutoriais e modelos de aplicativos de amostra que podem ser encontrados no GitHub ainda o usam.

Não acredita? Então veja por si mesmo. Pesquise no Google o texto "aplicativo de exemplo de renderização do lado do servidor" e tente este ataque em qualquer um dos resultados da pesquisa da primeira página.

▍ Identificação de vulnerabilidade durante a revisão de código


Procure chamadas para o método JSON.stringify() que aceita variáveis ​​que podem conter dados não confiáveis ​​na tag de script . Aqui está um exemplo que costumava estar na documentação do Redux:

 function renderFullPage(html, preloadedState) {    return `        <!doctype html>        <html>            <head>                <title>Redux Universal Example</title>            </head>            <body>                <div id="root">${html}</div>                <script>                    window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}                </script>                <script src="/static/bundle.js"></script>            </body>        </html>        ` } 

E aqui está um trecho de código do aplicativo de amostra encontrado no GitHub:

 function htmlTemplate( reactDom, reduxState, helmetData ) {    return `    <!DOCTYPE html>    <html>    <head>        <meta charset="utf-8">        ${ helmetData.title.toString( ) }        ${ helmetData.meta.toString( ) }        <title>React SSR</title>        <link rel="stylesheet" type="text/css" href="./styles.css" />    </head>       <body>        <div id="app">${ reactDom }</div>        <script>            window.REDUX_DATA = ${ JSON.stringify( reduxState ) }        </script>        <script src="./app.bundle.js"></script>    </body>    </html>    `;   } 

Às vezes, encontrar essa vulnerabilidade é um pouco mais difícil. O código a seguir também será inseguro - se a fuga correta de context.data não context.data executada:

 const RenderedApp = htmlData.replace('{{SSR}}', markup)    .replace('<meta-head/>', headMarkup)    .replace('{{data}}', new ArrayBuffer(JSON.stringify(context.data)).toString('base64')) 

Ao fazer a renderização no servidor, preste atenção no que exatamente está sendo renderizado. Se o que o usuário digitar não for adequadamente protegido e exibido no DOM, isso pode ser perigoso.

▍ Proteção


Uma das opções para proteção contra essa vulnerabilidade é usar o módulo serialize-javascript npm, projetado para proteger o JSON de saída. Se você estiver processando o servidor em um ambiente que não seja o Node.js., precisará escolher o pacote apropriado para o seu idioma.

Aqui está o comando para instalar o módulo:

 $ npm install --save serialize-javascript 

Depois disso, você precisa importá-lo para um arquivo e reescrever o código vulnerável anteriormente que lida com a window seguinte maneira:

 <script>window.__STATE__ = ${ serialize( data, { isJSON: true } ) }</script> 

Aqui está um ótimo artigo sobre esse assunto.

Vulnerabilidade №2: elos insidiosos


A tag <a> pode ter o atributo href , que contém um link para outra página do site, para outro site, para algum lugar da página atual. Os links podem conter scripts parecidos com este: javascript: stuff() . Se você não conhecia esse recurso HTML, tente agora copiando o seguinte código na linha do navegador:

 data:text/html, <a href="javascript: alert('hello from javascript!')" >click me</a> 

Para desenvolvedores da Web, isso significa que, se o conteúdo dos links for definido com base nos dados inseridos pelo usuário, um invasor poderá adicionar código malicioso começando com javascript: a esses dados. Em seguida, se o usuário clicar em um link incorreto, um script de invasor será iniciado no navegador.

Essa vulnerabilidade definitivamente não é apenas uma característica do React, mas é um dos problemas que os desenvolvedores do React geralmente encontram quando esperam que o valor correspondente seja automaticamente escapado corretamente. Note-se que em uma versão futura do React esse problema será menos agudo.

▍ Identificação de vulnerabilidade durante a revisão de código


Os usuários do projeto podem adicionar links a páginas nas quais outros usuários podem clicar? Nesse caso, tente adicionar um "link" à página como o seguinte:

 javascript: alert("You are vulnerable to XSS!") 

Se a caixa de mensagem correspondente for exibida clicando no link, isso significa que o projeto está vulnerável a ataques XSS. Tente isso sempre que você puder adicionar links. É provável que nem todos esses lugares sejam vulneráveis.

▍ Proteção


A proteção contra essa vulnerabilidade não é apenas adequada para projetos React. O que exatamente precisa ser feito depende do aplicativo. Além disso, pode ser necessário fazer correções no servidor.

Você pode pensar que, para resolver o problema, basta remover o prefixo javascript: dos dados. Este é um exemplo de uso da estratégia de lista negra, que não pode ser considerada bem-sucedida na limpeza de dados . Os hackers têm maneiras engenhosas de ignorar esses filtros; portanto, em vez de uma mudança (ou em adição a ela), faça com que os links usem um protocolo na lista de permissões (por exemplo, http: e escape de entidades HTML. Aqui está um artigo detalhado sobre esse tópico sobre a proteção de propriedades que um invasor pode controlar.

Outra estratégia que pode adicionar um nível adicional de proteção ao projeto é usar o mecanismo para abrir links personalizados em novas guias do navegador. No entanto, eu não recomendaria o uso dessa estratégia como a única "linha de defesa" do projeto. Abrir javascript: links em uma nova guia é um exemplo do comportamento não padrão dos elementos da página. A maioria dos navegadores executará o script em uma guia vazia sem prejudicar o usuário, mas isso não é garantido e você provavelmente pode contornar isso, o que depende do navegador.

Considere usar o componente UserLink especial, o que levará ao fato de que a tag <a> vulnerável tem menos probabilidade de chegar às páginas do seu projeto no futuro. Além disso, vale a pena adicionar alguns testes e regras de fiapos ao projeto, com o objetivo de identificar códigos potencialmente perigosos e impedir que eles entrem em produção.

Os links não são as únicas entidades que podem ser usadas dessa maneira. Mas eles são o alvo de ataque mais provável nos aplicativos React. Qualquer elemento pode ser vulnerável a esse ataque se o invasor puder controlar seu valor de URI . Outra possibilidade de realizar esse ataque, por exemplo, é um design de exibição. Uma lista completa dos atributos que podem conter URIs pode ser encontrada nesta lista usando a palavra-chave %URI usando a pesquisa do navegador ( Ctrl+F ).

Vulnerabilidade # 3: entender mal o significado da construção de forma perigosaSetInnerHtml


Sou extremamente grato a React que o aviso de segurança está diretamente no nome do método. Esse é o nome dangerouslySetInnerHTML . Apesar desse aviso, ainda somos frequentemente confrontados com o fato de que os desenvolvedores assumem riscos executando operações inseguras. O mesmo pode ser dito de eval() .

Considere o seguinte exemplo que encontrei no site na primeira página dos resultados de pesquisa do Google:

 <script dangerouslySetInnerHTML={{ __html: `window.__PRELOADED_STATE__ = ${JSON.stringify(initialState)};`}}></script> 

Este é um exemplo de vulnerabilidade nº 1, mas com um recurso que deve chamar imediatamente a atenção para o fato de que algo está errado aqui. Onde descobri isso, foi feita uma tentativa de explicar: "Usamos perigosamente o SetInnerHTML como um método de limpeza de dados e prevenção de ataques XSS". Bem, não! Isto está errado. Não faça isso. Para obter mais informações sobre o dangerouslySetInnerHTML , leia a documentação do React.

Outro exemplo de que isso acontece o tempo todo é como membros de uma equipe descobriram que tinham uma vulnerabilidade quando adicionaram a marcação Markdown a uma página usando dangerouslySetInnerHTML . Para se protegerem disso no futuro, eles começaram a usar uma regra especial de fiapos.

▍ Identificação de vulnerabilidade durante a revisão de código


Antes de enviar solicitações de recebimento ou executar operações de mesclagem, é útil procurar no código por seqüências dangerouslySetInnerHTML e eval (também procuro comandos console.log dessa maneira) ou usar a regra de linter correspondente.

▍ Proteção


Verifique se, em todos os casos de uso do método dangerouslySetInnerHTML , apenas os dados confiáveis ​​podem ser carregados na página. Como você sabe se os dados podem ser confiáveis? Se algo não vier de você, pode ser uma ameaça. Isso inclui dados baixados de APIs externas e o que é emitido usando as ferramentas Markdown.

Nota de falsificação de componente


Em 2015, alguém descobriu que você pode falsificar componentes passando JSON para os componentes que esperam texto. Consegui encontrar apenas um caso de uma mensagem de falsificação de componente e uma longa discussão causada por essa mensagem. A discussão se concentrou no que o React é responsável por impedir ataques XSS. Como resultado, os desenvolvedores do React lançaram uma correção que parece ter ajudado a corrigir essa vulnerabilidade.

Decidi não incluir uma história sobre essa vulnerabilidade no artigo, mas esse tópico pode ser interessante para futuras pesquisas.

Nota SSR


A vulnerabilidade de renderização do servidor é tão generalizada devido ao fato de estar presente na documentação do Redux e, como resultado, espalhada por muitos outros materiais. Este problema foi corrigido em 2016. Mas ainda hoje, depois de três anos, os guias para iniciantes espalhados por toda a Internet ainda ensinam o que você não deve ensinar.

A propósito, aqui está sua lição de casa: encontre um exemplo desse problema no GitHub e envie uma solicitação pull para corrigi-lo. Aqui está um exemplo .

Juntos, podemos, de uma vez por todas, nos livrar dessa vulnerabilidade!

Caros leitores! Você encontrou ataques nos seus projetos React?

Source: https://habr.com/ru/post/pt467255/


All Articles