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é.
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!
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 :-)
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).