Kodėl „JavaScript“ eval funkcijos yra bloga idėja?

Eval funkcija yra galingas ir paprastas būdas dinamiškai generuoti kodą, taigi kokios yra išlygos?

480
17 сент. nustatė Brian Singh 17 sep. 2008-09-17 22:09 '08 10:09 val. 2008-09-17 22:09
@ 25 atsakymai
  • Netinkamas evalo naudojimas atveria injekcijos atakų kodą.

  • Derinimas gali būti sudėtingesnis (eilutės numeriai ir tt)

  • Eval'd kodas veikia lėčiau (nėra jokio būdo kompiluoti / talpinti eval'd kodą)

Redaguoti: kaip @Jeff Walden nurodo komentaruose, # 3 šiandien yra mažiau nei 2008 m. Tačiau, nors gali įvykti tam tikras kompiliuojamų scenarijų talpinimas, tai bus apribota tik scenarijus, kurie kartojami be jokių pakeitimų. Labiau tikėtinas scenarijus yra tai, kad vertinate scenarijus, kurie kiekvieną kartą buvo atlikti nedideliais pakeitimais, ir todėl jų negalima saugoti. Tarkime, kad SOME kodas eval'd veikia lėčiau.

357
17 сент. Atsakymą pateikė „ Prestaul “ 17 sep . 2008-09-17 22:17 '08 10:17 val. 2008-09-17 22:17

evalas ne visada yra blogas. Yra kartų, kai tai tobula.

Tačiau šiuo metu ir istoriškai plačiai naudojasi žmonės, kurie nežino, ką daro. Deja, tai taikoma žmonėms, kurie, deja, spausdina javascript vadovus, o kai kuriais atvejais tai gali turėti saugumo pasekmių - arba, dažniau, paprastų klaidų. Taigi, kuo daugiau galime padaryti, kad būtų pateiktas klausimas dėl eval, tuo geriau. Kiekvieną kartą, kai naudojate eval, jums reikia sanitarijos - patikrinkite, ką darote, nes, greičiausiai, galite tai padaryti geriau, saugiau ir švariau.

Tipiškas pavyzdys, kaip nustatyti elemento spalvą su identifikatoriumi, saugomu kintamajame „bulvė“:

 eval('document.' + potato + '.style.color = "red"'); 

Jei tokio kodo autoriai suprato, kaip veikia „JavaScript“ objektai, jie supranta, kad vietoj pažodinių taškų pavadinimų galite naudoti kvadratines skliaustelius, pašalinant būtinybę:

border=0
 document[potato].style.color = 'red'; 

... kuri yra daug lengviau skaitoma ir mažiau pavojinga.

(Tada kažkas, kas / tikrai / žinojo, ką jie darė, pasakytų:

 document.getElementById(potato).style.color = 'red'; 

kuri yra patikimesnė nei siaubingas senas triukas patekti į DOM elementus tiesiai iš dokumento objekto.)

336
17 сент. atsakymas duotas 17 sep . 2008-09-17 23:27 '08 at 23:27 pm 2008-09-17 23:27

Manau, nes ji gali atlikti bet kokią „JavaScript“ funkciją iš eilutės. Naudojant tai leidžia žmonėms lengvai įvesti nesąžiningą kodą į projektą.

35
17 сент. atsakymą pateikė kemiller2002 rugsėjo 17 d 2008-09-17 22:11 '08 10:11 pm 2008-09-17 22:11

Primename du taškus:

  • Saugumas (tačiau kol sukuriate eilutę, kurią reikia įvertinti, tai gali būti ne problema)

  • Veikimas: tol, kol nepavyksta paleisti kodo, jo negalima optimizuoti. (apie „JavaScript“ ir našumą, žinoma , Steve Yegge pristatymą )

25
17 сент. atsakymas pateikiamas xtofl 17 sep . 2008-09-17 22:20 '08 10:20 val. 2008-09-17 22:20

Naudotojo įvedimo į eval () perdavimas yra saugumo rizika, bet ir kiekvienas eval () skambutis sukuria naują „JavaScript“ vertėjo egzempliorių. Tai gali būti ištekliaus šaltinis.

20
17 сент. atsakymas suteiktas Andrew Hedges rugsėjo 17 d 2008-09-17 22:28 '08, 22:28 pm 2008-09-17 22:28

Paprastai tai yra problema tik tuo atveju, jei pereinate vartotojo įėjimus į eval.

17
17 сент. atsakymas, kurį pateikė Markas Biekas 17 sep . 2008-09-17 22:12 '08 10:12 val. 2008-09-17 22:12

Iš esmės yra daug sunkiau išlaikyti ir derinti. Tai tarsi goto . Jį galite naudoti, tačiau tai kelia sunkumų ir sunkumų žmonėms, kuriems gali tekti atlikti pakeitimus vėliau.

15
17 сент. Atsakymas duotas Brian 17 sep. 2008-09-17 22:12 '08 10:12 val. 2008-09-17 22:12

Atminkite, kad dažnai galite naudoti eval (), kad įvykdytumėte kodą tokiomis sąlygomis, kurios yra kitaip ribojamos - socialinės tinklaveikos svetainės, kurios blokuoja tam tikras „JavaScript“ funkcijas, kartais gali būti apgaulingos jas perkeliant į eval -

 eval('al' + 'er' + 't(\'' + 'hi there!' + '\')'); 

Todėl, jei norite paleisti „JavaScript“ kodą, kur jis gali būti neleidžiamas kitaip („ MySpace“ , aš žiūriu į tave ...), tada eval () gali būti naudingas triukas.

Tačiau dėl visų pirmiau minėtų priežasčių neturėtumėte to naudoti savo kodui, kur jūs turite visišką kontrolę - jums to nereikia, ir saugiau, prikabinus prie „sudėtingų„ JavaScript “hacks“.

13
18 сент. atsakymą pateikia matinis lohkamp 18 sep . 2008-09-18 00:23 '08 0:23 2008-09-18 00:23

Jei nesuteikiate dinaminio turinio () dinamiško turinio (per cgi arba įvestį), jis bus toks pat saugus ir patikimas kaip ir visi kiti jūsų puslapio „JavaScript“.

11
17 сент. Atsakymą pateikė Thevs 17 Sep. 2008-09-17 22:24 '08, 10:24 val. 2008-09-17 22:24

Kartu su likusiais atsakymais nemanau, kad eval pareiškimai gali turėti preliminarų minimalizavimą.

7
03 янв. Atsakymą pateikė Paul Mendoza 03 sausis 2012-01-03 06:52 '12 at 6:52 2012-01-03 06:52

Tai yra galimas saugumo pavojus, jis turi skirtingą vykdymo sritį ir yra gana neveiksmingas, nes sukuria visiškai naują scenarijų aplinką kodų vykdymui. Daugiau informacijos rasite čia: eval .

Jis yra labai naudingas, tačiau jis naudojamas su saikingai, gali pridėti daug gerų funkcijų.

6
17 сент. Atsakyti Tom 17 Sept. 2008-09-17 22:37 '08 at 10:37 pm 2008-09-17 22:37

Žinau, kad ši diskusija yra pasenusi, bet man tikrai patinka šis „ Google“ požiūris ir norėjau pasidalinti jausmu su kitais;)

Dar vienas dalykas yra tai, kad kuo daugiau jūs gaunate, tuo labiau stengiatės suprasti, ir, galiausiai, jūs netikite, kad kažkas yra gera ar bloga, nes kažkas taip sakė :) Tai labai įkvepiantis vaizdo įrašas , padėjęs man daugiau galvoti apie save :) GEROS PRAKTIKA yra gera, bet nenaudoja jų be reikalo :)

5
30 нояб. atsakymas pateiktas op1ekun lapkričio 30 d 2012-11-30 02:00 '12 2:00 2012-11-30 02:00

Jei nesate tikri, kad vertinamas kodas priklauso patikimam šaltiniui (paprastai jūsų pačių programai), tai yra teisingas būdas jūsų sistemai taikyti skriptų užpuolimą.

5
17 сент. John Topley atsakymas rugsėjo 17 d 2008-09-17 22:13 '08 10:13 val. 2008-09-17 22:13

Jei norite, kad vartotojas įvestų keletą loginių funkcijų ir įvertintų IR ir ARBA, „JavaScript eval“ funkcija yra tobula. Galiu priimti dvi eilutes ir eval(uate) string1 === string2 ir tt

4
09 марта '10 в 17:28 2010-03-09 17:28 atsakymas duotas Ian kovo 10 d. 10 val. 17:28 2010-03-09 17:28

Tai nebūtinai yra tokia bloga, jei žinote kontekstą, kuriame jį naudojate.

Jei jūsų programa naudoja eval() kad sukurtų objektą iš kai kurio JSON, kuris grįžo iš XMLHttpRequest į savo svetainę, sukurtą patikimo serverio pusės kodo, tai tikriausiai nėra problema.

Neteisingas kliento pusės „JavaScript“ kodas negali padaryti tiek daug. Jei dalykas, kurį darote eval() , kilęs iš protingo šaltinio, esate gerai.

4
17 сент. atsakymą pateikė MarkR 17 sep . 2008-09-17 23:10 '08 at 11:10 pm 2008-09-17 23:10

Tai labai sumažina pasitikėjimo saugumu lygį.

4
17 сент. Atsakymą davė David Plumpton rugsėjo 17 d. 2008-09-17 23:06 '08 at 23:06 pm 2008-09-17 23:06

Jei pastebėsite, kad jūsų kode naudokite eval (), atminkite, kad mantra "eval () yra blogis".

Ši funkcija užima savavališką eilutę ir ją atlieka kaip javascript kodą. Kai atitinkamas kodas yra iš anksto žinomas (nenustatytas vykdymo metu), nėra priežasties naudoti „Eval“ (). Jei kodas dinamiškai generuojamas vykdymo metu, tai dažnai yra geriausias būdas pasiekti tikslą be eval (). Pvz., Paprasčiausiai naudojant kvadratines skliaustelius, kad būtų galima pažymėti prieigą prie dinaminių savybių, geriau ir paprasčiau:

 // antipattern var property = "name"; alert(eval("obj." + property)); // preferred var property = "name"; alert(obj[property]); 

Naudojant eval() taip pat yra saugumo pasekmių, nes galite atlikti kodą (pvz., Iš tinklo), kuris buvo sugadintas. Tai yra bendras anti-modelis, kai sprendžiate JSON atsakymą iš Ajax užklausos. Tokiais atvejais geriau analizuoti JSON atsakymą naršyklėje sukurtais metodais, kad įsitikintumėte, jog jis yra saugus ir galiojantis. Naršyklėms, kurios iš pradžių nepalaiko JSON.parse() , galite naudoti JSON.org biblioteką.

Taip pat svarbu nepamiršti, kad styginių perdavimas į setInterval() , setTimeout() ir Function() konstruktorius dažniausiai yra panašus į eval() ir todėl reikia vengti.

Užkulisiuose „JavaScript“ vis dar turi įvertinti ir vykdyti eilutę, kurią perduodate kaip programavimo kodą:

 // antipatterns setTimeout("myFunc()", 1000); setTimeout("myFunc(1, 2, 3)", 1000); // preferred setTimeout(myFunc, 1000); setTimeout(function () { myFunc(1, 2, 3); }, 1000); 

Naujo funkcijų () konstruktoriaus naudojimas yra panašus į eval () ir turėtų būti vertinamas atsargiai. Tai gali būti galingas dizainas, tačiau dažnai naudojamas neteisingai. Jei absoliučiai naudojate eval() , galite naudoti naują funkciją ().

Yra mažas potencialas, nes kodas, įvertintas naujoje funkcijoje (), bus vykdomas vietinės funkcijos apimtyje, todėl bet kokie kintamieji, apibrėžti vertintame kode su var, nebus automatiškai automatiškai kintami.

Kitas būdas užkirsti kelią automatiniams pasauliniams kintamiesiems yra eval() skambutį į tiesioginę funkciją.

3
08 мая '17 в 17:06 2017-05-08 17:06 Atsakymas duotas 12345678 08 Geg '17, 17:06 2017-05-08 17:06

eval () yra labai efektyvus ir gali būti naudojamas JS pareiškimui atlikti arba išraiška. Tačiau kyla klausimas, kaip naudoti eval (), bet leidžia jums tiesiog pasakyti, kaip žalinga pusė veikia eilutę, kurioje veikia eval (). Pabaigoje paleisite kenkėjišką kodą. Su galia yra didelė atsakomybė. Taigi naudokite jį išmintingai. Tai nėra susijusi su eval () funkcija, tačiau šiame straipsnyje pateikiama gana gera informacija: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Jei ieškote eval () pagrindų, žiūrėkite čia: https: //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

2
25 окт. atsakymas pateikiamas genijus 25 okt. 2014-10-25 18:17 '14, 18:17 pm 2014-10-25 18:17

Tai gali tapti problemiškesnė, nes naujos kartos naršyklės ateina su tam tikru „JavaScript“ kompiliatoriaus skoniu. Įvertinimo kodas gali neveikti taip, kaip ir kiti jūsų naujos naršyklės javascript. Kažkas turi atlikti profiliavimą.

2
17 сент. atsakymas suteiktas 17 brolių . 2008-09-17 22:20 '08 10:20 val. 2008-09-17 22:20

Be galimų saugumo problemų, jei vykdote vartotojo atsiųstą kodą, dažniausiai yra geresnis būdas, kai nereikia pakartotinai koduoti kodo kiekvieną kartą, kai jis vykdomas. Anoniminės funkcijos ar objektų savybės gali pakeisti daugumą evalinių programų ir yra daug saugesnės ir greitesnės.

2
17 сент. Matthew Crumley atsakymas rugsėjo 17 d 2008-09-17 22:14 '08 10:14 val. 2008-09-17 22:14

Tai vienas iš gerų straipsnių apie eval ir kaip tai nėra blogis: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Aš nesakau, kad turėtumėte pabėgti ir pradėti naudoti eval () visur. Iš tiesų eval () yra labai nedaug. Yra tam tikra problema dėl kodo aiškumo, derinimo ir, žinoma, veiklos, kurios negalima ignoruoti. Bet jūs neturėtumėte bijoti naudoti, kai turite atvejį, kai eval () yra prasmingas. Stenkitės nenaudoti jos pirmiausia, bet neleiskite niekam paniekinti, jei manote, kad jūsų kodas yra trapesnis ar mažiau saugus, kai eval () yra tinkamai naudojamas.

2
08 окт. atsakymas duotas Amr Elgarhy 08 spalis 2014-10-08 12:04 '14, 12:04 2014-10-08 12:04

Sakyčiau, kad nesvarbu, ar naudojate eval() javascript, kuris veikia naršyklėse. * (įspėjimas)

Visose šiuolaikinėse naršyklėse yra kūrėjo konsolė, kurioje galite savavališkai vykdyti savavališką javascript, o bet kuris pusiau protingas kūrėjas gali žiūrėti į jūsų JS šaltinį ir įdėti visus reikiamus bitus į dev konsolę, kad tai padarytų.

* Kol jūsų serverio galutiniai taškai teisingai patvirtina ir išvalo naudotojo pateiktas vertes, tai neturėtų būti svarbu, kas bus apdorojama ir eval'd jūsų „JavaScript“ kliento pusėje.

Jei paklausiate, ar tai tinka eval() naudojimui PHP, atsakymas yra NE , jei nesate baltas sąrašas , negalite priskirti vertybių, kurios gali būti perduotos jūsų evaliui.

1
01 марта '18 в 14:30 2018-03-01 14:30 atsakymą pateikė Adam Copley kovo 1, 18, 14:30, 2018-03-01 14:30

Tai ne visada bloga idėja. Paimkite, pavyzdžiui, kodų generavimą. Neseniai parašiau biblioteką, pavadintą „ Hyperbars“, kuri užpildo atotrūkį tarp virtualaus domeno ir vairo . Jis tai daro analizuodamas vairavimo modelį ir konvertuodamas jį į hipertekstą , kurį vėliau naudoja virtualus domenas . Hipersaitas generuojamas kaip eilutė ir prieš ją grąžinant, eval() , norėdami jį paversti vykdomuoju kodu. Šioje konkrečioje situacijoje aš eval() tiksliai priešingą blogį.

Daugiausia iš

 <div> {{#each names}} <span>{{this}}</span> {{/each}} </div> 

Dėl to

 (function (state) { var Runtime = Hyperbars.Runtime; var context = state; return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) { return [h('span', {}, [options['@index'], context])] })]) }.bind({})) 

„Performance eval() nėra problema šioje situacijoje, nes jums reikia tik interpretuoti sugeneruotą eilutę vieną kartą ir tada pakartotinai panaudoti atliktą produkciją kelis kartus.

Jūs galite pamatyti, kaip kodų generavimas buvo pasiektas, jei čia smalsu.

1
28 нояб. atsakymas pateikiamas Wikened 28 lapkričio. 2016-11-28 14:04 '16 at 14:04 2016-11-28 14:04

„JavaScript“ variklyje yra keletas našumo optimizavimo funkcijų, kurias jis atlieka kompiliavimo metu. Kai kurie iš jų virsta tuo, kad jie iš esmės gali statiškai analizuoti kodą, nes jis yra leksikuoti, ir iš anksto nustatyti, kur yra visos kintamųjų ir funkcijų deklaracijos, todėl reikia mažiau pastangų identifikatoriams pašalinti vykdymo metu.

Bet jei variklis suranda kodą eval (..), jis iš esmės turi manyti, kad visas jo suvokimas apie identifikatoriaus vietą gali būti negaliojantis, nes jis negali tiksliai žinoti, kokį kodą galite perduoti eval (.) Lexing metu. .) keisti objekto leksinę sritį ar turinį, kurį galite pereiti, kad sukurtumėte naują leksinę sritį, į kurią reikia susipažinti.

Kitaip tariant, pesimistine prasme dauguma optimizacijų, kurių jis būtų padaręs, yra beprasmiški, jei yra eval (..), todėl jis paprasčiausiai neveikia optimizavimo.

Tai paaiškina viską.

Nuoroda:

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20>

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20>

30 янв. atsakymas pateikiamas hkasera 30 jan. 2016-01-30 09:34 '16 at 9:34 2016-01-30 09:34

Nebandysiu paneigti to, kas buvo pasakyta iki šiol, bet siūlysiu naudoti šį eval (), kuris (kiek aš žinau) negali būti atliekamas jokiu kitu būdu. Turbūt yra ir kitų būdų koduoti šį būdą ir tikriausiai būdus, kaip jį optimizuoti, tačiau tai daroma siekiant parodyti eval, kuris iš tikrųjų neturi kitų alternatyvų, naudojimo. Tai yra: dinamiški (arba tiksliau) užprogramuoti objektų pavadinimai (priešingai nei vertybės).

 //Place this in a common/global JS lib: var NS = function(namespace){ var namespaceParts = String(namespace).split("."); var namespaceToTest = ""; for(var i = 0; i < namespaceParts.length; i++){ if(i === 0){ namespaceToTest = namespaceParts[i]; } else{ namespaceToTest = namespaceToTest + "." + namespaceParts[i]; } if(eval('typeof ' + namespaceToTest) === "undefined"){ eval(namespaceToTest + ' = {}'); } } return eval(namespace); } //Then, use this in your class definition libs: NS('Root.Namespace').Class = function(settings){ //Class constructor code here } //some generic method: Root.Namespace.Class.prototype.Method = function(args){ //Code goes here //this.MyOtherMethod("foo")); // => "foo" return true; } //Then, in your applications, use this to instantiate an instance of your class: var anInstanceOfClass = new Root.Namespace.Class(settings); 

Redaguoti: beje, aš nerekomenduosiu (dėl visų pirmiau minėtų saugumo priežasčių), kad savo objektų pavadinimus naudosite naudotojo įvestyje. Negaliu įsivaizduoti, kokių gerų priežasčių norėtumėte tai padaryti. Tačiau aš maniau, kad norėčiau pasakyti, kad tai nėra gera idėja :)

0
12 февр. Carnix atsakymą pateikė vasario 12 d. 2015-02-12 21:45 '15 - 21:45 2015-02-12 21:45

Kiti klausimai apie „ ar užduoti klausimą