Meilleures pratiques pour l'exécution de code non approuvé

31

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__du execcontexte pour interdire l'utilisation de packages potentiellement dangereux comme os. 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 execcontexte, 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.NodeVisitorpour 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 PyPyou 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.

pswg
la source
3
@MartijnPieters: Excellent. Probablement digne d'une réponse, si vous résumez chacun d'eux.
Robert Harvey
Considérez également: les déchets laissés sur le disque, le réseau (ne les laissez pas envoyer de spam ou autre), les autorisations sur d'autres fichiers (lecture de vos fichiers). Même éjecter pendant que la boucle peut détruire la mécanique du CD ... J'irais pour la virtualisation (les prisons ou certains kvm vous l'appelez) ou au moins l'utilisateur avec presque aucun privilège. Définissez une mémoire agréable et raisonnable pour profiter de vos propres programmes.
kyticka
1
Essayez PyPy :> Sandboxing: PyPy offre la possibilité d'exécuter du code non approuvé de manière entièrement sécurisée.
Vorac du

Réponses:

28

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:

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' execinstruction ( 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 local osdans votre espace de noms de module qui fait référence au osmodule. Cela peut conduire un attaquant déterminé à des modules qui peuvent les aider à sortir du bac à sable. Le picklemodule, 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 au picklemodule, 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. RestrictedPythontransforme 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 RestrictedPythonest 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.

Martijn Pieters
la source
10

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é:

  • créer un conteneur avec uniquement Python et ses dépendances et les dépendances du conteneur
  • créer un conteneur sans tous les appareils qui ne sont pas absolument nécessaires (c.-à-d. réseau et stockage)
  • créer un conteneur avec des restrictions sur la mémoire et l'utilisation des processus
  • recréer le conteneur à chaque exécution (ou au moins avec chaque utilisateur unique et période maximale)
  • exécuter en tant qu'utilisateur avec le moins de privilèges nécessaire
  • exécuter en tant qu'utilisateur qui n'a pas les autorisations pour écrire des fichiers

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.

dietbuddha
la source
C'est la seule chose où vous allez être encore à distance sûr que vous avez bien compris - donnez-lui son propre processus.
Michael Kohne le
3

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.

ddyer
la source
4
La question de la sécurité était pour son serveur, pas pour la machine du client. Les risques de sécurité potentiels de Java, comme ceux de toute autre technologie Web, sont que le serveur pourrait être utilisé pour déployer des programmes dangereux pour le client.
ddyer
1
@grasGendarme, tout comme les nouvelles histoires sur les accidents d'avion, vous en dit beaucoup sur leur rareté; des histoires sur les failles de sécurité java vous indiquent que java est relativement sécurisé. Vous n'obtiendrez jamais une telle histoire à propos de C parce que la réponse que vous obtiendrez serait "bien duh; si vous l'exécutez, elle fera tout ce qu'elle veut"
Richard Tingle
2

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.

James
la source
0

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

Big Ian
la source