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__
zexec
kontekstu, aby zabronić używania potencjalnie niebezpiecznych pakietów, takich jakos
. 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
exec
kontekś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.NodeVisitor
do 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ą
PyPy
lub 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.
python
security
web-services
pswg
źródło
źródło
Odpowiedzi:
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:
Ned Batchelder zaczyna od demonstracji, jak niebezpieczny
eval()
jest naprawdę ;eval()
jest często używany do wykonywania wyrażeń w języku Python; jako prymitywna i naiwna piaskownica dla jedno-liniowców.Następnie kontynuował próby zastosowania tych samych zasad w Pythonie 3 , ostatecznie udało mu się przełamać dzięki kilku pomocnym wskazówkom.
Pierre Bourdon używa podobnych technik do zhakowania systemu pythonowego podczas hack-a-thon
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
exec
instrukcji (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
os
znajduje się nazwa lokalna,os
która odnosi się doos
modułu. Może to doprowadzić zdeterminowanego napastnika do modułów, które pomogą im wydostać się z piaskownicy. Napickle
przykł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 dopickle
moduł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.
RestrictedPython
przekształ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
RestrictedPython
jest 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.
źródło
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:
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.
źródło
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.
źródło
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.
źródło
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
źródło