Estou escrevendo algum código JavaScript para analisar funções inseridas pelo usuário (para funcionalidade semelhante a planilha). Tendo analisado a fórmula, eu poderia convertê-lo em JavaScript e executá eval()
-lo para produzir o resultado.
No entanto, sempre evitei usá-lo, eval()
se posso evitá-lo porque é ruim (e, com ou sem razão, sempre achei que é ainda mais ruim no JavaScript, porque o código a ser avaliado pode ser alterado pelo usuário )
Então, quando é bom usá-lo?
javascript
coding-style
eval
Richard Turner
fonte
fonte
Respostas:
Gostaria de dedicar um momento para abordar a premissa de sua pergunta - que eval () é " mau ". A palavra " mal ", usada pelas pessoas da linguagem de programação, geralmente significa "perigoso", ou mais precisamente "capaz de causar muitos danos com um comando simples". Então, quando é bom usar algo perigoso? Quando você souber qual é o perigo e quando estiver tomando as precauções apropriadas.
Ao ponto, vamos olhar para os perigos no uso de eval (). Provavelmente existem muitos pequenos perigos ocultos, como todo o resto, mas os dois grandes riscos - a razão pela qual eval () é considerado mau - são desempenho e injeção de código.
Para o seu caso específico. Pelo que entendi, você mesmo está gerando as seqüências de caracteres, assumindo o cuidado de não permitir que uma sequência como "rm -rf algo importante" seja gerada, não há risco de injeção de código (mas lembre-se, é muito difícil garantir isso no caso geral). Além disso, se você estiver executando no navegador, a injeção de código é um risco bem menor, acredito.
Quanto ao desempenho, você terá que ponderar isso contra a facilidade de codificação. É minha opinião que se você estiver analisando a fórmula, é melhor calcular o resultado durante a análise, em vez de executar outro analisador (o que está dentro de eval ()). Mas pode ser mais fácil codificar usando eval (), e o resultado do desempenho provavelmente será imperceptível. Parece que eval () neste caso não é mais mau do que qualquer outra função que possa poupar algum tempo.
fonte
eval()
do seu servidor, ele também poderá alterar a fonte da página e também controlar as informações do usuário. . . Eu não vejo a diferença.eval()
não é mau. Ou, se for, é ruim da mesma maneira que reflexão, E / S de arquivo / rede, encadeamento e IPC são "ruins" em outros idiomas.Se, para o seu propósito ,
eval()
é mais rápido que a interpretação manual, ou torna seu código mais simples ou mais claro ... então você deve usá-lo. Se não, então você não deveria. Simples assim.fonte
Quando você confia na fonte.
No caso do JSON, é mais ou menos difícil adulterar a fonte, porque ela vem de um servidor da web que você controla. Desde que o próprio JSON não contenha dados que um usuário fez upload, não há grande desvantagem em usar o eval.
Em todos os outros casos, eu me esforçava muito para garantir que os dados fornecidos pelo usuário estivessem em conformidade com minhas regras antes de alimentá-los para avaliar ().
fonte
eval
também não analisará corretamente todas as cadeias JSON válidas. Por exemplo,JSON.parse(' "\u2028" ') === "\u2028"
maseval(' "\u2028" ')
gera uma exceção porque U + 2028 é uma nova linha em JavaScript, mas não é uma nova linha no que diz respeito ao JSON.Vamos ter gente de verdade:
Agora, todos os principais navegadores têm um console interno que seu possível hacker pode usar com abundância para invocar qualquer função com qualquer valor - por que eles se incomodariam em usar uma declaração de avaliação - mesmo que pudessem?
Se demorar 0,2 segundos para compilar 2000 linhas de JavaScript, qual é a minha degradação de desempenho se avaliar quatro linhas de JSON?
Até a explicação de Crockford para 'eval é mau' é fraca.
Como o próprio Crockford pode dizer: "Esse tipo de afirmação tende a gerar neurose irracional. Não compre".
Compreender a avaliação e saber quando isso pode ser útil é muito mais importante. Por exemplo, eval é uma ferramenta sensata para avaliar as respostas do servidor que foram geradas pelo seu software.
BTW: Prototype.js chama eval diretamente cinco vezes (incluindo em evalJSON () e evalResponse ()). O jQuery usa-o em parseJSON (via construtor Function).
fonte
I tendem a seguir o conselho do Crockford para
eval()
, e evitá-lo completamente. Mesmo as maneiras que parecem exigir isso não o fazem. Por exemplo, osetTimeout()
permite passar uma função em vez de avaliar.Mesmo que seja uma fonte confiável , eu não a uso, porque o código retornado pelo JSON pode ser ilegível, o que pode, na melhor das hipóteses, fazer algo complicado, na pior das hipóteses, expor algo ruim.
fonte
Vi pessoas advogadas a não usar eval, porque é ruim , mas vi as mesmas pessoas usarem Function e setTimeout dinamicamente, então elas usam eval sob os capuzes : D
BTW, se a sua sandbox não tiver certeza suficiente (por exemplo, se você estiver trabalhando em um site que permita a injeção de código), eval é o último dos seus problemas. A regra básica de segurança é que todas as entradas são ruins, mas, no caso do JavaScript, até o próprio JavaScript pode ser ruim, porque no JavaScript você pode sobrescrever qualquer função e não pode ter certeza de que está usando a real; se um código malicioso iniciar antes de você, você não poderá confiar em nenhuma função interna do JavaScript: D
Agora, o epílogo deste post é:
Se você REALMENTE precisar dele (80% do tempo de avaliação NÃO é necessário) e tiver certeza do que está fazendo, basta usar eval (ou melhor Função;)), fechamentos e POO cobrem 80/90% do caso o eval possa ser substituído usando outro tipo de lógica, o restante será um código gerado dinamicamente (por exemplo, se você estiver escrevendo um intérprete) e, como você já disse, avaliando o JSON (aqui você pode usar a avaliação segura de Crockford;))
fonte
O Eval é complementar à compilação, que é usada na modelagem do código. Por modelo, quero dizer que você escreve um gerador de modelos simplificado que gera código de modelo útil que aumenta a velocidade de desenvolvimento.
Eu escrevi uma estrutura em que os desenvolvedores não usam EVAL, mas eles usam nossa estrutura e, por sua vez, essa estrutura precisa usar EVAL para gerar modelos.
O desempenho de EVAL pode ser aumentado usando o seguinte método; em vez de executar o script, você deve retornar uma função.
Deve ser organizado como
O armazenamento em cache f certamente melhorará a velocidade.
Além disso, o Chrome permite a depuração de tais funções com muita facilidade.
Em relação à segurança, usar eval ou não dificilmente fará diferença,
Se a segurança do servidor for sólida o suficiente para qualquer um atacar de qualquer lugar, não se preocupe com o EVAL. Como mencionei, se o EVAL não existir, os invasores terão muitas ferramentas para invadir seu servidor, independentemente da capacidade de EVAL do seu navegador.
O Eval é bom apenas para gerar alguns modelos para executar um processamento complexo de strings com base em algo que não é usado previamente. Por exemplo, eu vou preferir
Ao contrário de
Como meu nome de exibição, que pode vir de um banco de dados e que não é codificado.
fonte
function (first, last) { return last + ' ' + first }
.eval
é principalmente outros usuários . Digamos que você tenha uma página de configurações e permite definir como o seu nome será exibido para outras pessoas. Digamos também que você não estava pensando muito claramente quando o escreveu, portanto, sua caixa de seleção tem opções como<option value="LastName + ' ' + FirstName">Last First</option>
. Abro minhas ferramentas de desenvolvimento, altero avalue
opção dealert('PWNED!')
, seleciono a opção alterada e envio o formulário. Agora, sempre que outra pessoa puder ver meu nome de exibição, esse código será executado.eval
é executar código que não faz parte do script que você escreveu. Se você não precisa do poder para fazer isso (e quase nunca o faz), evitareval
ajuda a afastar uma categoria inteira de problemas. Isso é bom se o código do servidor não for perfeito.Ao depurar no Chrome (v28.0.1500.72), descobri que as variáveis não estão vinculadas aos fechamentos se não forem usadas em uma função aninhada que produz o fechamento. Eu acho que é uma otimização do mecanismo JavaScript.
MAS : quando
eval()
é usado dentro de uma função que causa um fechamento, TODAS as variáveis de funções externas são vinculadas ao fechamento, mesmo que não sejam usadas. Se alguém tiver tempo para testar se é possível produzir vazamentos de memória, deixe um comentário abaixo.Aqui está o meu código de teste:
O que eu gostaria de destacar aqui é que eval () não deve necessariamente se referir à
eval()
função nativa . Tudo depende do nome da função . Portanto, ao chamar o nativoeval()
com um nome alternativo (digamosvar noval = eval;
e depois em uma função internanoval(expression);
), a avaliação deexpression
pode falhar quando se refere a variáveis que devem fazer parte do fechamento, mas na verdade não são.fonte
A Microsoft explica por que eval () é lento no navegador no IE Blog, Recomendações de desempenho do IE + JavaScript Parte 2: Ineficiências do código JavaScript .
fonte
Bottom Line
Se você criou ou higienizou o código
eval
, nunca é mau .Um pouco mais detalhado
eval
é ruim se estiver executando no servidor usando a entrada enviada por um cliente que não foi criado pelo desenvolvedor ou que não foi higienizado pelo desenvolvedor .eval
não é ruim se estiver sendo executado no cliente, mesmo se você estiver usando entradas não autorizadas criadas pelo cliente .Obviamente, você deve sempre limpar a entrada, para ter algum controle sobre o que seu código consome.
Raciocínio
O cliente pode executar qualquer código arbitrário que desejar, mesmo que o desenvolvedor não tenha codificado; Isso é verdade não apenas para o que é avaliado, mas para o chamado a
eval
si mesmo .fonte
A única instância em que você deve usar eval () é quando você precisa executar JS dinâmico em tempo real. Estou falando de JS que você baixa assincronamente do servidor ...
... E 9 vezes em 10, você poderia facilmente evitar isso refatorando.
fonte
eval
raramente é a escolha certa. Embora possa haver inúmeras instâncias em que você pode realizar o que precisa realizando concatenando um script e executando-o em tempo real, normalmente você tem técnicas muito mais poderosas e de manutenção à sua disposição: notação de matriz associativa (obj["prop"]
é a mesma queobj.prop
) , fechamentos, técnicas orientadas a objetos, técnicas funcionais - use-as.fonte
No que diz respeito ao script do cliente, acho que a questão da segurança é um ponto discutível. Tudo o que é carregado no navegador está sujeito a manipulação e deve ser tratado como tal. Não há risco zero no uso de uma instrução eval () quando existem maneiras muito mais fáceis de executar o código JavaScript e / ou manipular objetos no DOM, como a barra de URL no seu navegador.
Se alguém quiser manipular seu DOM, eu digo afaste-se. A segurança para impedir qualquer tipo de ataque deve sempre ser de responsabilidade do aplicativo do servidor, ponto final.
Do ponto de vista pragmático, não há benefício em usar um eval () em uma situação em que as coisas podem ser feitas de outra maneira. No entanto, existem casos específicos em que uma avaliação DEVE ser usada. Nesse caso, definitivamente pode ser feito sem nenhum risco de explodir a página.
fonte
<head></head>
necessário, mesmo que vazio?No lado do servidor, eval é útil quando se lida com scripts externos, como sql ou influxdb ou mongo. Onde a validação personalizada em tempo de execução pode ser feita sem reimplementar seus serviços.
Por exemplo, um serviço de conquista com os seguintes metadados
Que então permitem,
Injeção direta de objetos / valores através de uma string literal em um json, útil para modelar textos
Pode ser usado como um comparador, digamos que criamos regras para validar missões ou eventos no CMS
Con disso:
Pode haver erros no código e interromper as coisas no serviço, se não for totalmente testado.
Se um hacker pode escrever um script no seu sistema, você está praticamente ferrado.
Uma maneira de validar seu script é manter o hash dos scripts em algum lugar seguro, para que você possa verificá-los antes da execução.
fonte
Eu acho que qualquer caso de avaliação sendo justificado seria raro. É mais provável que você o use pensando que é justificado do que quando for realmente justificado.
Os problemas de segurança são os mais conhecidos. Mas saiba também que o JavaScript usa a compilação JIT e isso funciona muito mal com o eval. O Eval é um pouco como uma caixa preta para o compilador, e o JavaScript precisa prever o código com antecedência (até certo ponto) para aplicar com segurança e corretamente otimizações e escopo de desempenho. Em alguns casos, o impacto no desempenho pode até afetar outro código fora da avaliação.
Se você quiser saber mais: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval
fonte
Não há problema em usá-lo se você tiver controle total sobre o código que é passado para a
eval
função.fonte
eval
, a grande questão é: quando faz sentido que isso seja uma cadeia de caracteres em vez de um JS real?<script async="true" src="...">
. Veja também: w3bits.com/async-javascriptSomente durante o teste, se possível. Observe também que eval () é muito mais lento que outros avaliadores especializados em JSON etc.
fonte
Não há razão para não usar eval (), desde que você tenha certeza de que a fonte do código vem de você ou do usuário real. Embora ele possa manipular o que é enviado para a função eval (), isso não é um problema de segurança, porque ele é capaz de manipular o código fonte do site e, portanto, pode alterar o próprio código JavaScript.
Então ... quando não usar eval ()? Eval () não deve ser usado apenas quando houver uma chance de terceiros alterá-lo. Como interceptar a conexão entre o cliente e o servidor (mas se houver algum problema, use HTTPS). Você não deve avaliar () para analisar o código que é escrito por outras pessoas, como em um fórum.
fonte
eval
de uma sequência composta de conteúdo de um usuário pode permitir que ele execute código no navegador de outro usuário.eval
. Isso acontece o tempo todo.eval
. Como é útil culpar o servidor? Se alguém deve ser responsabilizado, deve ser o atacante. Independentemente da culpa, um cliente que não é vulnerável ao XSS, apesar dos erros no servidor, é melhor que um cliente vulnerável, sendo o resto igual.Se é realmente necessário, avaliar não é mau. Mas 99,9% dos usos de eval que eu tropeço não são necessários (não incluindo coisas de setTimeout).
Para mim, o mal não é uma performance ou mesmo um problema de segurança (bem, indiretamente, são os dois). Todos esses usos desnecessários de eval contribuem para um inferno de manutenção. Ferramentas de refatoração são descartadas. A pesquisa de código é difícil. Os efeitos imprevisíveis dessas avaliações são numerosos.
fonte
Quando o eval () do JavaScript não é mau?
Estou sempre tentando desencorajar o uso de eval . Quase sempre, está disponível uma solução mais limpa e sustentável. O Eval não é necessário mesmo para a análise JSON . Eval contribui para o inferno da manutenção . Não sem razão, é desaprovado por mestres como Douglas Crockford.
Mas encontrei um exemplo em que deveria ser usado:
Quando você precisa passar a expressão.
Por exemplo, eu tenho uma função que constrói um
google.maps.ImageMapType
objeto geral para mim, mas preciso informar a receita, como deve construir a URL do bloco a partir dos parâmetroszoom
ecoord
:fonte
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Meu exemplo de uso
eval
: import .Como é geralmente feito.
Mas com a ajuda
eval
e uma pequena função auxiliar, ele fica com uma aparência muito melhor:importable
pode parecer (esta versão não suporta a importação de membros concretos).fonte
.replace(/name/g, name).replace('path', path)
. Sename
contiver a string"path"
, você poderá obter surpresas.components
é um possível cheiro de código; refatorar seu código pode eliminar completamente o 'problema'. Sua solução atual é apenas açúcar sintático. Se você insistir em fazer isso, recomendo que você escreva seu próprio pré-processador, a ser executado antes da implantação. Isso deve ficareval
longe do código de produção.Eval não é mau, apenas mal utilizado.
Se você criou o código ou pode confiar nele, tudo bem. As pessoas continuam falando sobre como a entrada do usuário não importa com a avaliação. Bem, tipo de ~
Se houver uma entrada do usuário que vá para o servidor, ela retornará ao cliente e esse código será usado na avaliação sem ser higienizado. Parabéns, você abriu a caixa da pandora para que os dados do usuário sejam enviados para quem quer que seja.
Dependendo de onde a avaliação está, muitos sites usam SPAs, e a avaliação poderia facilitar o acesso do usuário a aplicativos internos que, de outra forma, não teriam sido fáceis. Agora eles podem criar uma extensão de navegador falsa que pode gravar nessa avaliação e roubar dados novamente.
Só preciso descobrir qual é o sentido de você usar a avaliação. Gerar código não é realmente ideal quando você pode simplesmente criar métodos para fazer esse tipo de coisa, usar objetos ou algo parecido.
Agora, um bom exemplo do uso de eval. Seu servidor está lendo o arquivo de arrogância que você criou. Muitos dos parâmetros de URL são criados no formato
{myParam}
. Portanto, você gostaria de ler os URLs e convertê-los em seqüências de caracteres de modelo sem precisar fazer substituições complexas, porque você tem muitos pontos de extremidade. Então você pode fazer algo assim. Observe que este é um exemplo muito simples.fonte
Geração de código. Recentemente, escrevi uma biblioteca chamada Hyperbars, que preenche a lacuna entre o virtual-dom e o guidão . Isso é feito analisando um modelo de guidão e convertendo-o em hiperescrito . O hiperescrito é gerado como uma string primeiro e, antes de devolvê-lo,
eval()
transforma-o em código executável. eu encontreieval()
nessa situação em particular o exato oposto do mal.Basicamente de
Para isso
O desempenho de
eval()
não é um problema em uma situação como essa também porque você só precisa interpretar a sequência gerada uma vez e, em seguida, reutilizar a saída executável várias vezes.Você pode ver como a geração de código foi alcançada se você estiver curioso aqui .
fonte
eval
uma dica de que alguma responsabilidade que pertence no tempo de compilação se mudou para o tempo de execução.Minha opinião é que eval é uma função muito poderosa para aplicativos Web do lado do cliente e é seguro ... Tão seguro quanto o JavaScript, que não é. :-) Os problemas de segurança são essencialmente um problema do lado do servidor porque, agora, com ferramentas como o Firebug, você pode atacar qualquer aplicativo JavaScript.
fonte
eval
precisa ser protegido contra ataques XSS, o que nem sempre é fácil de corrigir.O Eval é útil para geração de código quando você não possui macros.
Por exemplo (estúpido), se você estiver escrevendo um compilador Brainfuck , provavelmente desejará construir uma função que execute a sequência de instruções como uma string e avaliar para retornar uma função.
fonte
eval
.eval
, quando a alternativa ( Função ) é mais rápida ( como explicada no MDN ) e mais confiável (evita erros imprevisíveis pelo melhor isolamento entre o código gerado e outro código 'de suporte' na mesma página da web).Quando você analisa uma estrutura JSON com uma função de análise (por exemplo, jQuery.parseJSON), espera uma estrutura perfeita do arquivo JSON (cada nome de propriedade está entre aspas duplas). No entanto, o JavaScript é mais flexível. Portanto, você pode usar eval () para evitá-lo.
fonte
eval
, esp. ao obter dados JSON de uma fonte de terceiros. Consulte JSON.Stringify sem aspas nas propriedades? para a abordagem correta para analisar "JSON sem nomes de chave entre aspas".string
ae define astring
como uma sequência de zero ou mais caracteres Unicode, agrupados entre aspas duplas, usando escapes de barra invertida.eval
. Em qualquer aplicativo Web sério com vários inquilinos, com dezenas de desenvolvedores trabalhando na mesma base de código, isso é inaceitável.