Quais são especificamente os perigos de eval (parse (…))?

Existem várias questões sobre como evitar o uso de eval(parse(...))

  • r-evalparse-é-frequentemente-suboptimal
  • evitando-o-infamous-evalparse-construct

O que desencadeia as perguntas:

  • Por que especificamente eval(parse()) ser evitado?
  • E o mais importante, quais são os perigos?
    • Há algum perigo se o código não for usado na produção? (Eu estou pensando, qualquer perigo de obter resultados não intencionais. Claramente, se você não for cuidadoso com o que está analisando, você terá problemas. Mas isso é mais perigoso do que ser desleixado com get() ?)

A maioria dos argumentos contra eval(parse(...)) surgem não por causa de preocupações de segurança, afinal, nenhuma alegação é feita sobre R ser uma interface segura para expor à Internet, mas sim porque esse código geralmente está fazendo coisas que pode ser realizado usando methods menos obscuros, ou seja, methods que são mais rápidos e mais humanos. A linguagem R deve ser de alto nível, então a preferência dos cognoscenti (e eu não me considero nesse grupo) é ver código que seja ao mesmo tempo compacto e expressivo.

Assim, o perigo é que o eval(parse(..)) é um método alternativo de contornar a falta de conhecimento e a esperança de aumentar essa barreira é que as pessoas melhorem o uso da linguagem R. A porta permanece aberta, mas a esperança é de uso mais expressivo de outros resources. A questão de Carl Witthoft, hoje, ilustrou não saber que a function get estava disponível, e a questão a que ele se ligou expôs uma falta de compreensão de como a function se comportava (e como $ era mais limitada que [[ ). Em ambos os casos, uma solução eval(parse(..)) poderia ser construída, mas era mais desajeitada e menos clara do que a alternativa.

As preocupações de segurança só surgem realmente se você começar a chamar eval em sequências que outro usuário passou para você. Isso é um grande negócio se você estiver criando um aplicativo que execute R em segundo plano, mas para análise de dados em que você está escrevendo código para ser executado por você mesmo, não precisa se preocupar com o efeito de eval na segurança.

Alguns outros problemas com eval(parse( embora).

Em primeiro lugar, o código usando eval-parse é geralmente muito mais difícil de depurar que o código não analisado, o que é problemático porque o software de debugging é duas vezes mais difícil do que escrevê-lo em primeiro lugar.

Aqui está uma function com um erro.

 std <- function() { mean(1to10) } 

Bobo eu, eu esqueci o operador de cólon e criei meu vetor errado. Se eu tentar e fonte esta function, então R percebe o problema e lança um erro, apontando-me o meu erro.

Aqui está a versão do eval-parse.

 ep <- function() { eval(parse(text = "mean(1to10)")) } 

Isso irá originar, porque o erro está dentro de uma string válida. É só mais tarde, quando chegamos a rodar o código que o erro é lançado. Então, usando eval-parse, perdemos o recurso de verificação de erro de tempo de origem.

Eu também acho que esta segunda versão da function é muito mais difícil de ler.

O outro problema com o eval-parse é que é muito mais lento que o código executado diretamente. Comparar

 system.time(for(i in seq_len(1e4)) mean(1:10)) user system elapsed 0.08 0.00 0.07 

e

 system.time(for(i in seq_len(1e4)) eval(parse(text = "mean(1:10)"))) user system elapsed 1.54 0.14 1.69 

Geralmente há uma maneira melhor de ‘computar na linguagem’ do que trabalhar com strings de código; evalparse heavy-code precisa de muita segurança para garantir uma saída sensata, na minha experiência.

A mesma tarefa geralmente pode ser resolvida trabalhando diretamente no código R como um object de linguagem; Hadley Wickham tem um guia útil sobre meta-programação em R aqui :

A function defmacro () na biblioteca gtools é o meu substituto favorito (não pretendido pelo R punk) para a construção do evalparse

 require(gtools) # both action_to_take & predicate will be subbed with code F <- defmacro(predicate, action_to_take, expr = if(predicate) action_to_take) F(1 != 1, action_to_take = print('arithmetic doesnt work!')) F(pi > 3, action_to_take = return('good!')) [1] 'good!' # the raw code for F print(F) function (predicate = stop("predicate not supplied"), action_to_take = stop("action_to_take not supplied")) { tmp <- substitute(if (predicate) action_to_take) eval(tmp, parent.frame()) }  

O benefício deste método é que você tem a garantia de receber de volta o código R sintático-legal. Mais sobre esta function útil pode ser encontrada aqui :

Espero que ajude!

Em algumas linguagens de programação, eval() é uma function que avalia uma string como se fosse uma expressão e retorna um resultado; em outros, ele executa várias linhas de código como se tivessem sido incluídas no lugar da linha, incluindo o eval. A input para eval não é necessariamente uma string; em linguagens que suportam abstrações sintáticas (como Lisp), a input de eval consistirá em formas sintáticas abstratas. http://en.wikipedia.org/wiki/Eval

Existem todos os tipos de exploits dos quais se pode tirar proveito se o eval for usado indevidamente.

Um invasor pode fornecer um programa com a string “session.update (authenticated = True)” como dados, o que atualizaria o dictionary de session para definir uma chave autenticada como True. Para remediar isso, todos os dados que serão usados ​​com eval devem ser ignorados ou devem ser executados sem access a funções potencialmente prejudiciais. http://en.wikipedia.org/wiki/Eval

Em outras palavras, o maior perigo de eval() é o potencial de injeção de código em seu aplicativo. O uso de eval() também pode causar problemas de desempenho em alguns idiomas, dependendo do que está sendo usado.

Especificamente em R, é provavelmente porque você pode usar get() no lugar de eval(parse()) e seus resultados serão os mesmos sem ter que recorrer a eval()