JSON.parse kontra eval ()

94

My Spider Sense ostrzega mnie, że używanie eval()do analizowania przychodzącego JSON jest złym pomysłem. Zastanawiam się tylko, czy JSON.parse()- który, jak zakładam, jest częścią JavaScript, a nie funkcją specyficzną dla przeglądarki - jest bezpieczniejszy.

Kevin Major
źródło
Pod względem wydajności JSON.parsejest szybszy niż eval, przynajmniej w V8 (silnik JS Chromium). Źródło .
Paweł

Odpowiedzi:

110

Jesteś bardziej podatny na ataki, jeśli używasz eval: JSON jest podzbiorem Javascript, a json.parse po prostu analizuje JSON eval, pozostawiając otwarte drzwi dla wszystkich wyrażeń JS.

jldupont
źródło
„Jesteś bardziej podatny na ataki” , zupełnie się z tym nie zgadzam!
Hydroper
5
Przepraszam Matheusie, muszę się zgodzić. Problem polega na tym, że używasz eval () do interpretacji "danych wejściowych użytkownika" - które jest DOWOLNYM źródłem zewnętrznym od twojego JavaScript (włączając wartości zwrócone z serwletów lub innych usług sieciowych, które wywołałeś). Nie możesz zagwarantować, że użytkownicy nie wprowadzili złośliwego kodu JavaScript ani bezpośrednio do aplikacji klienckiej, ani pośrednio z powodu niezweryfikowanych danych przechowywanych w bazie danych serwera, a następnie przekazanych do Twojego programu za pomocą wywołania w stylu AJAX. Nadal może być konieczne sprawdzenie poprawności poszczególnych pól, aby uniknąć ataków „zdezorientowanych zastępców”, ale użycie JSON.parse jest dobrym pierwszym krokiem.
JackLThornton
1
@Hydro Krótki dowód słuszności koncepcji: spróbuj eval('alert(1)');.
Valerio Bozz,
37

Wszystkie JSON.parseimplementacje najprawdopodobniej używająeval()

JSON.parseopiera się na rozwiązaniu Douglasa Crockforda , które jest używane eval()na linii 497 .

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

j = eval('(' + text + ')');

Zaletą JSON.parsejest to, że sprawdza, czy argumentem jest poprawna składnia JSON.

kujon
źródło
56
tak, z wyjątkiem tego, że wiersz tuż przed tym potwierdza, że ​​jest to bezpieczny i poprawny ciąg.
nickf
6
Testowałem JSON.parse()w Firefoksie 28 i Chromium 33 na moim systemie Linux Mint. Był 2x szybszy niż eval()w Firefoksie i 4x szybszy w Chromium. Nie jestem pewien, jaki kod źródłowy publikujesz, ale w moich przeglądarkach to nie to samo.
jbo5112
„Zaleta” @plodder prawdopodobnie nie jest tania w przeprowadzaniu takiej weryfikacji.
mmm
2
Nowoczesne przeglądarki zapewniają natywną JSON.parse()implementację, która jest bezpieczniejsza i szybsza niż eval()parsery oparte na technologii.
Mohammad Alhashash
15

Nie wszystkie przeglądarki mają natywną obsługę formatu JSON, więc będą chwile, w których trzeba będzie użyć eval() ciągu JSON. Użyj parsera JSON ze strony http://json.org, ponieważ obsługuje on wszystko o wiele łatwiej.

Eval() jest złem, ale w stosunku do niektórych przeglądarek jest złem koniecznym, ale jeśli możesz tego uniknąć, zrób to !!!!!

AutomatedTester
źródło
12

Istnieje różnica między tym, co zaakceptuje JSON.parse () i eval (). Wypróbuj eval na tym:

var x = "{\" nazwa_koszyka_zakupowego \ ": \" koszyk_zakupowy: 2000 \ "}"

eval(x)         //won't work
JSON.parse(x)   //does work

Zobacz ten przykład .

Jeff Lowery
źródło
1
eval nie działa, ponieważ analizuje ciągi znaków jako instrukcje kodu i dlatego traktuje „{...}” jako wyrażenie kodu zamiast wyrażenia deklaracji wartości. jeśli usuniesz niejednoznaczność (na przykład „[{....}]”), nie ma wątpliwości co do natury wyrażenia, a eval utworzy tablicę zawierającą przeanalizowany objet
Charles HETIER
1
Tak. Tradycyjnie x byłby zawijany w nawiasy: eval ("(" + x + ")"). To, co powiedziałem, jest nadal aktualne: nie ma dwuznaczności podczas używania JSON.parse ().
Jeff Lowery,
9

Jeśli przeanalizujesz JSON z eval, pozwalasz, aby przetwarzany ciąg zawierał absolutnie wszystko, więc zamiast być tylko zbiorem danych, możesz znaleźć wykonywanie wywołań funkcji lub cokolwiek innego.

Ponadto JSON parseakceptuje dodatkowy parametr, reviver, który pozwala określić, jak postępować z określonymi wartościami, takimi jak daty (więcej informacji i przykład w dokumentacji wbudowanej tutaj )

David Hedlund
źródło
4

JSON to tylko podzbiór JavaScript. Ale evalocenia pełny język JavaScript, a nie tylko podzbiór, którym jest JSON.

Gumbo
źródło
Racja, wiem o tym. Czy sugerujesz, że JSON.parse () WYŁĄCZNIE ocenia JSON i kończy się niepowodzeniem na wszystkich innych przychodzących danych? Czy jest to po prostu opakowanie dla: var myObject = eval ('(' + responseText + ')'); ??
Kevin Major
6
@Kevin Major: Tak, natywnie zaimplementowany JSON.parse(bezpośrednio zaimplementowany w silniku JavaScript) analizuje tylko JSON. Ale inne implementacje nienatywne używają pewnych sprawdzeń poprawności, a następnie używają ich evalze względu na wydajność.
Gumbo