70

使用を避ける方法についていくつかの質問がありますeval(parse(...))

これは疑問を引き起こします:

  • 具体的eval(parse())に避ける べき理由
  • そして最も重要なことは、危険とは何ですか?
    • コードが本番環境で使用されていない場合、危険はありますか? (私は、意図しない結果が返される危険性を考えています。解析しているものに注意を払わないと、問題が発生することは明らかです。しかし、それは、だらしないことよりも危険get()ですか?)
4

4 に答える 4

42

反対の議論のほとんどは、セキュリティ上の懸念のためではなくeval(parse(...))、結局のところ、Rがインターネットに公開するための安全なインターフェイスであるという主張はなされていません。より速く、より人間的に解析可能なメソッド。R言語は高レベルであると想定されているため、cognoscentiの好み(そして私はそのグループに自分自身を考慮していません)は、コンパクトで表現力豊かなコードを見ることです。

したがって、危険はeval(parse(..))知識の不足を回避する裏口の方法であり、その障壁を引き上げる希望は、人々がR言語の使用を改善することです。ドアは開いたままですが、他の機能をより表現力豊かに使用することが期待されています。今日のCarlWitthoftの質問getは、関数が利用可能であることを知らないことを示しており、彼がリンクした質問は[[、関数がどのように動作するか(およびどのよう$に制限されているか)についての理解の欠如を明らかにしました[[。どちらの場合も、eval(parse(..))ソリューションを構築できましたが、他のソリューションよりも不格好で明確ではありませんでした。

于 2012-11-30T18:26:21.753 に答える
36

別のユーザーから渡された文字列に対して eval の呼び出しを開始した場合にのみ、セキュリティ上の問題が実際に発生します。evalバックグラウンドで R を実行するアプリケーションを作成している場合、これは大きな問題ですが、自分で実行するコードを記述しているデータ分析では、セキュリティへの影響を心配する必要はありません。

ただし、その他のいくつかの問題eval(parse(

まず、eval-parse を使用するコードは通常、解析されていないコードよりもデバッグがはるかに困難です。これは、ソフトウェアのデバッグが、最初にコードを記述するよりも2 倍難しいため、問題になります。

ここに間違いのある関数があります。

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

愚かなことに、コロン演算子を忘れて、ベクトルを間違って作成してしまいました。この関数を source しようとすると、R は問題に気づき、エラーをスローして、間違いを指摘します。

これが eval-parse バージョンです。

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

エラーは有効な文字列内にあるため、これが発生します。エラーがスローされるのは、後でコードを実行するときだけです。したがって、eval-parse を使用すると、ソース時のエラー チェック機能が失われます。

また、関数のこの 2 番目のバージョンは、はるかに読みにくいと思います。

eval-parse のもう 1 つの問題は、直接実行されるコードよりもはるかに遅いことです。比較

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

system.time(for(i in seq_len(1e4)) eval(parse(text = "mean(1:10)")))
   user  system elapsed 
   1.54    0.14    1.69
于 2012-12-01T15:05:34.527 に答える
18

通常、コード文字列を操作するよりも「言語を計算する」ためのより良い方法があります。私の経験では、重いコードの evalparse には、適切な出力を保証するために多くの保護が必要です。

同じタスクは通常、R コードを言語オブジェクトとして直接処理することで解決できます。Hadley Wickham は、R でのメタプログラミングに関する便利なガイドをここに用意しています。

gtools ライブラリの defmacro() 関数は、evalparse コンストラクトの私のお気に入りの代替品です (中途半端な R しゃれは意図されていません)。

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())
}
<environment: 0x05ad5d3c> 

この方法の利点は、構文的に正しい R コードを取得できることが保証されることです。この便利な機能の詳細については、次を参照してください

それが役立つことを願っています!

于 2012-12-02T10:44:41.930 に答える
8

一部のプログラミング言語でeval()は、文字列を式であるかのように評価し、結果を返す関数です。他の例では、eval を含む行の代わりに含まれているかのように複数行のコードを実行します。eval への入力は必ずしも文字列ではありません。構文の抽象化をサポートする言語 (Lisp など) では、eval の入力は抽象的な構文形式で構成されます。 http://en.wikipedia.org/wiki/Eval

eval が不適切に使用された場合に利用できるあらゆる種類のエクスプロイトがあります。

攻撃者は、プログラムに文字列「session.update(authenticated=True)」をデータとして提供し、セッション ディクショナリを更新して認証済みキーを True に設定する可能性があります。これを改善するには、eval で使用されるすべてのデータをエスケープするか、潜在的に有害な関数にアクセスせずに実行する必要があります。 http://en.wikipedia.org/wiki/Eval

つまり、最大の危険eval()は、アプリケーションへのコード インジェクションの可能性です。を使用すると、使用目的にeval()応じて、一部の言語でパフォーマンスの問題が発生する可能性もあります。

get()具体的にはRでは、おそらく代わりに使用できるため、eval(parse())に頼らなくても結果が同じになるためですeval()

于 2012-11-30T17:43:33.673 に答える