Najlepsze praktyki wykonywania niezaufanego kodu


31

Mam projekt, w którym muszę pozwolić użytkownikom na uruchamianie na moim serwerze dowolnego, niezaufanego kodu Pythona ( trochę takiego ). Jestem całkiem nowy w Pythonie i chciałbym uniknąć błędów, które wprowadzają luki w zabezpieczeniach lub inne luki w systemie. Czy są dostępne najlepsze praktyki, zalecane lektury lub inne wskazówki, które możesz mi przekazać, aby uczynić moją usługę użyteczną, ale nie nadużywającą?

Oto, co do tej pory rozważałem:

  • Usuń __builtins__z execkontekstu, aby zabronić używania potencjalnie niebezpiecznych pakietów, takich jak os. Użytkownicy będą mogli korzystać tylko z pakietów, które im dostarczam.
  • Użyj wątków, aby wymusić rozsądny limit czasu.
  • Chciałbym ograniczyć całkowitą ilość pamięci, którą można przydzielić w execkontekście, ale nie jestem pewien, czy to w ogóle możliwe.

Istnieje kilka alternatyw dla strita exec, ale nie jestem pewien, która z nich byłaby tutaj pomocna:

  • Używanie ast.NodeVisitordo przechwytywania wszelkich prób uzyskania dostępu do niebezpiecznych obiektów. Ale jakich przedmiotów powinienem zabronić?
  • Wyszukiwanie dowolnych podwójnych znaków podkreślenia na wejściu. (mniej wdzięczny niż powyższa opcja).
  • Za pomocą PyPylub podobnego do piaskownicy kodu.

UWAGA: Zdaję sobie sprawę, że istnieje co najmniej jeden tłumacz oparty na JavaScript. To nie zadziała w moim scenariuszu.



3
@MartijnPieters: Doskonale. Prawdopodobnie warta odpowiedzi, jeśli podsumujesz każdą z nich.
Robert Harvey

Zastanów się również: śmieci pozostawione na dysku, sieć (nie pozwól im wysyłać spamu lub czegokolwiek), uprawnienia do innych plików (odczyt plików). Nawet wysunięcie w pętli while może zniszczyć mechanikę CD ... Poszedłbym na wirtualizację (więzienia lub jakieś kvm, jak to nazwiesz) lub przynajmniej użytkownika bez prawie żadnych uprawnień. Ustaw rozsądną ilość pamięci i korzystaj z własnych programów.
kyticka


1
Wypróbuj PyPy :> Sandboxing: PyPy zapewnia możliwość uruchamiania niezaufanego kodu w całkowicie bezpieczny sposób.
Vorac,

Odpowiedzi:


28

Piaskownica w Pythonie jest trudna . Python jest z natury introspektywny na wielu poziomach.

Oznacza to również, że możesz znaleźć metody fabryczne dla konkretnych typów z tych samych typów i zbudować nowe obiekty niskiego poziomu, które będą uruchamiane bezpośrednio przez interpretera bez ograniczeń.

Oto kilka przykładów znalezienia kreatywnych sposobów na wyjście z piaskownicy Python:

Podstawową ideą jest zawsze znalezienie sposobu na stworzenie podstawowych typów Pythona; funkcje i klasy oraz wyrwać się z powłoki, zmuszając interpreter języka Python do wykonania dowolnego (niezaznaczonego!) kodu bajtowego.

To samo i więcej dotyczy execinstrukcji ( exec()funkcja w Pythonie 3).

Więc chcesz:

  • Ściśle kontrolować kompilację bajtów kodu Pythona lub przynajmniej przetworzyć kod bajtowy, aby usunąć dostęp do nazw zaczynających się od podkreślników.

    Wymaga to dokładnej wiedzy na temat działania interpretera języka Python i struktury kodu bajtowego Pythona. Obiekty kodu są zagnieżdżone; kod bajtowy modułu obejmuje tylko najwyższy poziom instrukcji, każda funkcja i klasa składa się z własnej sekwencji kodu bajtowego oraz metadanych, zawierających na przykład inne obiekty kodu bajtowego dla zagnieżdżonych funkcji i klas.

  • Musisz dodać do białej listy moduły, których można użyć. Ostrożnie.

    Moduł python zawiera odniesienia do innych modułów. Po zaimportowaniu w przestrzeni nazw modułu osznajduje się nazwa lokalna, osktóra odnosi się do osmodułu. Może to doprowadzić zdeterminowanego napastnika do modułów, które pomogą im wydostać się z piaskownicy. Na pickleprzykład moduł pozwala na przykład ładować dowolne obiekty kodu, więc jeśli jakakolwiek ścieżka prowadząca do modułów z białej listy prowadzi do picklemodułu, problem nadal występuje.

  • Musisz ściśle ograniczyć limity czasowe. Nawet najbardziej neutralny kod może nadal próbować działać wiecznie, wiążąc zasoby.

Spójrz na RestrictedPython , który próbuje zapewnić ci ścisłą kontrolę kodu bajtowego. RestrictedPythonprzekształca kod Pythona w coś, co pozwala kontrolować, jakie nazwy, moduły i obiekty są dozwolone w Pythonie od 2.3 do 2.7.

Jeśli RestrictedPythonjest wystarczająco bezpieczny dla Twoich celów, zależy od wdrażanych zasad. Niedopuszczenie do dostępu do nazw zaczynających się od podkreślenia i ścisłej białej listy modułów byłoby początkiem.

Moim zdaniem jedyną naprawdę solidną opcją jest użycie oddzielnej maszyny wirtualnej, która nie ma dostępu do sieci do świata zewnętrznego, który niszczysz po każdym uruchomieniu. Zamiast tego każdy nowy skrypt otrzymuje nową maszynę wirtualną. W ten sposób nawet jeśli kodowi uda się wyrwać z piaskownicy Pythona (co nie jest mało prawdopodobne), dostęp do atakującego jest krótkotrwały i bez wartości.


10

TL; DR Użyj chroot / jail i uruchom jako niestandardowy użytkownik bez żadnych uprawnień.

Najlepszą praktyką do wykonywania niezaufanego kodu jest segregacja go za pomocą systemowego obszaru izolowanego. Dla większego bezpieczeństwa:

  • utwórz kontener zawierający tylko Pythona i jego zależności oraz zależności kontenera
  • utwórz kontener bez wszystkich urządzeń, które nie są absolutnie konieczne (tj. sieć i pamięć)
  • utwórz kontener z ograniczeniami użycia pamięci i procesu
  • odtwórz kontener przy każdym uruchomieniu (lub przynajmniej przy każdym unikalnym użytkowniku i maksymalnym okresie)
  • działaj jako użytkownik z najmniejszymi potrzebnymi uprawnieniami
  • uruchom jako użytkownik, który nie ma uprawnień do zapisywania plików

Postępujesz również zgodnie ze standardowymi praktykami bezpiecznego działania w chroot. Możesz odbudować system plików chroota przy każdym wywołaniu, jest to szczególnie paranoiczne. Zazwyczaj po prostu uniemożliwiasz użytkownikowi modyfikację systemu plików, w którym działa chroot.


Jest to jedyna rzecz, w której będziesz nawet zdalnie pewien, że masz rację - daj jej własny proces.
Michael Kohne

3

Nie ma możliwości, aby zrobić to bezpiecznie.

Jeśli chcesz zrobić coś takiego bezpiecznie, musisz zacząć od własnej implementacji Pythona, która działa w całkowicie kontrolowanym środowisku, najlepiej w przeglądarce użytkownika zamiast w twoim systemie. Możesz zacząć od Jython (python dla java) i spakować go jako aplet java. Ponieważ działałby w piaskownicy Java na komputerze użytkownika, twój system byłby w miarę bezpieczny.


4
Kwestia bezpieczeństwa dotyczyła jego serwera, a nie komputera klienta. Potencjalne zagrożenia bezpieczeństwa Javy, takie jak w przypadku innych technologii sieciowych, polegają na tym, że serwer może być wykorzystywany do wdrażania programów niebezpiecznych dla klienta.
ddyer

1
@grasGendarme, podobnie jak nowe historie o katastrofach lotniczych, w rzeczywistości wiele mówi o tym, jak rzadkie są one; historie o lukach w zabezpieczeniach Java informują, że Java jest stosunkowo bezpieczna. Nigdy nie spotkałbyś się z taką historią o C, ponieważ odpowiedź brzmiałaby: „no cóż, jeśli ją uruchomisz, zrobi wszystko, co zechce”
Richard Tingle

2

Jak powiedział Martijn powyżej, w Pythonie jest to naprawdę bardzo trudne. Szczerze mówiąc, ponieważ Python jest introspektywny, nie sądzę, aby było to możliwe poprzez ograniczenie funkcji językowych. A jeśli dostaniesz piaskownicę działającą dla jednej wersji Pythona, istnieje szansa, że ​​następna wersja go złamie.

Chciałbym spojrzeć na PyPy zamiast standardowego CPython. Krótko mówiąc, jest to zgodna alternatywna implementacja języka Python. Ma kilka zalet i wyraźne cechy, a jedną z nich jest piaskownica poprzez zastępowanie wywołań systemowych zamiast ograniczania funkcji językowych.


0

Tak długo, jak wydajność nie jest dla Ciebie bardzo ważna, zawsze możesz uruchomić ją w Brython, co skutecznie umieszcza ją w piaskownicy JavaScript

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.