Une fonction f()
utilise eval()
(ou quelque chose de dangereux) avec des données que j'ai créées et stockées 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ûr à exécuter car les chaînes que je lui fournis sont les miennes.
Cependant, si jamais je décidais de l'utiliser pour quelque chose de dangereux (par exemple, une entrée utilisateur), les choses pourraient mal tourner . De plus, si l' local_file
arrêt cesse d'être local, cela créerait une vulnérabilité, car je devrais également faire confiance à la machine qui fournit ce fichier.
Comment dois-je m'assurer de ne jamais "oublier" que cette fonction n'est pas sûre à utiliser (sauf si des critères spécifiques sont remplis)?
Remarque: eval()
est dangereux et peut généralement être remplacé par quelque chose de sûr.
la source
Réponses:
Définissez un type pour décorer les entrées «sûres». Dans votre fonction
f()
, assurez-vous que l'argument a ce type ou renvoyez une erreur. Soyez assez intelligent pour ne jamais définir de raccourcidef g(x): return f(SafeInput(x))
.Exemple:
Bien que cela puisse être facilement contourné, il est plus difficile de le faire par accident. Les gens pourraient critiquer un contrôle de type aussi draconien, mais ils manqueraient le point. Étant donné que le
SafeInput
type n'est qu'un type de données et non une classe orientée objet pouvant être sous-classée, la vérification de l'identité du type avectype(x) is SafeInput
est plus sûre que la vérification de la compatibilité du type avecisinstance(x, SafeInput)
. Étant donné que nous voulons appliquer un type spécifique, ignorer le type explicite et simplement effectuer un typage de canard implicite n'est pas non plus satisfaisant ici. Python a un système de type, alors utilisons-le pour détecter d'éventuelles erreurs!la source
assert
est supprimé automatiquement car j'utiliserai du code python optimisé. Ilif ... : raise NotSafeInputError
faudrait quelque chose comme .eval()
méthodeSafeInput
, afin de ne pas avoir besoin d'une vérification de type explicite. Donnez à la méthode un nom qui n'est utilisé dans aucune de vos autres classes. De cette façon, vous pouvez toujours vous moquer du tout à des fins de test.eval
a accès aux variables locales, il se peut que le code dépende de la façon dont il mute les variables. En déplaçant l'eval dans une autre méthode, il n'aura plus la possibilité de muter les variables locales.SafeInput
constructeur de prendre un nom / handle du fichier local et de faire la lecture lui-même, en s'assurant que les données proviennent bien d'un fichier local.Comme Joel l'a souligné une fois, faites en sorte que le mauvais code semble incorrect ( faites défiler jusqu'à la section "La vraie solution", ou mieux encore lisez-le complètement; cela en vaut la peine, même s'il s'adresse à des variables au lieu de noms de fonctions). Je suggère donc humblement de renommer votre fonction en quelque chose comme
f_unsafe_for_external_use()
- vous trouverez très probablement un schéma d'abréviation vous-même.Edit: Je pense que la suggestion d'Amon est une très bonne variation basée sur OO sur le même thème :-)
la source
En complément de la suggestion de @amon, vous pouvez également penser à combiner le modèle de stratégie ici, ainsi que le modèle d'objet de méthode.
Et puis une implémentation «normale»
Et une implémentation admin-input-eval
(Remarque: avec un exemple réel, je pourrais peut-être donner un meilleur exemple).
la source