web-dev-qa-db-fra.com

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

J'ai un projet où je dois autoriser les utilisateurs à exécuter arbitrairement et non approuvé python ( n peu comme ça ) contre mon serveur. Je suis assez nouveau pour = 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 pointeurs que vous pouvez me donner service utilisable mais non abusif?

Voici ce que j'ai considéré jusqu'à présent:

  • Retirer __builtins__ du contexte exec pour interdire l'utilisation de paquets potentiellement dangereux comme os. Les utilisateurs ne pourront utiliser que les packages que je leur fournis.
  • Utilisez des threads pour imposer un délai raisonnable.
  • Je voudrais limiter la quantité totale de mémoire qui peut être allouée dans le contexte exec, mais je ne sais pas si c'est même possible.

Il existe des alternatives à un exec simple, mais je ne sais pas laquelle serait utile ici:

  • Utilisation d'un ast.NodeVisitor pour intercepter toute tentative d'accès à 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 suis conscient qu'il existe au moins un interpréteur JavaScript. Cela ne fonctionnera pas dans mon scénario.

31
p.s.w.g

Le sandboxing 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ète sans limitation.

Voici quelques exemples pour trouver des moyens créatifs de sortir de Python sandboxes:

L'idée de base est toujours de trouver un moyen de créer des types Python; fonctions et classes et de sortir du Shell en obtenant l'interpréteur Python à exécuter arbitrairement). (décoché!) bytecode.

La même chose et plus s'appliquent à l'instruction exec (fonction exec() dans 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 manière dont Python bytecode est structuré. 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 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 local nom os dans votre espace de noms de module qui fait référence au module os. Cela peut conduire un attaquant déterminé vers des modules qui peuvent les aider à sortir du sandbox. Le module pickle, par exemple, vous permet de charger des objets de code arbitraires par exemple, donc si tout chemin à travers des modules sur liste blanche mène au module pickle, vous avez un problème encore.

  • 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 oeil à RestrictedPython , qui tente de vous donner le contrôle strict du bytecode. RestrictedPython transforme Python code 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. Chaque nouveau script reçoit un nouveau VM à la place. De cette façon, même si le code parvient à sortir de votre Python sandbox (ce qui n'est pas improbable)) tous les l'attaquant a accès à est de courte durée et sans valeur.

28
Martijn Pieters

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 système sandbox. Pour plus de sécurité:

  • créer un conteneur avec seulement Python et ses dépendances et les dépendances du conteneur
  • créer un conteneur sans tous les périphériques 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 n'est pas en mesure d'apporter des modifications au système de fichiers dans lequel le chroot s'exécute.

10
dietbuddha

Il n'y a aucun moyen de le faire en toute sécurité.

Si vous vouliez 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 une applet Java. Comme il s'exécuterait dans le Java sandbox, sur la machine de l'utilisateur, votre système serait raisonnablement sûr.

3
ddyer

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 vous obtenez un bac à sable fonctionnant pour une version de Python, il y a une chance que la prochaine version casse le.

Je voudrais jeter un œil à PyPy au lieu de CPython standard. En bref, c'est une implémentation alternative conforme de Python. Il présente plusieurs avantages et fonctionnalités distinctes, et l'un d'eux est le sandboxing en remplaçant les appels système au lieu de limiter les fonctionnalités linguistiques.

2
James

Tant que les performances ne sont pas extrêmement importantes pour vous, vous pouvez toujours les exécuter dans Brython, ce qui les place effectivement dans le bac à sable JavaScript

0
Big Ian