編集
混乱が多いように思われるので、質問を少し単純化します。以下の元の質問に答えてみることも、代わりにこのバージョンに取り組み、行の下のすべてを無視することもできます。
私の目標は、任意の式を取得し、非常に制限された環境で評価することです。この環境には、次のタイプの値を持つ変数のみが含まれます。
- 数値ベクトル
- 1 つ以上の数値ベクトルを取り、数値ベクトルを返す純粋な関数 (つまり、算術演算子)
さらに、式は数値定数や文字列定数などの任意のリテラルを必ず使用できます (ただし、数値ベクトルや文字列ベクトルは が必要なため、使用できませんc
)。この環境で式を評価し、式が環境外のものにアクセスできないようにして、式の評価がセキュリティ リスクにならないようにしたいと考えています。では、以下のコードで、評価時に何か悪いことをする文字列を空白に埋めることができますか? 「いたずら」とは、画面に何かを出力する、変数の値にアクセスする、secret
任意のシェル コマンド (できれば出力を生成するコマンド) を実行すること、またはその他のいたずらと思われること (選択を正当化すること) として定義されます。
a <- 1
b <- 2
x <- 5
y <- 1:10
z <- -1
## Give secret a random value so that you can't just compute it from
## the above variables
secret <- rnorm(5)
allowed.variables <- c(
## Numeric variables
"a", "b", "x", "y", "z",
## Arithmetic operators
"(", "+", "-", "/", "*", "^", "sqrt", "log", "log10", "log2", "exp", "log1p")
restricted.environment <- Map(get, allowed.variables)
## Example naughty expressions that my method successfully guards
## against
expr1 <- "secret"
expr2 <- "cat('Printing something with cat\n')"
expr3 <- "system('echo Printing something via shell command')"
arbitrary.expression <- "?????????" # Your naughty string constant here
eval(parse(text=arbitrary.expression), envir=restricted.environment, enclos=emptyenv())
元の質問
ユーザー入力として算術式を取得して評価するコードを書いています。使用できる指定された変数のセットと、算術関数のホワイトリスト ( 、 、+
、-
など*
)があります。任意のコード インジェクションの可能性を回避するために、これらの変数と演算子のみがスコープ内にあるように式を評価する方法はありますか? うまくいくと思うものがありますが、それが本当に防弾であるという確信がない限り、実際に使用したくありません。/
^
## Shortcut for parse-then-eval pattern
evalparse <- function(expr, ...) eval(parse(text=expr), ...)
# I control these
arithmetic.operators <- Map(get, c("(", "+", "-", "/", "*", "^", "sqrt", "log", "log10", "log2", "exp", "log1p"))
vars <- list(a=1, b=2)
safe.envir <- c(vars, arithmetic.operators)
# Assume that these expressions are user input, e.g. from a web form.
nice.expr <- "a + b"
naughty.expr <- paste("cat('ARBITRARY R CODE INJECTION\n'); system('echo ARBITRARY SHELL COMMAND INJECTION');", nice.expr)
## NOT SAFE! Lookups outside env still possible.
evalparse(nice.expr, envir=safe.envir)
evalparse(naughty.expr, envir=safe.envir)
## Is this safe?
evalparse(nice.expr, envir=safe.envir, enclos=emptyenv())
evalparse(naughty.expr, envir=safe.envir, enclos=emptyenv())
上記のコードを R で実行すると、最初の evalnaughty.expr
でペイロードが正常に実行されることがわかります。ただし、 を使用した 2 回目の評価では、変数、、および指定された算術演算子にenclose=emptyenv()
しかアクセスできないため、ペイロードの実行は失敗します。a
b
では、このメソッド (つまりeval(..., envir=safeenv, enclos=emptyenv())
) は、実際のユーザー入力を受け入れる本番環境で実際に使用しても問題ありませんか、それとも、制限された環境で任意のコードを実行するための卑劣な方法がありませんか?