J'ai un projet où je dois autoriser les utilisateurs à exécuter du code python arbitraire et non fiable ( un peu comme celui-ci ) sur mon serveur. Je suis assez nouveau sur python et j'aimerais éviter de faire des erreurs qui introduisent des failles de sécurité ou d'autres vulnérabilités dans le système. Y a-t-il des meilleures pratiques disponibles, une lecture recommandée ou d'autres conseils que vous pouvez me donner pour rendre mon service utilisable mais pas abusif?
Voici ce que j'ai considéré jusqu'à présent:
- Supprimer
__builtins__
duexec
contexte pour interdire l'utilisation de packages potentiellement dangereux commeos
. Les utilisateurs ne pourront utiliser que les packages que je leur fournis. - Utilisez des threads pour appliquer un délai raisonnable.
- Je voudrais limiter la quantité totale de mémoire qui peut être allouée dans le
exec
contexte, mais je ne sais pas si c'est même possible.
Il existe des alternatives à une ligne droite exec
, mais je ne sais pas laquelle serait utile ici:
- Utiliser un
ast.NodeVisitor
pour intercepter toute tentative d'accéder à des objets dangereux. Mais quels objets dois-je interdire? - Recherche de doubles soulignements dans l'entrée. (moins gracieux que l'option ci-dessus).
- Utiliser
PyPy
ou quelque chose de similaire pour sandboxer le code.
REMARQUE: je sais qu'il existe au moins un interpréteur basé sur JavaScript. Cela ne fonctionnera pas dans mon scénario.
Réponses:
Le sandboxing en Python est difficile . Python est intrinsèquement introspectable, à plusieurs niveaux.
Cela signifie également que vous pouvez trouver les méthodes d'usine pour des types spécifiques à partir de ces types eux-mêmes et construire de nouveaux objets de bas niveau, qui seront exécutés directement par l'interpréteur sans limitation.
Voici quelques exemples de solutions créatives pour sortir des sandbox Python:
Ned Batchelder commence par une démonstration de la dangerosité
eval()
réelle ;eval()
est souvent utilisé pour exécuter des expressions Python; comme un bac à sable primitif et naïf pour les one-liners.Il a ensuite continué à essayer d'appliquer les mêmes principes à Python 3 , réussissant finalement à sortir avec quelques pointeurs utiles.
Pierre Bourdon utilise des techniques similaires pour pirater un système python lors d'un hack-a-thon
L'idée de base est toujours de trouver un moyen de créer des types Python de base; fonctions et classes et sortir du shell en obtenant l'interpréteur Python pour exécuter arbitraire (non vérifié!) bytecode.
La même chose et plus s'appliquent à l'
exec
instruction (exec()
fonction en Python 3).Donc, vous voulez:
Contrôlez strictement la compilation d'octets du code Python, ou au moins post-traitez le bytecode pour supprimer tout accès aux noms commençant par des traits de soulignement.
Cela nécessite une connaissance approfondie du fonctionnement de l'interpréteur Python et de la structure du bytecode Python. Les objets de code sont imbriqués; le bytecode d'un module ne couvre que le niveau supérieur des instructions, chaque fonction et classe se compose de leur propre séquence de bytecode plus des métadonnées, contenant d' autres objets de bytecode pour les fonctions et classes imbriquées, par exemple.
Vous devez ajouter à la liste blanche les modules qui peuvent être utilisés. Soigneusement.
Un module python contient des références à d' autres modules. Si vous importez
os
, il y a un nom localos
dans votre espace de noms de module qui fait référence auos
module. Cela peut conduire un attaquant déterminé à des modules qui peuvent les aider à sortir du bac à sable. Lepickle
module, par exemple, vous permet de charger des objets de code arbitraires par exemple, donc si un chemin à travers des modules en liste blanche mène aupickle
module, vous avez toujours un problème.Vous devez limiter strictement les quotas de temps. Même le code le plus stérilisé peut toujours tenter de s'exécuter indéfiniment, bloquant ainsi vos ressources.
Jetez un œil à RestrictedPython , qui tente de vous donner le contrôle strict du bytecode.
RestrictedPython
transforme le code Python en quelque chose qui vous permet de contrôler quels noms, modules et objets sont autorisés dans Python 2.3 à 2.7.Si
RestrictedPython
est suffisamment sécurisé pour vos besoins, cela dépend des politiques que vous implémentez. Ne pas autoriser l'accès aux noms commençant par un trait de soulignement et la liste strictement blanche des modules serait un début.À mon avis, la seule option vraiment robuste consiste à utiliser une machine virtuelle distincte, sans accès réseau au monde extérieur que vous détruisez après chaque exécution. À la place, chaque nouveau script reçoit une nouvelle machine virtuelle. De cette façon, même si le code parvient à sortir de votre sandbox Python (ce qui n'est pas improbable), tout l'attaquant y accède est de courte durée et sans valeur.
la source
TL; DR Utilisez un chroot / prison et exécutez en tant qu'utilisateur personnalisé sans aucun privilège.
La meilleure pratique pour exécuter du code non approuvé consiste à le séparer via un sandbox système . Pour plus de sécurité:
Vous suivez également les pratiques standard pour exécuter les choses en toute sécurité dans un chroot. Vous pouvez également reconstruire le système de fichiers du chroot à chaque appel est particulièrement paranoïaque. En règle générale, l'utilisateur ne peut pas apporter de modifications au système de fichiers dans lequel le chroot s'exécute.
la source
Il n'y a aucun moyen de le faire en toute sécurité.
Si vous voulez faire quelque chose comme ça en toute sécurité, vous devez commencer par avoir votre propre implémentation de python qui s'exécute dans un environnement complètement contrôlé, s'exécute de préférence dans le navigateur des utilisateurs plutôt que sur votre système. Vous pouvez commencer par Jython (python pour java) et le conditionner en applet java. Comme il s'exécuterait dans le bac à sable java, sur la machine de l'utilisateur, votre système serait raisonnablement sûr.
la source
Comme Martijn l'a dit ci-dessus, c'est vraiment, vraiment difficile en Python. Franchement parce que Python est tellement introspectable, je ne pense pas que ce soit possible en limitant les fonctionnalités du langage. Et si un bac à sable fonctionne pour une version de Python, il est possible que la prochaine version le brise.
J'aurais un regard sur PyPy au lieu de CPython standard. En bref, c'est une implémentation alternative conforme de Python. Il a plusieurs avantages et fonctionnalités distinctes, et l'un d'eux est le sandboxing via le remplacement des appels système au lieu de limiter les fonctionnalités linguistiques.
la source
Tant que les performances ne sont pas extrêmement importantes pour vous, vous pouvez toujours les exécuter dans Brython, ce qui les place dans le bac à sable JavaScript
la source