Seite 1 von 2

Ein Python-Programm scriptingfähig machen

Verfasst: Donnerstag 27. November 2008, 18:52
von ernstla
Hallo,

ich entwickle eine Webapplikation mit Python, die Scriptingmöglichkeiten, in der Art von Makros o. ä., benötigt. Python lässt sich ja schlecht sandboxen, was die Verwendung von Python selbst bei einer Webanwendung verbietet. Die Sprache sollte Funktionen, Schleifen, Bedingungen, die üblichen Verdächtigen eben, zulassen. Objektorientierung ist nicht notwendig, würde aber nicht schaden.

Es sollten weiterhin auf eine definierte Menge von Python-Objekte in der Scriptsprache zugegriffen werden können, die dann die einzige Verbindung zur "Außenwelt" wären.
Ich benötigen also eine Sprache die in Python embedded werden kann.

Gefunden habe ich bisher python-spidermonkey, womit die JavaScript-Engine von Mozilla eingebunden werden kann. Das Projekt lag einige Zeit brach, wurde aber wiederbelebt. Die Version 0.0.1a klingt jedoch nicht sehr vertauenserweckend.

Außerdem pylux, womit Lua verwendet werden kann. Aber auch hier ist nachdem was ich gesehen habe seit 2001 nichts mehr passiert.

Die Alternative wäre eine eigene kleine DSL zu schreiben, z. B. mit Hilfe von pyparsing. Wobei ich den Aufwand gegenüber einer "fertigen" Lösung als recht hoch einschätze.

Die Frage ist nun ob jemand von Euch schon Erfahrungen mit diesem Thema gemacht hat und falls ja, was Eure Lösung war.

Vielen Dank

Thomas

Verfasst: Donnerstag 27. November 2008, 19:34
von sma
Wenn dir die Möglichkeiten einer Templatesprache wie Jinja, welche AFAIK eine Sandbox hat, nicht ausreicht, dann führt wohl kein Weg an einer maßgeschneiderten Lösung vorbei. Beachte, dass Sicherheit natürlich immer etwas relatives ist und du es wahrscheinlich nicht verhindern kannst, dass jemand mit Endlosschleifen oder übermäßig großen Datenstrukturen Ressourcen verbraucht.

Ich würde einen eigenen Interpreter bauen - sicherlich auch, weil Programmiersprachen und Compilerbau ein Hobby von mir ist.

Zwei Vorbilder würde ich in Erwägung ziehen: JavaScript und Python. Eine eigene Sprache zu entwickeln wäre glaube ich nochmals eine Nummer schwieriger. Nimm lieber ein Subset einer existierenden Sprache.

Für JavaScript spricht, dass es im Webumfeld nicht wegzudenken und von vielen Menschen vielleicht nicht beherrscht aber zumindest benutzt wird.

Eine JavaScript-Interpreter in Python zu schreiben, wäre eine nette Fingerübung, die man denke ich in 1-2 Tagen realisieren kann. Habe ich - wie vieles - mal angefangen, aber ist noch in keinem gebrauchsfertigen Zustand. Einen Interpreter als C-Bibliothek einzubinden finde ich nicht so gut, weil man dann dessen mögliche Probleme erbt und wahrscheinlich auch nicht einfach ein Script von außen abbrechen kann.

Für Python könnte sprechen, das Python vielleicht den Anwendern bekannt ist. Wählt man das Subset sorgfältig aus, kann man die Sprache auch sandboxen. Man muss die Metaprogammierung beschneiden. Allerdings ist Python auch komplexer. Dafür bekommt man einen Python-Parser schon mit Python und müsste jetzt "nur noch" unerwünschte Knoten aus dem Syntaxbaum ausfiltern und das Ergebnis dann mit einem eigenen Laufzeitsystem interpretieren, um ganz sicher zu sein.

Wenn der Interpreter möglichst einfach sein soll, dann empfehle ich Scheme. Ein nacktes Scheme ohne Systemfunktionen kann man in unter 100 Zeilen bauen.

Wenn's noch exotischer sein soll, hätte ich da noch ein paar andere Vorschläge ;)

Stefan

Verfasst: Donnerstag 27. November 2008, 20:00
von Leonidas
sma hat geschrieben:Wenn der Interpreter möglichst einfach sein soll, dann empfehle ich Scheme. Ein nacktes Scheme ohne Systemfunktionen kann man in unter 100 Zeilen bauen.
Guile ist ähnlich wie Lua speziell für die einbettung in andere Programme gedacht gewesen. Außerdem gibt es auch noch TinyScheme, welches etwa von Gimp verwendet wird. Haben aber wie es sich für Schemes gehört, keine Schleifen. Man könnte allerdings auch ECL einbinden, ein einbettbares Common Lisp, dass dann fast schon sein "kitchen sink" mitbringt. Und, nun ja, eben Lua selbst. Zur Not baut man sich das Python-Binding selbst, muss aber keine eigene Sprache designen. Wie man an sma sieht ist der individuelle Ansatz dazu sehr verschieden. Eine weitere Alternative ist RPython, vielleicht kann man das irgendwie sandboxen.

Verfasst: Donnerstag 27. November 2008, 20:12
von ernstla
Danke Stefan

Leider reichen die Möglichkeiten von Jinja und Konsorten nicht aus. Es geht eher in die Richtung, die Du weiter unten beschreibst.

Endlosschleifen und ähnliches bleiben natürlich ein Problem, das es zu berücksichtigen gilt.

An einen eigenen kleinen, an JavaScript angelehnten Interpreter habe ich auch schon gedacht, eben weil es so bekannt ist. Und natürlicherweise auch an Python. Sogar an einen Lisp-Dialekt.

Dachte mir schon hier schlecht herum zu kommen. Aber wie du schon sagst: Schöne Fingerübung.

Danke

Thomas

Verfasst: Donnerstag 27. November 2008, 20:37
von veers
Wenn du etwas Konkreter wirst was du damit genau machen willst könnte ich dir vermutlich ein paar Vorschläge machen.

Verfasst: Freitag 28. November 2008, 10:05
von ernstla
Okay, ich hätte vielleicht etwas klarer sein sollen. Eine formularbasierende Workflowanwendung, die den Großteil der Daten in einer eigenen Datenbank hält, erklärt die Anwendung wohl am besten.

Im Ablauf des Workflows würde die Sprache an mehreren Stellen zum Einsatz kommen. Zum einen soll sie Boolsche Ausdrücke auswerten, über die der Ablauf gesteuert wird. In den Ausdrücken können Funktionen verwendet werden, die die zu überprüfenden Daten liefern.

Zum anderen muss sie auch als eine Art Trigger- oder Batchsprache herhalten. Im Ablauf treten vom Benutzer zu bearbeitende Tasks auf, aber auch automatisierte. Die automatisierten könnten z. B. Summen berechnen, Stammdaten abgleichen, ACL setzen, evtl. Web Services aufrufen usw. Wichtig ist, dass die Sprache dabei nur einen klar eingegrenzten Spielraum hat, also nur auf eine bereitgestellte API zugreifen kann. Es sollte weder auf das Dateisystem zugegriffen, noch irgendwelche Prozesse gestartet oder Module eingebunden werden können.

Zur Information: Im (Lotus Notes) System, das durch die Webanwendung abgelöst wird, gab es Skripte, die zum Teil mehrere hundert Zeilen lang waren. Nur um deutlich zu machen, dass schon eine gewisse Komplexitätsstufe erreicht werden kann.

Ich hoffe ich konnte etwas Licht ins Dunkel bringen.

Thomas

Verfasst: Freitag 28. November 2008, 10:17
von Hyperion
ernstla hat geschrieben: ..., ACL setzen, evtl. Web Services aufrufen usw.
ernstla hat geschrieben: Wichtig ist, dass die Sprache dabei nur einen klar eingegrenzten Spielraum hat, also nur auf eine bereitgestellte API zugreifen kann. Es sollte weder auf das Dateisystem zugegriffen, noch irgendwelche Prozesse gestartet oder Module eingebunden werden können.
Das klingt für mich ein wenig widersprüchlich!

Verfasst: Freitag 28. November 2008, 10:32
von ernstla
Der Zugriff auf ACL (damit ist nicht die ACL des Betriebssystems gemeint, sondern die Programmeigene), der Zugriff auf Web Services und der ganze Rest würden von der API zur Verfügung gestellt werden. Es sollen keine externen Module geladen werden können.

Verfasst: Freitag 28. November 2008, 10:59
von veers
Ok, das bringt schon viel mehr Klarheit.
In der Firma in der ich Arbeite haben wir ein solches Workflow System. Da wird das an stelle von Scripts mit einem Grafischen Worklow Editor und vordefinierten Aktionen gelöst. Das scheint aber nicht das zu sein was du willst. Was du willst, sollte aber mit Python möglich sein.

Hast du das schon gesehen:
http://wiki.python.org/moin/How%20can%2 ... 20Sandbox)

Es wäre interessant zu wissen wie die Sandbox von Appengine realisiert wurde...

Verfasst: Freitag 28. November 2008, 12:18
von ernstla
Der Ansatz mit den vordefinierten Aktionen die im GUI konfiguriert werden, können wir nur zum Teil umsetzten. Manche Anforderungen lassen sich wohl am einfachsten per Skript umsetzen. Wir denken eher daran, dass die im GUI konfigurierbaren Aktionen in ein Skript übersetzt werden, das dann wiederum ausgeführt wird. Manche Sachen sind aber so komplex, dass sie sich nicht über ein GUI abbilden lassen.

Ja, die Seite kenne ich. Da stößt man relativ schnell drauf. Da die Anwendung auch unter Windows läuft, fällt der Ansatz mit chroot und jails wohl weg.

Verfasst: Freitag 28. November 2008, 13:23
von veers
Ich frage mich wie schwer es wäre die ganzen os/sys/... Funktionen die Zugriff auf das Betriebsystem zu lassen aus CPython zu entfernen. Müsste doch relativ einfach machbar sein, oder übersehe ich da etwas?

TinyPy zu hacken wäre vielleicht auch noch ein Ansatz.

Verfasst: Freitag 28. November 2008, 13:30
von Leonidas
veers hat geschrieben:Es wäre interessant zu wissen wie die Sandbox von Appengine realisiert wurde...
Wenn man CPython hackt geht das wunderbar und Guido wird wohl in der Lage sein, alle möglichen Elemente zu entfernen bis nur noch "sicheres" zurückbleibt.

Verfasst: Freitag 28. November 2008, 13:40
von veers
Leonidas hat geschrieben:
veers hat geschrieben:Es wäre interessant zu wissen wie die Sandbox von Appengine realisiert wurde...
Wenn man CPython hackt geht das wunderbar und Guido wird wohl in der Lage sein, alle möglichen Elemente zu entfernen bis nur noch "sicheres" zurückbleibt.
Zu schade wird das nicht Publiziert...

Verfasst: Freitag 28. November 2008, 14:15
von lunar
veers hat geschrieben:
Leonidas hat geschrieben:
veers hat geschrieben:Es wäre interessant zu wissen wie die Sandbox von Appengine realisiert wurde...
Wenn man CPython hackt geht das wunderbar und Guido wird wohl in der Lage sein, alle möglichen Elemente zu entfernen bis nur noch "sicheres" zurückbleibt.
Zu schade wird das nicht Publiziert...
Security by obscurity halt ;)

Verfasst: Freitag 28. November 2008, 17:11
von Mad-Marty
Ich würde wahrscheinlich damit anfangen import und __import__ zu entfernen. Zumindest die verwendung in den Scripten.

Dann alles was nach subprocess, Popen und systecall riecht sowie file-system-access.


Damit ist es dann imo schon relativ stark sandboxed.
Wäre noch die frage nach den Ressourcen ... ein Controller muss her umd die PC ressourcen nur im bestimmten umfang bereitzustellen.

Und natürlich alle module weg die nicht gebraucht werden. Insbesondere Ctypes u.ä., weil das ja ein freifahrtschein auf systemrechte ist ;)


Denke sowas ist durchaus in 1 woche machbar das es vorerst funktioniert, bis zur perfektion aber wohl doch ein bischen mehr ;)

Verfasst: Freitag 28. November 2008, 18:57
von fred.reichbier
Hallo,

ich hab gerade zufällig PyGuile gefunden und möchte den Link einfach noch einbringen, weil Guile ja auch erwähnt wurde :D

Nebenbei, ich fänd ein Python-Binding für tinypy recht interessant. Hacken an tinypy selbst muss man glaube ich nichts, wenn ich das richtig sehe, hats ja noch keine "batteries included - yet".
Die Lösung mit einem 'Normal-Python' und ein paar Verboten ist aber sicherlich die Unsauberste ... ich denke auch nicht, dass man das effektiv 'sicher' bekommt :/

Gruß,

Fred

Verfasst: Freitag 28. November 2008, 19:35
von Leonidas
fred.reichbier hat geschrieben:Die Lösung mit einem 'Normal-Python' und ein paar Verboten ist aber sicherlich die Unsauberste ... ich denke auch nicht, dass man das effektiv 'sicher' bekommt :/
Ja, der hier vorgeschlagene Ansatz ist eher ein Python zu verwenden, wo eben viele Sachen auskompiliert. PyGuile geht aber den anderen Ansatz, es ruft aus dem Guile-Interpreter Python auf, zumindest habe ich es so verstanden.

Verfasst: Freitag 28. November 2008, 19:59
von fred.reichbier
Oh, du hast recht. Naja, wenigstens sagt der Autor hier, dass PyGuile später auch bidirektional funktionieren soll.

Verfasst: Freitag 28. November 2008, 20:56
von Leonidas
fred.reichbier hat geschrieben:Oh, du hast recht. Naja, wenigstens sagt der Autor hier, dass PyGuile später auch bidirektional funktionieren soll.
Besser noch, er linkt auf Schemepy, ein in Python eingebettetes Scheme. Wenn man ins das Archiv schaut, dann stellt man fest dass es sogar noch besser ist als erwartet, es unterstützt mehrere Schemes, momentan Guile und MzScheme (also das von PLT Scheme). Es soll sogar pure-Python Fallbacks haben, vermutlich über ctypes. Mein Lieblingsscheme mit Python kombiniert ist super, mal sehen wo ich das verwenden kann :)

Übrigens, der Tarball ist wohl aus versehen zweimal mit gzip gepackt, also falls euer Packprogramm da meckert, einfach einmal gunzip laufen lassen.

Edit: Der Fallback scheint ein selbstgebautes Scheme zu sein. Naja, muss man ja nicht nutzen. Ansonsten bin ich begeistert: DVCS-Repository, gute Idee, flexible Implementierung (soll laut beschreibung auch Sandboxing unterstützen). Jetzt ist nur die Frage ob es auch funktioniert, werde das demnächst mit Mz ausprobieren.

Verfasst: Samstag 29. November 2008, 11:26
von sma
Leonidas hat geschrieben:flexible Implementierung (soll laut beschreibung auch Sandboxing unterstützen)
Wenn ich beliebigen Code an MzScheme schicken kann, wie soll das eine Sandbox sein? Nach wie vor bin ich nicht von der Idee überzeugt, eine existierende Sprachimplementierung irgendwie per C-API an Python anzuflanschen.

Auch der Versuch, einfach genug bei CPython wegzulassen, um ein "sicheres" Sprachsubset zu bekommen, fühlt sich falsch an. Der Quelltext ist recht umfangreich und eine Garantie, dass man nichts übersieht, gibt es nicht. Ich meine gehört zu haben, dass das "härten" der Python-Version für die App-Engine Monate gedauert hat, weil die Zeile für Zeile den Quelltext gelesen und überprüft haben. Neben den offensichtlichen Problemen wie file-IO kann es ja bedingt durch die Implementationssprache C immer noch alle Arten von Buffer-Überläufen oder sonstigen Speicherfehlern kommen. Das mag vielleicht nur ein Problem für Google sein und wäre dem Poster dieses Threads hier egal, dennoch ist der Ansatz IMHO nicht empfehlenswert.

Besser finde ich daher den konstruktiven Ansatz, nur das zusammenzufügen, wo man sicher ist, dass man dadurch eine Sandbox nicht öffnet.

Stefan