Quali sono specificamente i pericoli di eval (parse (…))?

Ci sono diverse domande su come evitare l’uso di eval(parse(...))

  • r-evalparse-è-spesso-non ottimale
  • evitando-the-famigerato-evalparse-costrutto

Che fa scaturire le domande:

  • Perché in particolare dovrebbe essere eval(parse()) essere evitato?
  • E, cosa più importante, quali sono i pericoli?
    • Ci sono dei rischi se il codice non viene utilizzato in produzione? (Sto pensando, qualsiasi pericolo di ottenere risultati non previsti. Chiaramente se non stai attento a ciò che stai analizzando, avrai dei problemi. Ma è più pericoloso che essere sciatto con get() ?)

La maggior parte degli argomenti contro eval(parse(...)) sorgono non a causa di problemi di sicurezza, dopotutto, non viene fatto alcun reclamo su R come un’interfaccia sicura da esporre su Internet, ma piuttosto perché tale codice generalmente fa cose che può essere realizzato usando metodi meno oscuri, cioè metodi che sono sia più veloci che più umani. Il linguaggio R dovrebbe essere di alto livello, quindi la preferenza dei cognoscenti (e non mi considero in quel gruppo) è vedere il codice che è sia compatto che espressivo.

Quindi il pericolo è che eval(parse(..)) sia un metodo backdoor per aggirare la mancanza di conoscenza e la speranza nel sollevare quella barriera è che le persone miglioreranno il loro uso del linguaggio R. La porta rimane aperta ma la speranza è per un uso più espressivo di altre funzionalità. La domanda di Carl Witthoft in precedenza ha dimostrato di non sapere che la funzione get era disponibile e che la domanda a cui era collegato mostrava una mancanza di comprensione di come la [[ function function (e come $ fosse più limitata di [[ ). In entrambi i casi si poteva build una soluzione eval(parse(..)) , ma era più clunkier e meno chiara dell’alternativa.

I problemi di sicurezza sorgono solo se inizi a chiamare eval su stringhe che un altro utente ti ha passato. Questo è un grosso problema se si sta creando un’applicazione che esegue R in background, ma per l’analisi dei dati in cui si scrive codice da eseguire autonomamente, non è necessario preoccuparsi dell’effetto di eval sulla sicurezza.

Alcuni altri problemi con eval(parse( però.

In primo luogo, il codice che utilizza eval-parse è in genere molto più difficile da eseguire rispetto al codice non analizzato, il che è problematico in quanto il debug del software è due volte più difficile della scrittura iniziale.

Ecco una funzione con un errore in esso.

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

Sciocco, mi sono dimenticato dell'operatore del colon e ho creato il mio vettore in modo errato. Se provo a richiamare questa funzione, allora R rileva il problema e genera un errore, indicandomi il mio errore.

Ecco la versione eval-parse.

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

Ciò si verificherà , poiché l'errore si trova all'interno di una stringa valida. È solo più tardi, quando veniamo a eseguire il codice che viene generato l'errore. Quindi, usando eval-parse, abbiamo perso la capacità di controllo degli errori in tempo reale.

Penso anche che questa seconda versione della funzione sia molto più difficile da leggere.

L'altro problema con eval-parse è che è molto più lento del codice eseguito direttamente. Confrontare

 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 

Di solito c’è un modo migliore di “calcolare sulla lingua” piuttosto che lavorare con le stringhe di codice; un codice pesante molto dettagliato ha bisogno di molte protezioni per garantire un risultato sensato, secondo la mia esperienza.

Solitamente lo stesso compito può essere risolto lavorando direttamente sul codice R come object linguaggio; Hadley Wickham ha una guida utile sulla meta-programmazione in R qui :

La funzione defmacro () nella libreria gtools è il mio sostituto preferito (nessun punk R semi intasato inteso) per il costrutto 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()) }  

Il vantaggio di questo metodo è che è garantito il ritorno del codice R sintatticamente legale. Maggiori informazioni su questa utile funzione possono essere trovate qui :

Spero possa aiutare!

In alcuni linguaggi di programmazione, eval() è una funzione che valuta una stringa come se fosse un’espressione e restituisce un risultato; in altri, esegue più righe di codice come se fossero state incluse al posto della riga, inclusa la valutazione. L’input per eval non è necessariamente una stringa; nelle lingue che supportano le astrazioni sintattiche (come la Lisp), l’input di eval consisterà in forms sintattiche astratte. http://en.wikipedia.org/wiki/Eval

Ci sono tutti i tipi di exploit che si possono sfruttare se eval viene usato in modo improprio.

Un utente malintenzionato potrebbe fornire un programma con la stringa “session.update (authenticated = True)” come dati, che aggiornerebbe il dizionario della sessione per impostare una chiave autenticata come True. Per rimediare a questo, tutti i dati che verranno utilizzati con eval devono essere sfuggiti, oppure devono essere eseguiti senza accesso a funzioni potenzialmente dannose. http://en.wikipedia.org/wiki/Eval

In altre parole, il più grande pericolo di eval() è il potenziale per l’iniezione di codice nella tua applicazione. L’uso di eval() può anche causare problemi di prestazioni in alcune lingue a seconda di cosa viene usato.

Specificamente in R, probabilmente è perché puoi usare get() al posto di eval(parse()) ei tuoi risultati saranno gli stessi senza dover ricorrere a eval()