Mam sytuację z kodem, w którym eval()
pojawił się jako możliwe rozwiązanie. Teraz nigdy wcześniej nie musiałem używać, eval()
ale natknąłem się na wiele informacji o potencjalnym niebezpieczeństwie, jakie może spowodować. To powiedziawszy, jestem bardzo ostrożny, jeśli chodzi o jego używanie.
Moja sytuacja jest taka, że mam dane wejściowe podane przez użytkownika:
datamap = raw_input('Provide some data here: ')
Gdzie datamap
musi być słownik. Rozejrzałem się i odkryłem, że eval()
może to rozwiązać. Pomyślałem, że mógłbym być w stanie sprawdzić typ danych wejściowych przed próbą ich użycia i byłoby to realne zabezpieczenie.
datamap = eval(raw_input('Provide some data here: ')
if not isinstance(datamap, dict):
return
Czytałem dokumenty i wciąż jestem niejasny, czy to byłoby bezpieczne, czy nie. Czy eval ocenia dane zaraz po ich wprowadzeniu lub po datamap
wywołaniu zmiennej?
Czy ast
moduł jest .literal_eval()
jedyną bezpieczną opcją?
źródło
ast.literal_eval("1 & 1")
zgłosi błąd, aleeval("1 & 1")
tak się nie stanie.ast.literal_eval
do czegoś takiego (np. mógłbyś ręcznie zaimplementować parser).ast.literal_eval()
uważa tylko niewielki podzbiór składni Pythona za prawidłowy:Przejście
__import__('os').system('rm -rf /a-path-you-really-care-about')
doast.literal_eval()
spowoduje błąd, aleeval()
z radością wyczyści dysk.Ponieważ wygląda na to, że pozwalasz użytkownikowi wprowadzić zwykły słownik, użyj
ast.literal_eval()
. Bezpiecznie robi to, co chcesz i nic więcej.źródło
eval: Jest to bardzo potężne, ale jest również bardzo niebezpieczne, jeśli akceptujesz ciągi znaków do oceny z niezaufanych danych wejściowych. Załóżmy, że oceniany ciąg to „os.system ('rm -rf /')”? Naprawdę rozpocznie się usuwanie wszystkich plików z twojego komputera.
ast.literal_eval: Bezpiecznie oceniaj węzeł wyrażenia lub ciąg znaków zawierający literał Pythona lub wyświetlany kontener. Dostarczony ciąg lub węzeł może składać się tylko z następujących struktur literałów Pythona: łańcuchów, bajtów, liczb, krotek, list, dykt, zestawów, wartości logicznych, Brak, bajtów i zestawów.
Składnia:
Przykład:
W powyższym kodzie
().__class__.__bases__[0]
nic poza samym obiektem. Teraz utworzyliśmy instancję wszystkich podklas , tutaj naszym głównymenter code here
celem jest znalezienie z niej jednej klasy o nazwie n .Musimy
code
obiekt ifunction
obiekt z instancji podklas. Jest to alternatywny sposóbCPython
uzyskania dostępu do podklas obiektu i dołączenia systemu.Od pythona 3.7 metoda ast.literal_eval () jest teraz bardziej rygorystyczna. Dodawanie i odejmowanie dowolnych liczb nie jest już dozwolone. połączyć
źródło
ast.literal_eval("1+1")
nie działa w Pythonie 3.7 i jak wspomniano wcześniej, literal_eval powinien być ograniczony do literałów tych kilku struktur danych. Nie powinien być w stanie przeanalizować operacji binarnej.KABOOM
kod? Znalazłem go tutaj:KABOOM
KABOOM
jest ładnie wyjaśnione tutaj: nedbatchelder.com/blog/201206/eval_really_is_dangerous.htmlPython jest chętny do oceny, więc
eval(raw_input(...))
oceni dane wejściowe użytkownika, gdy tylko trafiąeval
, niezależnie od tego, co później zrobisz z danymi. Dlatego nie jest to bezpieczne , zwłaszcza podczaseval
wprowadzania danych przez użytkownika.Użyj
ast.literal_eval
.Na przykład wpisanie tego w monicie będzie dla ciebie bardzo, bardzo złe:
źródło
Jeśli potrzebujesz tylko słownika dostarczonego przez użytkownika, prawdopodobnie lepszym rozwiązaniem jest
json.loads
. Głównym ograniczeniem jest to, że json dicts wymaga kluczy łańcuchowych. Możesz również podać tylko dane dosłowne, ale tak jest również w przypadkuliteral_eval
.źródło
Utknąłem z
ast.literal_eval()
. Próbowałem tego w debugerze IntelliJ IDEA i ciągle wracałNone
na wyjściu debuggera.Ale później, kiedy przypisałem jego wyjście do zmiennej i wydrukowałem w kodzie. Działało dobrze. Przykład kodu udostępniania:
Jego wersja Pythona 3.6.
źródło