Przez te wszystkie lata, kiedy rozwijałem się w PHP, zawsze słyszałem, że używanie eval()
jest złe.
Biorąc pod uwagę poniższy kod, czy nie miałoby sensu użycie drugiej (i bardziej eleganckiej) opcji? Jeśli nie, dlaczego?
// $type is the result of an SQL statement
// e.g. SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string
$type = "enum('a','b','c')";
// possibility one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);
// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');
$result = array(); preg_replace_callback('#^enum\s*\(\s*\'|\'\s*\)\s*$#', function($m) use($result) { $result[] = $m[1]; }, $type);
Odpowiedzi:
Byłbym ostrożny, nazywając eval () czystym złem. Dynamiczna ocena jest potężnym narzędziem i czasami może uratować życie. Dzięki eval () można obejść wady PHP (patrz poniżej).
Główne problemy z eval () to:
Główny problem z faktycznym użyciem eval () jest tylko jeden:
Z reguły postępuję zgodnie z następującą zasadą:
źródło
eval jest zły, gdy istnieje tylko najmniejsza możliwość, że dane wejściowe użytkownika są uwzględnione w ocenianym ciągu. Kiedy przeprowadzasz ewaluację bez treści pochodzących od użytkownika, powinieneś być bezpieczny.
Niemniej jednak powinieneś pomyśleć co najmniej dwa razy przed użyciem eval, wygląda to zwodniczo prosto, ale biorąc pod uwagę obsługę błędów (patrz komentarz VBAssassins), możliwość debugowania itp., Nie jest już takie proste.
A więc praktyczna zasada: zapomnij o tym. Kiedy eval jest odpowiedzią, prawdopodobnie zadajesz niewłaściwe pytanie! ;-)
źródło
eval()
jest niemożliwe, jest to lepsze podejście. Wiele osób twierdzi, żeeval()
w niektórych przypadkach jest to nieuniknione, ale nie podają żadnych konkretnych przykładów, które moglibyśmy argumentować - w ten sposób ta debata nie ma sensu. Więc proszę, ludzie, którzy mówią, żeeval()
jest to nieuniknione, najpierw udowodnijcie to!eval () jest zawsze równie zła.
„Kiedy eval () nie jest zły?” jest moim zdaniem niewłaściwym pytaniem, ponieważ wydaje się sugerować, że wady używania eval () magicznie znikają w niektórych kontekstach.
Używanie eval () jest ogólnie złym pomysłem, ponieważ zmniejsza czytelność kodu, możliwość przewidywania ścieżki kodu (i możliwych konsekwencji dla bezpieczeństwa) przed uruchomieniem, a tym samym możliwość debugowania kodu. Użycie eval () może również zapobiec optymalizacji kodu ocenianego i otaczającego go kodu przez pamięć podręczną kodu operacji, taką jak Zend Opcache zintegrowana z PHP 5.5 i nowszymi wersjami, lub przez kompilator JIT, taki jak ten w HHVM.
Ponadto nie ma sytuacji, w której użycie eval () byłoby absolutnie konieczne - PHP jest w pełni funkcjonalnym językiem programowania bez niego.
To, czy faktycznie postrzegasz je jako zło, czy też możesz osobiście uzasadnić użycie eval () w niektórych przypadkach, zależy od Ciebie. Dla niektórych zło jest zbyt wielkie, aby kiedykolwiek je usprawiedliwić, a dla innych eval () to przydatny skrót.
Jeśli jednak postrzegasz eval () jako zło, jest ono złe przez cały czas. W zależności od kontekstu nie traci magicznie swojego zła.
źródło
W tym przypadku eval jest prawdopodobnie wystarczająco bezpieczny, o ile użytkownik nigdy nie może utworzyć dowolnych kolumn w tabeli w tabeli.
Jednak nie jest już bardziej elegancki. Jest to w zasadzie problem z analizą tekstu, a wykorzystywanie parsera PHP do obsługi wydaje się trochę hakerskie. Jeśli chcesz nadużywać funkcji językowych, dlaczego nie nadużywać parsera JSON? Przynajmniej w przypadku parsera JSON nie ma żadnej możliwości wstrzyknięcia kodu.
$json = str_replace(array( 'enum', '(', ')', "'"), array) '', '[', ']', "'"), $type); $result = json_decode($json);
Wyrażenie regularne jest prawdopodobnie najbardziej oczywistym sposobem. Możesz użyć jednego wyrażenia regularnego, aby wyodrębnić wszystkie wartości z tego ciągu:
$extract_regex = '/ (?<=,|enum\() # Match strings that follow either a comma, or the string "enum("... \' # ...then the opening quote mark... (.*?) # ...and capture anything... \' # ...up to the closing quote mark... /x'; preg_match_all($extract_regex, $type, $matches); $result = $matches[1];
źródło
eval()
jest powolny, ale nie nazwałbym tego złem.To zły użytek, jaki z niego zrobimy, może prowadzić do wstrzyknięcia kodu i być złym.
Prosty przykład:
$_GET = 'echo 5 + 5 * 2;'; eval($_GET); // 15
Szkodliwy przykład:
$_GET = 'system("reboot");'; eval($_GET); // oops
Radziłbym ci nie używać,
eval()
ale jeśli to zrobisz, upewnij się, że potwierdziłeś / dodałeś do białej listy wszystkie dane wejściowe.źródło
Gdy używasz obcych danych (takich jak dane wejściowe użytkownika) wewnątrz eval.
W powyższym przykładzie nie stanowi to problemu.
źródło
rażąco ukradnę zawartość tutaj:
blog.joshuaeichorn.com: using-eval-in-php
źródło
eval()
jest zawsze zły.źródło
eval()
tak szybko, jak zakładam, że zadałem pytanie źle; rzadko jest to „właściwa” odpowiedź, ale stwierdzenie, że jest ono zawsze złe, jest po prostu błędne.Zwróciłbym również uwagę na osoby obsługujące Twój kod.
eval () nie jest łatwe do obejrzenia i dowiedzenia się, co powinno się wydarzyć, twój przykład nie jest taki zły, ale w innych miejscach może to być właściwy koszmar.
źródło
Osobiście uważam, że ten kod jest nadal dość zły, ponieważ nie komentujesz tego, co robi. Nie testuje również swoich danych wejściowych pod kątem ważności, co czyni go bardzo delikatnym.
Uważam również, że ponieważ 95% (lub więcej) zastosowań eval jest aktywnie niebezpiecznych, niewielka potencjalna oszczędność czasu, jaką może on zapewnić w innych przypadkach, nie jest warta oddawania się złej praktyce jego używania. Poza tym będziesz musiał później wyjaśnić swoim sługom, dlaczego twoje użycie eval jest dobre, a ich złe.
I, oczywiście, twój PHP wygląda jak Perl;)
Istnieją dwa kluczowe problemy z eval () (jako scenariusz „ataku iniekcyjnego”):
1) Może spowodować obrażenia 2) Może po prostu się zawiesić
i bardziej społeczny niż techniczny:
3) Będzie to kusić ludzi do niewłaściwego używania go jako skrótu w innym miejscu
W pierwszym przypadku ryzykujesz (oczywiście nie wtedy, gdy oceniasz znany ciąg znaków) wykonania dowolnego kodu. Twoje dane wejściowe mogą jednak nie być tak znane lub ustalone, jak myślisz.
Bardziej prawdopodobne jest (w tym przypadku) awarię, a ciąg znaków zakończy się nieuzasadnionym niejasnym komunikatem o błędzie. IMHO, cały kod powinien zawieść tak starannie, jak to możliwe, aw przypadku niepowodzenia powinien zgłosić wyjątek (jako najłatwiejszą do obsługi formę błędu).
Sugerowałbym, że w tym przykładzie kodujesz przez przypadek, a nie na zachowanie. Tak, instrukcja wyliczenia SQL (i czy na pewno wyliczenie tego pola? - czy wywołałeś właściwe pole odpowiedniej tabeli odpowiedniej wersji bazy danych? Czy faktycznie odpowiedziała?) Wygląda jak składnia deklaracji tablicy w PHP, ale sugerowałbym, że naprawdę nie chcesz znaleźć najkrótszej ścieżki od wejścia do wyjścia, ale raczej zająć się określonym zadaniem:
To mniej więcej to, co robi twoja opcja, ale zawinąłbym wokół niej kilka „if” i komentarzy dla jasności i bezpieczeństwa (np. Jeśli pierwszy mecz nie pasuje, wyrzuć wyjątek lub ustaw wynik zerowy).
Nadal istnieją pewne możliwe problemy z przecinkami lub cudzysłowami i prawdopodobnie powinieneś rozpakować dane, a następnie usunąć je z cudzysłowu, ale przynajmniej traktuje dane jako dane, a nie jako kod.
W wersji preg_version najgorszym wynikiem będzie prawdopodobnie $ result = null, aw wersji eval najgorszy jest nieznany, ale przynajmniej awaria.
źródło
eval ocenia łańcuch jako kod, problem polega na tym, że jeśli łańcuch jest w jakikolwiek sposób „skażony”, może to narazić na ogromne zagrożenie bezpieczeństwa. Zwykle problem występuje w przypadku, gdy dane wejściowe użytkownika są oceniane w ciągu znaków, w wielu przypadkach użytkownik mógłby wprowadzić kod (na przykład php lub ssi), który jest następnie uruchamiany w ramach eval, działałby z takimi samymi uprawnieniami jak skrypt php i mógłby być wykorzystywane do uzyskiwania informacji / dostępu do Twojego serwera. Upewnienie się, że dane wejściowe użytkownika są odpowiednio wyczyszczone przed przekazaniem ich do eval, może być dość trudne. Są inne problemy ... niektóre z nich są dyskusyjne
źródło
PHP radzi, aby napisać kod w taki sposób, aby mógł być wykonywany przez call_user_func zamiast robić jawne ewaluacje.
źródło
Innym powodem
eval
jest to, że nie może być buforowany przez bufory kodu bajtowego PHP, takie jak eAccelertor lub ACP.źródło
To złe programowanie sprawia, że eval () jest złym, a nie funkcja. Czasami go używam, ponieważ nie mogę go obejść w programowaniu dynamicznym w wielu witrynach. Nie mogę przeprowadzić parsowania PHP w jednej witrynie, ponieważ nie otrzymam tego, co chcę. Po prostu otrzymam wynik! Cieszę się, że istnieje funkcja eval (), która znacznie ułatwia mi życie. Wprowadzane przez użytkownika? Hakerzy zaczepiają tylko źli programiści. O to się nie martwię.
źródło
Przewiduję, że wkrótce będziesz miał poważne problemy ...
Szczerze mówiąc, nie ma absolutnie żadnego pożytku z wygórowanej funkcji, takiej jak eval, w języku interpretowanym, takim jak PHP. Nigdy nie widziałem, aby eval wykonywał funkcje programu, których nie można byłoby wykonać innymi, bezpieczniejszymi sposobami ...
Z całego serca zgadzam się, że Eval jest źródłem wszelkiego zła dla wszystkich ludzi, którzy uważają, że pomocne będzie testowanie danych wejściowych użytkownika. Pomyśl dwa razy, dane wejściowe użytkownika mogą przybierać wiele różnych form, a hakerzy wykorzystują tę funkcję, na której Ci nie zależy. Moim zdaniem po prostu unikaj eval.
Widziałem przygotowane przykłady nadużywania funkcji eval, która przewyższała moją własną kreatywność. Z punktu widzenia bezpieczeństwa unikaj za wszelką cenę, a nawet posunąłbym się nawet do żądania, aby było to przynajmniej opcją w konfiguracji PHP, a nie „daną”.
źródło
eval
. I dlatego dla każdej funkcji X: X jest źródłem wszelkiego eval ... eee ... zła, więc lepiej całkowicie zrezygnować z programowania (wyciągając dywan spod tych głupich hakerów, wciąż ich przechytrzając).Oto rozwiązanie do uruchamiania kodu PHP pobranego z bazy danych bez użycia eval. Zezwala na wszystkie funkcje w zakresie i wyjątki:
$rowId=1; //database row id $code="echo 'hello'; echo '\nThis is a test\n'; echo date(\"Y-m-d\");"; //php code pulled from database $func="func{$rowId}"; file_put_contents('/tmp/tempFunction.php',"<?php\nfunction $func() {\n global \$rowId;\n$code\n}\n".chr(63).">"); include '/tmp/tempFunction.php'; call_user_func($func); unlink ('/tmp/tempFunction.php');
Zasadniczo tworzy unikalną funkcję z zawartym kodem w pliku tekstowym, dołącza plik, wywołuje funkcję, a po zakończeniu usuwa plik. Używam tego do codziennego pozyskiwania / synchronizacji bazy danych, gdzie każdy krok wymaga unikalnego kodu do obsługi. To rozwiązało wszystkie problemy, z którymi miałem do czynienia.
źródło
Kiedyś często używałem eval (), ale znalazłem większość przypadków, w których nie trzeba używać eval do robienia sztuczek. Cóż, masz call_user_func () i call_user_func_array () w PHP. Wystarczy statycznie i dynamicznie wywołać dowolną metodę.
Aby wykonać statyczne wywołanie, skonstruuj swoje wywołanie zwrotne jako tablicę („nazwa_klasy”, „nazwa_metody”) lub nawet jako prosty ciąg znaków, taki jak „nazwa_klasy :: nazwa_metody”. Aby wykonać wywołanie dynamiczne, użyj wywołania zwrotnego w stylu tablicy ($ object, 'method').
Jedynym sensownym zastosowaniem eval () jest napisanie własnego kompilatora. Zrobiłem jeden, ale eval jest nadal zły, ponieważ jest tak cholernie trudny do debugowania. Najgorsze jest to, że błąd krytyczny w ewaluowanym kodzie powoduje awarię kodu, który go wywołał. Użyłem rozszerzenia Parsekit PECL, aby przynajmniej sprawdzić składnię, ale nadal bez radości - spróbuj odwołać się do nieznanych klas i awarii całej aplikacji.
źródło
Poza względami bezpieczeństwa, eval () nie może zostać skompilowana, zoptymalizowana ani zbuforowana w kodzie operacyjnym, więc zawsze będzie wolniejsza - o wiele wolniejsza - niż normalny kod php. Dlatego używanie eval jest niewykonalne, chociaż to nie czyni go złym. (
goto
jest zły,eval
to tylko zła praktyka / śmierdzący kod / brzydki)źródło
eval
dostaje niższą ocenę zła niżgoto
? Czy to przeciwny dzień?goto
w 5.3.goto
-fobianów: są narzędzia i są rzemieślnicy, którzy ich używają (lub nie). To nigdy nie narzędzia sprawiają, że profesjonalista przy popełnianiu błędów wygląda jak idiota, ale raczej niemożność użycia odpowiednich narzędzi (właściwie). Ale to zawsze narzędzia winne ...Większość ludzi zwróci uwagę na fakt, że może to być niebezpieczne, gdy masz do czynienia z danymi wejściowymi użytkownika (z którymi można sobie poradzić).
Dla mnie najgorsze jest to, że ogranicza to łatwość utrzymania twojego kodu:
źródło