web-dev-qa-db-fra.com

S'assurer que le code dangereux n'est pas utilisé accidentellement

Une fonction f() utilise eval() (ou quelque chose de plus dangereux) avec des données que j'ai créées et stockées dans local_file Sur la machine exécutant mon programme:

import local_file

def f(str_to_eval):
    # code....
    # .... 
    eval(str_to_eval)    
    # ....
    # ....    
    return None


a = f(local_file.some_str)

f() est sécuritaire de fonctionner depuis que les cordes que je lui fournis sont les miennes.

Cependant, si je décide de l'utiliser pour quelque chose de dangereux (par exemple, les choses de l'utilisateur) peuvent aller terriblement mal . De plus, si le local_file Arrête d'être local, il créerait une vulnérabilité car je devrais faire confiance à la machine qui fournit également ce fichier.

Comment dois-je m'assurer que je n'ai jamais "oublié" que cette fonction est dangereuse à utiliser (à moins que des critères spécifiques ne soient satisfaits)?

Remarque: eval() est dangereux et peut habituellement être remplacé par quelque chose de sécurité.

10
Fermi paradox

Définissez un type pour décorer des entrées "sûres". Dans votre fonction f(), affirmez que l'argument a ce type ou lancez une erreur. Soyez assez intelligent pour ne jamais définir un raccourci def g(x): return f(SafeInput(x)).

Exemple:

class SafeInput(object):
  def __init__(self, value):
    self._value = value

  def value(self):
    return self._value

def f(safe_string_to_eval):
  assert type(safe_string_to_eval) is SafeInput, "safe_string_to_eval must have type SafeInput, but was {}".format(type(safe_string_to_eval))
  ...
  eval(safe_string_to_eval.value())
  ...

a = f(SafeInput(local_file.some_str))

Bien que cela puisse être facilement contourné, cela rend plus difficile de le faire par accident. Les gens pourraient critiquer un tel contrôle de type draconien, mais ils manqueraient le point. Puisque le type SafeInput est juste un type de données et non une classe orientée objet qui pourrait être sous-classée, la vérification de l'identité de type avec type(x) is SafeInput est plus sûre que la vérification de la compatibilité de type avec isinstance(x, SafeInput). Puisque nous voulons faire respecter un type spécifique, ignorer le type explicite et simplement faire la dactylographie de canard implicite n'est également pas satisfaisant ici. Python a un système de type, alors utilisons-le pour attraper des erreurs possibles!

26
amon

Comme Joel une fois signalé, faire un mauvais code qui regarde mal (Faites défiler jusqu'à la section "La solution réelle" ou mieux le lisez complètement; cela en vaut la peine, même s'il s'adresse à la variable au lieu de noms de fonctions) . Donc, je suggère humblement de renommer votre fonction à quelque chose comme f_unsafe_for_external_use() - vous proposez probablement un système d'abréviation vous-même.

Edit: Je pense que la suggestion d'Amon est une très bonne, OO Variation basée sur le même thème :-)

11
Murphy

Complétant la suggestion par @AMON, vous pouvez également penser à combiner le modèle de stratégie ici, ainsi que le modèle d'objet de la méthode.

class AbstractFoobarizer(object):
    def handle_cond(self, foo, bar):
        """
        Handle the event or something.
        """
        raise NotImplementedError

    def run(self):
        # do some magic
        pass

Puis une mise en œuvre "normale"

class PrintingFoobarizer(AbstractFoobarizer):
    def handle_cond(self, foo, bar):
        print("Something went very well regarding {} and {}".format(foo, bar))

Et une implémentation d'administration-entrée-évaluation

class AdminControllableFoobarizer(AbstractFoobarizer):
    def handle_cond(self, foo, bar):
        # Look up code in database/config file/...
        code = get_code_from_settings()
        eval(code)

(Remarque: avec un exemple de réel World-ISH, je pourrais peut-être donner un meilleur exemple).

0