Einer der coolsten Features des R ist, dass es seine eigene Sprache verarbeiten kann, so dass Sie eine Funktion weiße Liste erstellen und überprüfen Ausdrücke dagegen:
# Function to check if an expression is safe
is_safe_call <- function(text, allowed.funs) {
# Recursive function to evaluate each element in the user expression
safe_fun <- function(call, allowed.funs) {
if(is.call(call)) {
call.l <- as.list(call)
if(!is.name(call.l[[1L]]) || !as.character(call.l[[1L]]) %in% allowed.funs)
stop(as.character(call.l[[1L]]), " is not an allowed function")
lapply(tail(call.l, -1L), safe_fun, allowed.funs)
}
TRUE
}
# parse and call recursive function
expr <- parse(text=text)
if(length(expr) > 1L) stop("Only single R expressions allowed")
safe_fun(expr[[1L]], allowed.funs)
}
Wir haben dann eine weiße Liste der zulässigen Funktionen definieren. Es ist sehr wichtig, dass Sie sehr vorsichtig sind, was Sie hier zulassen. Insbesondere wenn Sie parse
, eval
oder andere Funktionen mit möglichen unangenehmen Nebenwirkungen zulassen (system
, unlink
, usw.), öffnen Sie Ihr System für den Angriff.
allowed.funs <- c("+", "exp", "*", "^", "-", "sqrt")
Und wir testen:
is_safe_call("x^2 + exp(3*x)", allowed.funs)
## [1] TRUE
is_safe_call("x^2 - sqrt(3*x)", allowed.funs)
## [1] TRUE
is_safe_call("unlink('~', recursive=TRUE)", allowed.funs)
## Error in safe_fun(parse(text = text)[[1L]], allowed.funs) :
## unlink is not an allowed function
is_safe_call("x + sqrt(unlink('~', recursive=TRUE))", allowed.funs)
## Error in FUN(X[[i]], ...) : unlink is not an allowed function
is_safe_call('x; print("Your computer is compromised")')
## Error in is_safe_call("x; print(\"Your computer is compromised\")") :
## Only single R expressions allowed
Keine waranties ausdrücken oder in diese impliziert werden. Es mag einen Weg geben, dies zu hacken, an den ich nicht gedacht habe, also stellen Sie es nicht ohne eine gründliche Überprüfung auf einen öffentlich zugänglichen Server, aber ich denke, das könnte einfach funktionieren.
Beachten Sie, dass, wenn jemand einen Ausdruck zur Verfügung stellen kann, der sich selbst hackt parse
, dann können Sie auf diese Weise kompromittiert werden.
EDIT: Ben Bolker schlug einen cleveren Trick, um zu versuchen, dies zu hacken, aber diese Funktion ist robust, dass:
is_safe_call("exp <- function(...) system(\"echo do bad stuff\")", allowed.funs)
## Error in safe_fun(expr[[1L]], allowed.funs) :
## <- is not an allowed function
allowed.funs <- c("+", "exp", "*", "^", "-", "sqrt", "<-")
is_safe_call("exp <- function(...) system(\"echo do bad stuff\")", allowed.funs)
## Error in FUN(X[[i]], ...) : function is not an allowed function
allowed.funs <- c("+", "exp", "*", "^", "-", "sqrt", "<-", "function")
is_safe_call("exp <- function(...) system(\"echo do bad stuff\")", allowed.funs)
## Error in FUN(X[[i]], ...) : system is not an allowed function
Ich denke, es sollte eine Art und Weise, dies zu tun mit 'substitute'/'parse', aber ich kann es nicht erarbeiten –
https://cran.r-project.org/package=RAppArmor –