Ich habe an einem persönlichen Projekt in C # gearbeitet, dessen Zweck mehr oder weniger darin besteht, dem Benutzer das Ausführen von Skripten zu ermöglichen, die von anderen Benutzern geschrieben wurden, und die Berechtigungen dieses Skripts einzuschränken. Mein Programm kompiliert die Skripte mithilfe einer Bibliothek eines Drittanbieters, speichert sie mithilfe der .NET Code Access Security-Mechanismen in Sandboxen und stellt sicher, dass sie nur über die Berechtigungen verfügen, die der Benutzer ihnen erteilen möchte.
Im Großen und Ganzen sind meine Sicherheitsanforderungen:
- Der Benutzer sollte in der Lage sein, den Zugriff des nicht vertrauenswürdigen Skripts nur auf bestimmte Teile des Dateisystems zu beschränken, einschließlich des Verbots des gesamten Dateisystemzugriffs
- Der Benutzer sollte in der Lage sein, die Netzwerkverbindungen des nicht vertrauenswürdigen Skripts nur auf bestimmte IP-Adressen oder Hostnamen zu beschränken, einschließlich des Verbots aller Netzwerkverbindungen
- Es ist in Ordnung, wenn das Benutzerskript es schafft, die Hostanwendung zu hängen oder zu beenden, aber das Benutzerskript darf die Berechtigungsbeschränkungen nicht umgehen können (dh Denial-of-Service ist in Ordnung, Verletzung nicht).
Ich denke darüber nach, etwas Ähnliches in C ++ zu tun, als eine Art persönliche Übung. Offensichtlich sind die Dinge komplizierter, wenn nativer Code direkt ausgeführt wird, selbst wenn die Benutzerskripte in einer Skriptsprache wie Lua geschrieben sind.
Der erste Ansatz, den ich mir vorstellen kann, besteht darin, meine eigenen Hooks in die Standardbibliotheksfunktionen der Skriptumgebung einzufügen. Wenn die Skriptsprache beispielsweise Lua ist, müsste ich, anstatt io.open normal verfügbar zu machen, einen Wrapper verfügbar machen, der die Argumente mit den Berechtigungen des Skripts vergleicht, bevor sie an die ursprüngliche Implementierung übergeben werden.
Mein Anliegen bei diesem Ansatz ist, dass er die Menge meines eigenen Codes, der für die Sicherheit zuständig ist, drastisch erhöht und daher eine potenzielle Sicherheitslücke darstellt, die ich selbst geschrieben habe. Mit anderen Worten, wenn ich mit .NET CAS arbeite, kann ich darauf vertrauen, dass Microsoft seine Arbeit im Sandbox-Code gut gemacht hat, anstatt meinem eigenen Sandbox-Code vertrauen zu müssen.
Gibt es Alternativen, die mir nicht bekannt sind?
Antworten:
Wie andere bereits festgestellt haben, ist das Ausführen von Fremdcode das größte Problem bei dieser Art der Implementierung. Wie in Kain0_0s Kommentar vorgeschlagen, wäre eine VM der am besten geeignete Weg, um die Freiheit von Fremdcode aufrechtzuerhalten, ohne den Host-Computer zu gefährden (zu viel). Dies ist im Grunde das, was Continuous Integration Services wie CircleCI tun.
Dies erleichtert auch die Implementierung der Benutzeroberfläche erheblich, da Sie Bilder mit allen gewünschten Konfigurations- und Sicherheitsfunktionen abrufen können. Sie müssen sich auch keine Sorgen machen, ob der Code auf Ihrem Host ausgeführt werden kann.
Dafür würde ich:
Erstellen Sie Snapshots von Benutzerskriptumgebungen, die ich mit Docker behandeln möchte (eine Umgebung für C #, eine für Python usw. mit den entsprechenden Sicherheitskonfigurationen).
Starten Sie auf Benutzeranforderung Docker-relevante Instanzen über den Code-Trigger und fügen Sie das Fremdskript in den Einstiegspunkt der Docker-Instanz ein.
Der Code wird in der Docker-Instanz mit Benutzerberechtigungen ausgeführt, Dateien werden geschrieben, möglicherweise wird hier und da eine Verbindung hergestellt, die Ausgabe abgerufen und die Umgebung wird dann zerstört
Da Docker-Container als Prozesse ausgeführt werden, können sie relativ einfach beendet werden, dh wenn sie ein bestimmtes Zeitlimit überschreiten. Wenn ein Fehler auftritt, können sie sofort beendet werden.
Lassen Sie Ihren Hauptcode grundsätzlich den Benutzerauslöser, die Einstiegspunktinjektion und die automatische Zerstörungslogik für Docker verwalten, das für das Sandboxing für diese Art von Operation verantwortlich ist.
quelle