[Python] alternative ad eval

Manlio Perillo manlio.perillo a gmail.com
Mar 18 Mar 2014 13:39:27 CET


2014-03-17 22:57 GMT+01:00 Balan Victor <balan.victor0 a gmail.com>:

> Ho un array di tuple cosi formate da 3 elementi:
> (int|float|boolean|string|datetime|..., string, boolean). Es:
>
> [
>  (10, "value >= 1", True),
>  ("Ciao", "o in value", True),
>  (True, "value == False", False),
>  (92.5f, "value >= 92.0f", True),
> ]
> Il primo elemento della tupla può essere qualunque tipo o classe di python.
> Il secondo elemento è una espressione da applicare sulla tupla e che deve
> restituire True or False(value si riferisce al primo elemento della tupa)
> Il terzo elemento è il risultato dell'operazione appena sopra.
>
> A intervalli regolari ho bisogno di scorrere l'array sopra e aggiornare il
> valore del terzo elemento.
> Ho pensato di usare eval in questo modo:
>
> def check_status(value, eval_string):
>   rc =  eval(eval_string)
>   if rc is not bool: raise WrongEvalString()
>   return rc
>
> Conosco i rischi di eval e vorrei evitare di usarlo però non riesco a
> trovare nulla di altrettanto semplice e con le stesse potenzialità.
>
>
eval è relativamente sicuro, dato che può eseguire solo espressioni, e non
statement completi come exec.
Lo puoi rendere ancora più sicuro limitando il namespace, ad esempio:

def expand_template(template, **kwargs):
    from string import Template

    return Template(template).substitute(**kwargs)

def eval_expression(expr_literal, value):
    expr = expand_template(expr_literal, value=value)

    return eval(expr, {}, {})


def check_status(value, eval_string):
  rc =  eval_expression(eval_string, value)
  if rc is not True:
      raise WrongEvalString()

check_status(10, "$value == 10")

Questo però non basta, devi avere il controllo anche su value, ad esempio
accettando solo stringhe secondo un dato protocollo, di cui farai il
parsing e validazione.
Il mio protocollo preferito è "Typed NetStrings":
  "<typeid><len>:<literal>
Ad esempio per un intero:
  "i3:777"

tale protocollo è facile da leggere, parsare e validare (perchè verboso)

NB: In realtà la stringa che fa la validazione può essere impostata solo da
> qualcuno di autorizzato quindi il rischio che mi cancelli tutto il fs non
> ci dovrebbe essere, e non dovrebbero nemmeno fare operazioni del tipo
> "value ** value" però in ogni caso vorrei trovare qualcosa che mi metta al
> sicuro da questo tipo di operazioni.
>

Riguardo operazioni non autorizzate sei abbastanza al sicuro, grazie al
fatto che eval esegue solo espressioni, ed al fatto che valuti solo oggetti
a te noti.
In caso di dubbi, leggi la grammatica di Python per sapere cosa può
contenere una espressione.

Riguardo "value ** value" temi un attacco di tipo DoS?

In questo caso se vuoi limitare anche le possibili espressioni, l'unica
alternativa e scriverti un tuo parser, come ti hanno già suggerito.  Dai
una occhiata al modulo ast di Python.


Ciao  Manlio
-------------- parte successiva --------------
Un allegato HTML è stato rimosso...
URL: <http://lists.python.it/pipermail/python/attachments/20140318/6cb38b6d/attachment.html>


Maggiori informazioni sulla lista Python