4 votes

Désactiver l'import de module intégré dans Python embarqué

Je suis en train d'intégrer Python 3.6 dans mon application, et je veux désactiver la commande d'importation dans les scripts pour empêcher les utilisateurs d'importer des bibliothèques Python intégrées. J'aimerais n'utiliser que le langage lui-même et mes propres modules définis en C++.

Py_SetProgramName (L"Example");
Py_Initialize ();
PyObject* mainModule = PyImport_AddModule ("__main__");
PyObject* globals = PyModule_GetDict (mainModule);

// Cela devrait fonctionner
std::string script1 = "print ('exemple')";
PyRun_String (script1.c_str (), Py_file_input, globals, nullptr);

// Cela ne devrait pas fonctionner
std::string script2 = "import random\n"
                      "print (random.randint (1, 10))\n";
PyRun_String (script2.c_str (), Py_file_input, globals, nullptr);

Py_Finalize ();

Connaissez-vous un moyen d'accomplir cela ?

4voto

Zooba Points 6440

Python a une longue histoire d'être impossible à créer un bac à sable sécurisé (voir Comment puis-je sandbox Python en pur Python? comme point de départ, puis plongez dans une ancienne discussion python-dev si cela vous intéresse). Voici ce que je considère comme vos deux meilleures options.

Pré-analysez le code

Avant d'exécuter quoi que ce soit, analysez le code. Vous pourriez le faire en Python avec le module AST puis parcourir l'arbre, ou vous pourriez probablement vous en sortir avec des recherches de texte plus simples. Cela fonctionne probablement dans votre scénario parce que vous avez des cas d'utilisation restreints - cela ne se généralise pas à du code vraiment arbitraire.

Ce que vous cherchez dans votre cas sera n'importe quelle instruction import (simple), et toute variable de niveau supérieur (par exemple, dans a.b.c vous vous intéresserez à a et probablement a.b pour un certain a) qui ne sont pas "approuvées". Cela vous permettra d'échouer sur tout code qui n'est pas propre avant de l'exécuter.

Le défi ici est que même un code triviallement obscurci contournera vos vérifications. Par exemple, voici quelques façons d'importer des modules en utilisant d'autres modules ou des globales qu'une analyse de base pour import ne trouvera pas. Vous voudriez probablement restreindre l'accès direct à __builtins__, globals, certains/la plupart/tous les noms avec __double_underscores__ et les membres de certains types. Dans un AST, ceux-ci apparaîtront inévitablement comme des lectures de variables de niveau supérieur ou des accès d'attributs.

getattr(__builtins__, '__imp'+'ort__')('autre_module')

globals()['__imp'+'ort__']('autre_module')

module.__loader__.__class__(
    "autre_module",
    module.__loader__.path + '/../autre_module.py'
).load_module()

(J'espère que cela va un peu sans dire, c'est un défi impossible, et c'est pourquoi cette approche de bac à sable n'a jamais pleinement réussi. Mais cela peut être suffisant, en fonction de votre modèle de menace spécifique.)

Audit en temps d'exécution

Si vous êtes en mesure de compiler votre propre exécution Python, vous pourriez envisager d'utiliser les crochets (actuellement en brouillon) du PEP 551. (Avis de non-responsabilité: je suis l'auteur de ce PEP.) Il existe des implémentations en brouillon contre les dernières versions 3.7 et 3.6.

Essentiellement, cela vous permettrait d'ajouter des crochets pour toute une série d'événements au sein de Python et de déterminer comment y répondre. Par exemple, vous pouvez écouter tous les événements import et déterminer si vous devez les autoriser ou les refuser à l'exécution en fonction du module exact qui est importé, ou écouter les événements compile pour gérer toutes les compilations à l'exécution. Vous pouvez le faire en code Python (avec sys.addaudithook) ou en code C (avec PySys_AddAuditHook).

Le fichier Programs/spython.c dans le dépôt est un exemple assez complet d'audit en C, tandis que le faire en Python ressemble plus à ceci (extrait de ma présentation sur ce PEP):

import sys

def empecher_bitly(evenement, args):
    if evenement == 'urllib.Request' et '://bit.ly/' in args[0]:
        print(f'Avertissement: urlopen({args[0]}) bloqué')
        raise RuntimeError('l'accès à bit.ly n'est pas autorisé')

sys.addaudithook(empecher_bitly)

L'inconvénient de cette approche est que vous devez construire et distribuer votre propre version de Python, au lieu de vous fier à une installation système. Cependant, en général, c'est une bonne idée si votre application dépend de l'intégration, car cela signifie que vous n'aurez pas à contraindre les utilisateurs dans une configuration système spécifique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X