Pergunta

A função eval é uma maneira poderosa e fácil de gerar dinamicamente código, então o que são as advertências?

Foi útil?

Solução

  1. O uso inadequado de eval abre o seu código para ataques de injeção

  2. Depuração pode ser mais desafiador (Não há números de linha, etc.)

  3. executa o código eval'd mais lento (sem oportunidade de compilação / cache eval'd código)

Edit: Como @ Jeff Walden aponta nos comentários, # 3 é menos verdade hoje do que era em 2008. No entanto, enquanto alguns cache de scripts compilados pode acontecer isso só será limitado a scripts que são eval'd repetidas com nenhuma modificação. Um cenário mais provável é que você está eval'ing scripts que têm ligeira modificação sofrida cada vez e, como tal, não pode ser armazenada em cache. Vamos apenas dizer que algum código eval'd executa mais lentamente.

Outras dicas

eval nem sempre é mau. Há momentos em que é perfeitamente cabível.

No entanto, eval é atualmente e historicamente massivamente mais utilizados por pessoas que não sabem o que estão fazendo. Isso inclui pessoas escrevendo tutoriais JavaScript, infelizmente, e em alguns casos isso pode certamente ter consequências segurança - ou, mais frequentemente, erros simples. Assim, quanto mais podemos fazer para jogar um ponto de interrogação sobre eval, melhor. Toda vez que você usar eval você precisa sanidade-check o que você está fazendo, porque as chances são que você poderia estar fazendo isso de uma maneira melhor, mais seguro, mais limpo.

Para dar um exemplo bastante típico, para definir a cor de um elemento com um id armazenado na variável 'potato':

eval('document.' + potato + '.style.color = "red"');

Se os autores do tipo de código acima teve uma pista sobre as noções básicas de como objetos JavaScript trabalho, eles perceberam que colchetes pode ser usado em vez de ponto-nomes literais, eliminando a necessidade de eval:

document[potato].style.color = 'red';

... que é muito mais fácil de ler, bem como menos potencialmente buggy.

(Mas então, alguém que / realmente / sabiam o que estavam fazendo diria:

document.getElementById(potato).style.color = 'red';

que é mais confiável do que o velho truque desonesto de acessar elementos DOM em linha reta fora do objeto de documento.)

Eu acredito que é porque ele pode executar qualquer função JavaScript a partir de uma string. Usando isso torna mais fácil para as pessoas para injetar código desonestos para o aplicativo.

Dois pontos vêm à mente:

  1. Segurança (mas contanto que você gerar a cadeia a ser avaliada se, isso pode ser um não-problema)

  2. Performance: até que o código a ser executado é desconhecida, não pode ser otimizado. (Cerca de javascript e desempenho, certamente apresentação de Steve Yegge )

Passando a entrada do usuário para eval () é um risco de segurança, mas também cada invocação de eval () cria uma nova instância do interpretador de JavaScript. Isso pode ser um devorador de recursos.

Em geral, é um problema apenas se você estiver passando entrada do usuário eval.

Principalmente, é muito mais difícil de manter e depurar. É como um goto. Você pode usá-lo, mas torna mais difícil de encontrar problemas e mais difícil para as pessoas que podem precisar fazer alterações mais tarde.

Uma coisa a ter em mente é que muitas vezes você pode usar eval () para executar código em um outro ambiente restrito - sites de redes sociais que funciona bloco específico de JavaScript às vezes pode ser enganado por quebrando-os em um bloco de eval -

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Então, se você está olhando para executar um código JavaScript onde não poderiam ser autorizados ( Myspace , eu estou olhando para você ...) então eval () pode ser um truque útil.

No entanto, por todas as razões mencionadas acima, você não deve usá-lo para seu próprio código, onde você tem o controle completo - não é apenas necessário, e melhor-off relegado para a prateleira 'complicadas hacks JavaScript'

A menos que você deixe eval () um conteúdo dinâmico (através do cgi ou entrada), é tão seguro e sólido como todos os outros JavaScript em sua página.

Juntamente com o resto das respostas, eu não acho que as declarações eval pode ter minimização avançada.

É um risco de segurança possível, ele tem um escopo diferente de execução, e é bastante ineficiente, uma vez que cria um inteiramente novo ambiente de script para a execução do código. Veja aqui mais algumas informações:. eval

É bastante útil, embora, e usado com moderação pode adicionar um monte de boa funcionalidade.

A menos que você esteja 100% certo que o código que está sendo avaliada é de uma fonte confiável (geralmente o seu próprio aplicativo), então é uma maneira infalível de expor seu sistema a um ataque de cross-site scripting.

Eu sei que esta discussão é antiga, mas eu realmente gosto este abordagem pelo Google e queria compartilhar esse sentimento com os outros;)

A outra coisa é que o melhor que você começa o mais que você tente entender e, finalmente, você simplesmente não acreditar que algo é bom ou ruim só porque alguém disse isso :) Este é um muito inspirador vídeo que me ajudou a pensar mais por mim :) boas práticas são bom, mas não usá-los mindelessly:)

Não é necessariamente tão ruim desde que você saiba que contexto você está usando-o em.

Se seu aplicativo está usando eval() para criar um objeto de algum JSON que tem de voltar de uma XMLHttpRequest para seu próprio site, criado por seu código do lado do servidor confiável, ele provavelmente não é um problema.

do lado do cliente não confiável código JavaScript não pode fazer isso muito de qualquer maneira. Desde que a coisa que você está executando eval() no veio de uma fonte razoável, você está bem.

Ele reduz significativamente o seu nível de confiança sobre a segurança.

Se você deseja que o usuário inserir algumas funções lógicas e avaliar para E o OR, em seguida, a função JavaScript eval é perfeito. Eu posso aceitar duas cordas e eval(uate) string1 === string2, etc.

Se você detectar o uso de eval () em seu código, lembre-se do “eval () é o mal.” Mantra

Este função toma uma cadeia arbitrária e executa-lo como código JavaScript. Quando o código em questão é conhecido de antemão (não determinado em tempo de execução), não há nenhuma razão para o uso Eval (). Se o código é gerado dinamicamente em tempo de execução, muitas vezes há uma maneira melhor de atingir o objectivo sem Eval (). Por exemplo, apenas usando a notação de colchete para Propriedades de acesso dinâmicos é melhor e mais simples:

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

Usando eval() também tem implicações de segurança, porque você pode estar executando código (para exemplo proveniente da rede) que foi adulterado. Esta é uma antipattern comum quando se trata de uma resposta JSON de uma solicitação Ajax. Nesses casos é melhor usar os navegadores dos built-in métodos para analisar a resposta JSON para make certeza que é seguro e válido. Para navegadores que não suportam JSON.parse() nativamente, você pode usar uma biblioteca de JSON.org.

Também é importante lembrar que as cordas que passam a setInterval(), setTimeout(), e o construtor Function() é, na sua maior parte, semelhante ao uso de eval() e, por conseguinte Deveria ser evitado.

Nos bastidores, JavaScript ainda tem que avaliar e executar a seqüência que você passar como código de programação:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

Usando a nova função () construtor é semelhante ao eval () e deve ser abordado com cuidado. Poderia ser uma construção poderosa, mas muitas vezes é mal utilizado. Se você absolutamente deve uso eval(), você pode considerar o uso de nova função () em vez.

Há um pequeno potencial beneficiar porque o código avaliado em nova função () será executado em uma função local escopo, portanto, quaisquer variáveis ??definidas com var no código que está sendo avaliado não se tornarão Globals automaticamente.

Outra forma de evitar globals automáticos é para embrulhar o chamada eval() em uma função imediata.

Além dos possíveis problemas de segurança se você estiver executando o código enviado pelo usuário, na maioria das vezes não há uma maneira melhor que não envolve re-analisar o código de cada vez que é executado. funções anônimas ou propriedades do objeto pode substituir a maioria dos usos de eval e são muito mais seguro e mais rápido.

Isto pode tornar-se mais de uma questão como a próxima geração de navegadores sair com algum sabor de um compilador JavaScript. Código executado através Eval pode não funcionar tão bem como o resto do seu JavaScript contra esses navegadores mais recentes. Alguém deveria fazer alguma criação de perfis.

Este é um dos bons artigos falando sobre eval e como ele não é um mal: http://www.nczonline.net/ blogue / 2013/06/25 / eval-isnt-mal-just-incompreendido /

Eu não estou dizendo que você deve ir correr para fora e começar a usar eval () em toda parte. Na verdade, existem muito poucos casos de uso para a execução Eval () em tudo. Definitivamente, existem preocupações com clareza código, debugability, e certamente desempenho que não deve ser menosprezada. Mas você não deve ter medo de usá-lo quando você tem um caso em que Eval () faz sentido. Tente não usá-lo em primeiro lugar, mas não deixe que qualquer um susto -lo a pensar o seu código é mais frágil ou menos seguro quando eval () é usada apropriadamente.

eval () é muito poderoso e pode ser usado para executar uma instrução JS ou avaliar uma expressão. Mas a questão não é sobre os usos da eval (), mas vamos apenas dizer que de alguma forma a seqüência que você correndo com eval () é afetado por um partido malicioso. No final você vai estar executando código malicioso. Com o poder vem grande responsabilidade. Para usá-lo sabiamente é que você está usando. Isso não está relacionado muito a eval () função, mas este artigo tem muito bom informações: http://blogs.popart.com/2009/07/javascript-injection- ataques / Se você está procurando as noções básicas de eval () veja aqui: https://developer.mozilla.org/en-US / docs / web / JavaScript / Referência / Global_Objects / eval

Eu não vou tentativa de refutar nada disse até aqui, mas vou oferecer este uso de eval () que (tanto quanto eu sei) não pode ser feito de outra maneira. Há provavelmente outras maneiras de código este, e provavelmente maneiras de otimizar-lo, mas isso é feito escrita comum e sem sinos e assobios por causa clareza para ilustrar um uso de eval que realmente não tem outras alternativas. Ou seja:. Dinâmico (ou mais precisamente) nomes de objetos programmically-criados (em oposição aos valores)

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

EDIT: a propósito, eu não iria sugerir (para todas as razões de segurança apontado até então) que você basear sua objeção nomes na entrada do usuário. Eu não posso imaginar qualquer razão que você gostaria de fazer isso, porém. Ainda assim, pensei que iria indicá-lo que não seria uma boa ideia:)

O motor JavaScript tem uma série de otimizações de desempenho que executa durante a fase de compilação. Algumas delas se resumem a ser capaz de analisar essencialmente estaticamente o código como lexes e pré-determinar onde todas as declarações a variável e de função são, de modo que é preciso menos esforço para identificadores de resolver durante a execução.

Mas, se o motor encontra um eval (..) no código, que essencialmente tem que assumir que toda a sua consciência de identificador de localização pode ser inválido, porque não pode saber em lexing tempo exatamente o código que você pode passar para eval ( ..) para modificar o escopo léxico, ou o conteúdo do objeto que você pode passar para com para criar um novo escopo léxico de ser consultado.

Em outras palavras, no sentido pessimista, a maioria dessas otimizações que faria são inúteis se eval (..) está presente, por isso simplesmente não executar as otimizações em tudo.

Isso explica tudo.

Referência:

https: //github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https: //github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

Não é sempre uma má idéia. Tomemos por exemplo, geração de código. Eu escrevi recentemente uma biblioteca chamada Hyperbars que preenche a lacuna entre virtual dom e guidão . Ele faz isso por analisar um modelo de guidão e convertê-lo para hyperscript que é posteriormente utilizado pelo Virtual-dom. O hyperscript é gerada como uma string em primeiro lugar e antes de devolvê-lo, eval()-lo para transformá-lo em código executável. Eu descobri eval() nesta situação particular, exatamente o oposto do mal.

Basicamente a partir

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

Para este

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

O desempenho dos eval() não é um problema em uma situação como esta, porque você só precisa interpretar a cadeia gerada uma vez e, em seguida, reutilizar a saída executável muitas vezes.

Você pode ver como a geração de código foi conseguido Se você está curioso aqui .

Eu iria tão longe a ponto de dizer que ele realmente não importa se você usar eval() em javascript que é executado em browsers. * (Advertência)

Todos os navegadores modernos têm um console do desenvolvedor, onde você pode executar arbitrária javascript de qualquer maneira e qualquer desenvolvedor semi-inteligente pode olhar para a sua fonte JS e colocar o que pedaços de que eles precisam para o console dev para fazer o que quiserem.

* Enquanto seus endpoints servidor têm a validação correta e sanitização dos valores fornecidos pelo usuário, não deve importa o que é analisado e eval'd em sua javascript do lado do cliente.

Se você fosse perguntar se é adequado para uso eval() em PHP no entanto, a resposta é NÃO , a menos que você whitelist quaisquer valores que podem ser passados ??para sua declaração eval .

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top