Caffeinefreecode logo
Eval: A poderosa, perigosa e incompreendida função do JavaScript
Autor

31/05/2023

Eval: A poderosa, perigosa e incompreendida função do JavaScript

O JavaScript é uma linguagem fantástica.

Mas, por ser uma linguagem com tipagem dinâmica, algumas operações que não fazem sentido algum, ainda assim podem ocorrer. O resultado é mais estranho ainda.

Já tentou somar uma "string" com um número?

const a = 1;
const b = '2';
a + b // 12

E as comparações de igualdade?

0 == []; // true
0 == '0'; // true

// Se 0 == [] e 0 == '0', por inferência então '0' é igual a [] ...

Só que não

'0' == []; // false

Bom, se você tiver paciência e quiser decorar todos os casos de igualdade, você pode acessar este link. Não recomendo.

Mas vamos deixar isso de lado. Quero falar com vocês sobre uma das features mais poderosas e com certeza a mais perigosa do JavaScript. A proibida. A temida. A incompreendida. Vamos deixar outros títulos para você pensar no final do post.

Eval.

Talvez você nunca tenha visto ela. Geralmente ninguém ensina sobre ela nos cursos. Talvez você já tenha utilizado ela e não viu tanto problema assim. Meu foco aqui é justamente essa galera. Acompanha comigo aqui.

Para começar, o que é esse tal eval faz??

Ele basicamente é um método que recebe uma "string" e avalia o resultado dela.

Vamos supor que você precisa fazer uma operação matemática. Para isso, você recebe o input de um usuário com a expressão 2 + 2.

Ao invés de implementar uma calculadora com design patterns, switch cases de operadores e toda uma lógica, você poderia simplesmente usar o 'eval' da seguinte maneira:

const userTextInput = '2+2';
const result = eval(userTextInput);
// result = 4

OMG. Quer dizer que quando eu estava no meu curso e meu professor pediu para eu implementar uma calculadora, ao invés de ter gasto todas aquelas linhas de código, eu poderia ter feito com uma linha?

Sinto muito, mas SIM!!

Então o eval é maravilhoso, imagina as aplicações possíveis com essa função.

O que acontece é que você geralmente vai querer usar eval para avaliar o resultado de alguma expressão da qual a origem é externa. Geralmente um input de um usuário, ou então a comunicação com outra API. Não faz sentido você usar o eval para algo interno. Você já tem a expressão e pode usar o JavaScript para avaliar ela diretamente.

Dito isso, se a fonte é externa precisamos fazer um escape da "string" que será passada para função.

Se você tiver bem claro que tipo de ações você deve permitir que o eval faça, sem problemas. Apenas valide o input de acordo. Acontece que isso é muito difícil de saber. Já estamos usando o eval por justamente não saber o que precisamos avaliar.

Se ainda não está claro, vamos ver alguns pontos que podem facilmente serem explorados

Imagine o seguinte caso de uso.

Estamos criando um Gateway que permite que o usuário manipule as requisições, permitindo que o mesmo altere o corpo da requisição ou os headers. Vamos usar o eval para isso.

Este Gateway também lida com a autenticação e autorização dos usuários.

Vamos imaginar que para criar uma rota no nosso gateway, criamos uma estrutura JSON da seguinte maneira:

{
endpoint: "/posts",
method: "GET",
actions: ["req.body.claims = user.claims"]
}

Repare no atributo actions. Este atributo é onde o usuário passa um conjunto de ações para serem executadas dentro do Gateway antes de fazer o proxy. O Gateway usa o eval para cada uma das strings dentro desse conjunto.

Neste caso estamos dizendo que queremos adicionar no corpo da requisição as claims do usuário.

Obviamente, o usuário conhece que existe a variável user, dentro do escopo do Gateway, que possui no momento da requisição as claims do usuário. Por isso "user.claims".

Primeiro adendo. O usuário que está consumindo o microsserviço do Gateway conhece a implementação do mesmo. O que fere vários princípios de design e arquitetura.

Segundo, agora mesmo você deve estar imaginando o enorme problema que isso pode trazer.

Vamos supor que alguém consegue acesso ao seu Gateway e cria uma rota para sua aplicação.

E ele passa o seguinte JSON para essa rota:

{
endpoint: "/endpoint-nao-seguro",
method: "GET",
actions: ["await user.delete();"]
}

Pronto. Você simplesmente tem uma falha de segurança enorme na sua aplicação apenas devido a um método nativo do JavaScript.

Este é apenas um exemplo. Com um código um pouco mais elaborado você poderia criar um script para roubar os dados dos usuários ou apagar o banco de dados, derrubar o servidor. Inúmeros casos que podem ser explorados.

Portanto, sempre que você se lembrar deste método, evite-o. Principalmente se sua aplicação lidar com dados sensíveis.

Em suma o método eval por si só permite uma variedade enorme de aplicações e usos. O maior problema não é o método, mas é quando ele é usado em aplicações com falhas de design.

E o mais importante, não esqueça de beber sua água hoje.