เหตุใดการใช้ฟังก์ชัน JavaScript eval จึงเป็นความคิดที่ไม่ดี


534

ฟังก์ชั่น eval เป็นวิธีที่ทรงพลังและง่ายต่อการสร้างรหัสแบบไดนามิกดังนั้นคำเตือนคืออะไร



5
ดังที่อธิบายไว้ในmoduscreate.com/javascript-performance-tips-tricks - (ฟังก์ชั่นใหม่ (str)) () นั้นมีประสิทธิภาพมากกว่า eval (str) เพียง 2 เซ็นต์ของฉัน :)
Grgur

3
เห็นได้ชัดว่า fcuntion ใหม่ (a) นั้น 67% ช้ากว่า eval (a) บนโครเมี่ยม
นอนหลับ

สำหรับฉันฟังก์ชั่นใหม่ (a) คือ 80% ช้าลงล่าสุด chrome บน osx
john Smith

3
ฉันได้เพิ่มฟังก์ชั่นแบบคงที่เพียงเพื่อเปรียบเทียบประสิทธิภาพ jsperf.com/eval-vs-new-function/2
Nepoxx

คำตอบ:


386
  1. การใช้eval ที่ไม่เหมาะสมจะเปิดรหัสของคุณสำหรับการโจมตีฉีด

  2. การดีบักอาจท้าทายกว่า (ไม่มีหมายเลขบรรทัด ฯลฯ )

  3. โค้ด eval'd รันช้าลง (ไม่มีโอกาสรวบรวม / แคชโค้ด eval'd)

แก้ไข: เนื่องจาก @Jeff Walden ชี้ให้เห็นในความคิดเห็น # 3 ในปัจจุบันมีความเป็นจริงน้อยกว่าในปี 2008 อย่างไรก็ตามในขณะที่การแคชของสคริปต์ที่รวบรวมอาจเกิดขึ้นสิ่งนี้จะถูก จำกัด เฉพาะสคริปต์ที่ไม่ถูกแก้ไขซ้ำ สถานการณ์ที่เป็นไปได้มากกว่าคือคุณกำลังตรวจสอบสคริปต์ที่ผ่านการแก้ไขเล็กน้อยในแต่ละครั้งและไม่สามารถแคชได้ สมมุติว่าบางรหัส eval'd รันช้ากว่า


2
@JeffWalden ความคิดเห็นที่ดี ฉันได้อัปเดตโพสต์ของฉันแล้วแม้ว่าฉันจะทราบว่าเป็นเวลาหนึ่งปีแล้วที่คุณโพสต์ Xnzo72 หากคุณมีคุณสมบัติความคิดเห็นของคุณบ้าง (เหมือนที่เจฟฟ์ทำ) จากนั้นฉันอาจจะเห็นด้วยกับคุณ Jeff ชี้ให้เห็นถึงคีย์: "eval ของสตริงเดียวกันหลาย ๆ ครั้งสามารถหลีกเลี่ยงค่าใช้จ่ายในการแยกวิเคราะห์" อย่างที่คุณเป็นผิด # 3 ถือเป็นจริงสำหรับหลาย ๆ สถานการณ์
Prestaul

7
@Prestaul: เนื่องจากผู้โจมตีควรใช้เครื่องมือสำหรับนักพัฒนาเพื่อเปลี่ยนจาวาสคริปต์ในไคลเอนต์ทำไมคุณถึงบอกว่า Eval () เปิดโค้ดของคุณเพื่อโจมตีการฉีด? ยังไม่ได้เปิดใช่ไหม (ฉันกำลังพูดถึงลูกค้าจาวาสคริปต์แน่นอน)
Eduardo Molteni

60
@EduardoMolteni เราไม่สนใจ (และไม่สามารถป้องกันได้) ผู้ใช้เรียกใช้ js ในเบราว์เซอร์ของตนเอง การโจมตีที่เราพยายามหลีกเลี่ยงคือเมื่อค่าที่ผู้ใช้ให้ได้รับการบันทึกจากนั้นวางใน javascript และ eval'd ในภายหลัง ตัวอย่างเช่นฉันอาจตั้งชื่อผู้ใช้ของฉันเป็น: badHackerGuy'); doMaliciousThings();และถ้าคุณนำชื่อผู้ใช้ของฉันเชื่อมต่อลงในสคริปต์บางส่วนและประเมินผลในเบราว์เซอร์ของผู้อื่นฉันสามารถเรียกใช้จาวาสคริปต์ที่ฉันต้องการบนเครื่องของพวกเขา โพสต์ข้อมูลของพวกเขาไปยังเซิร์ฟเวอร์ของฉัน ฯลฯ )
Prestaul

3
โดยทั่วไปแล้ว # 1 นั้นเป็นจริงสำหรับค่อนข้างมากถ้าไม่เรียกฟังก์ชั่นส่วนใหญ่ eval () ไม่ควรแยกออกและหลีกเลี่ยงโดยโปรแกรมเมอร์ที่มีประสบการณ์เพียงเพราะโปรแกรมเมอร์ที่ไม่มีประสบการณ์ใช้ในทางที่ผิด อย่างไรก็ตามโปรแกรมเมอร์ที่มีประสบการณ์มักจะมีสถาปัตยกรรมที่ดีกว่าในรหัสของพวกเขาและ eval () จะไม่ค่อยถูกต้องการหรือแม้แต่คิดเกี่ยวกับเนื่องจากสถาปัตยกรรมที่ดีกว่านี้
frodeborli

4
@TamilVendhan แน่ใจว่าคุณสามารถใส่เบรกพอยต์ คุณสามารถเข้าถึงไฟล์เสมือนที่สร้างขึ้นโดย Chrome สำหรับโค้ดที่เข้ารหัสได้โดยเพิ่มdebugger;คำสั่งลงในซอร์สโค้ดของคุณ นี่จะหยุดการทำงานของโปรแกรมของคุณในบรรทัดนั้น หลังจากนั้นคุณสามารถเพิ่มจุดพักการดีบักได้เหมือนกับไฟล์ JS อื่น
ซิด

346

eval ไม่ใช่ความชั่วร้ายเสมอไป มีหลายครั้งที่มันเหมาะสมอย่างสมบูรณ์แบบ

อย่างไรก็ตามการใช้ eval ในปัจจุบันและในอดีตมักใช้กันอย่างแพร่หลายโดยผู้ที่ไม่ทราบว่ากำลังทำอะไรอยู่ ซึ่งรวมถึงคนที่เขียนบทช่วยสอน JavaScript โชคไม่ดีและในบางกรณีสิ่งนี้อาจส่งผลต่อความปลอดภัยอย่างแน่นอน - หรือบ่อยครั้งกว่านั้นคือข้อบกพร่องอย่างง่าย ดังนั้นยิ่งเราสามารถทำเครื่องหมายคำถามเพื่อหลีกเลี่ยง eval ยิ่งดี เมื่อใดก็ตามที่คุณใช้ eval คุณต้องมีสติตรวจสอบสิ่งที่คุณทำเพราะโอกาสที่คุณจะทำได้ดีกว่าปลอดภัยกว่าและสะอาดกว่า

เพื่อให้เป็นตัวอย่างที่ธรรมดาเกินไปให้ตั้งค่าสีขององค์ประกอบที่มี id ที่เก็บอยู่ในตัวแปร 'potato':

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

หากผู้เขียนรหัสประเภทข้างต้นมีเงื่อนงำเกี่ยวกับพื้นฐานของวิธีการทำงานของวัตถุ JavaScript พวกเขาจะรู้ว่าสามารถใช้วงเล็บเหลี่ยมแทนตัวอักษรชื่อจริงและตัดความต้องการ eval:

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

... ซึ่งง่ายต่อการอ่านและค่าบั๊กที่น้อยกว่า

(แต่แล้วบางคนที่ / จริง / รู้ว่าสิ่งที่พวกเขากำลังทำจะพูดว่า:

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

ซึ่งเชื่อถือได้มากกว่าเคล็ดลับเก่า ๆ ที่หลบการเข้าถึงองค์ประกอบ DOM ตรงจากวัตถุเอกสาร)


82
อืมฉันว่าฉันโชคดีเมื่อฉันได้เรียนรู้ JavaScript ครั้งแรก ฉันใช้ "document.getElementById" เพื่อเข้าถึง DOM เสมอ แดกดันฉันไม่เพียง แต่ในเวลานั้นเพราะผมไม่ได้มีเงื่อนงำว่าวัตถุทำงานใน JavaScript ;-)
ไมค์ Spross

5
ตกลง. บางครั้ง eval ก็โอเคเช่นสำหรับการตอบสนองของ JSON จากเว็บเซอร์
schoetbi

40
@schoetbi: คุณไม่ควรใช้JSON.parse()แทนeval()JSON เหรอ?
nyuszika7h

4
@bobince code.google.com/p/json-sans-evalใช้ได้กับทุกเบราว์เซอร์ดังนั้นgithub.com/douglascrockford/JSON-jsจึงไม่ทำงาน json2.js ของ Doug Crockford ใช้ eval ภายใน แต่ใช้เช็ค นอกจากนี้ยังรองรับการใช้งานกับเบราว์เซอร์ในตัวสำหรับ JSON
Martijn

8
@bince มีบางสิ่งที่เรียกว่าการตรวจสอบคุณสมบัติและ polyfills เพื่อจัดการไลบรารี JSON ที่หายไปและสิ่งอื่น ๆ (ดูmodernizr.com )
MauganRa

37

ฉันเชื่อว่าเป็นเพราะสามารถเรียกใช้ฟังก์ชัน JavaScript ใด ๆ จากสตริง การใช้มันทำให้ผู้คนสามารถฉีดรหัสโกงเข้าไปในแอปพลิเคชันได้ง่ายขึ้น


5
ทางเลือกคืออะไร?
moderns

5
ทางเลือกอื่นจริงๆเพียงแค่เขียนโค้ดที่ไม่ต้องการมัน Crockford พูดถึงเรื่องนี้นานมากและถ้าคุณต้องการใช้มันเขาบอกได้เลยว่ามันเป็นข้อบกพร่องในการออกแบบโปรแกรมและจำเป็นต้องนำกลับมาใช้ใหม่ ที่จริงแล้วฉันเห็นด้วยกับเขาด้วย JS สำหรับทุกข้อบกพร่องนั้นมีความยืดหยุ่นและช่วยให้มีพื้นที่มากมายในการทำให้มีความยืดหยุ่น
kemiller2002

3
ไม่เป็นความจริงเฟรมเวิร์กส่วนใหญ่มีวิธีการแยกวิเคราะห์ JSON และถ้าคุณไม่ได้ใช้เฟรมเวิร์กคุณสามารถใช้ JSON.parse () เบราว์เซอร์ส่วนใหญ่รองรับและถ้าคุณใช้งานได้จริงคุณสามารถเขียนโปรแกรมแยกวิเคราะห์สำหรับ JSON ได้ง่ายๆ
kemiller2002

6
ฉันไม่ได้ซื้ออาร์กิวเมนต์นี้เพราะมันง่ายต่อการฉีดรหัสโกงลงในแอปพลิเคชัน Javascript เรามีเบราว์เซอร์คอนโซลส่วนขยายสคริปต์ ฯลฯ ... ทุกชิ้นส่วนของรหัสที่ส่งไปยังลูกค้านั้นเป็นตัวเลือกสำหรับลูกค้าที่จะดำเนินการ
2867288

6
ประเด็นคือมันง่ายกว่าที่ฉันจะฉีดรหัสลงในเบราว์เซอร์ของคุณ สมมติว่าคุณกำลังใช้ eval ในสตริงการสืบค้น หากฉันหลอกให้คุณคลิกลิงก์ที่ไปยังไซต์นั้นโดยแนบสตริงการสืบค้นของฉันตอนนี้ฉันเรียกใช้งานโค้ดของฉันบนเครื่องของคุณโดยได้รับอนุญาตอย่างสมบูรณ์จากเบราว์เซอร์ ฉันต้องการบันทึกทุกสิ่งที่คุณพิมพ์บนเว็บไซต์นั้นและส่งมาให้ฉัน เสร็จแล้วและไม่มีทางที่จะหยุดฉันได้เพราะเมื่อ eval ดำเนินการเบราว์เซอร์จะให้สิทธิ์สูงสุด
kemiller2002

27

จุดสองจุดอยู่ในใจ:

  1. ความปลอดภัย (แต่ตราบใดที่คุณสร้างสตริงเพื่อประเมินด้วยตัวคุณเองนี่อาจจะไม่ใช่ปัญหา)

  2. ประสิทธิภาพการทำงาน: จนกว่าจะไม่ทราบรหัสที่จะดำเนินการจะไม่สามารถปรับให้เหมาะสมได้ (เกี่ยวกับจาวาสคริปต์และประสิทธิภาพการทำงานนำเสนออย่างแน่นอนของSteve Yegge )


9
เหตุใดการรักษาความปลอดภัยจึงเป็นปัญหาหากลูกค้าสามารถทำอะไรกับรหัสของเราได้ทุกเมื่อที่ต้องการ ลิงเกรส ?
Paul Brewczynski

2
@PaulBrewczynski ปัญหาด้านความปลอดภัยปรากฏขึ้นเมื่อผู้ใช้ A บันทึกส่วนหนึ่งของรหัสเพื่อให้เป็นevaluated จากนั้นรหัสชิ้นส่วนเล็ก ๆ นั้นจะทำงานบนเบราว์เซอร์ B ของผู้ใช้
Felipe Pereira

21

การส่งอินพุตของผู้ใช้ไปยัง eval () เป็นความเสี่ยงด้านความปลอดภัย แต่การร้องขอ eval () แต่ละครั้งจะสร้างอินสแตนซ์ใหม่ของล่าม JavaScript นี่อาจเป็นหมูทรัพยากร


27
ในช่วง 3 ปีที่ผ่านมาตั้งแต่ฉันตอบคำถามนี้ความเข้าใจของฉันเกี่ยวกับสิ่งที่เกิดขึ้นมีมากขึ้นเช่นกัน สิ่งที่เกิดขึ้นจริงคือบริบทการดำเนินการใหม่ถูกสร้างขึ้น ดูdmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts
Andrew Hedges

20

โดยทั่วไปเป็นเพียงปัญหาถ้าคุณผ่านการป้อนข้อมูลของผู้ใช้ที่ประเมินแล้ว


16

ส่วนใหญ่มันยากที่จะรักษาและแก้ไขปัญหา gotoมันเหมือน คุณสามารถใช้มันได้ แต่มันทำให้การค้นหาปัญหาและคนที่อาจจำเป็นต้องทำการเปลี่ยนแปลงนั้นยากขึ้นในภายหลัง


Eval สามารถใช้แทนฟีเจอร์การเขียนโปรแกรม metaprogramming ที่ขาดหายไปเช่นเทมเพลต ฉันชอบเครื่องกำเนิดไฟฟ้าขนาดกะทัดรัดมากกว่ารายการฟังก์ชั่นที่ไม่มีที่สิ้นสุดในฟังก์ชั่น
อ่อนไหวต่อ

ตราบใดที่สตริงไม่ได้มาจากผู้ใช้หรือถูก จำกัด ไว้ที่เบราว์เซอร์ที่คุณสามารถทำได้ จาวาสคริปต์มีพลัง metaprogramming จำนวนมากที่ใช้สิ่งต่าง ๆ เช่นการเปลี่ยนต้นแบบ, obj [สมาชิก], พร็อกซี, json.parse, หน้าต่าง, ฟังก์ชันมัณฑนากร (adverbs) โดยที่ newf = decorator (oldf), ฟังก์ชันลำดับที่สูงขึ้นเช่น Array.prototype.map (f) , การส่งผ่านข้อโต้แย้งไปยังฟังก์ชั่นอื่น ๆ , การโต้แย้งคำหลักผ่าน {} คุณช่วยเล่าให้ฉันฟังเกี่ยวกับกรณีการใช้งานที่คุณไม่สามารถทำสิ่งเหล่านี้ได้แทนที่จะเป็นแบบประเมิน?
aoeu256

13

สิ่งหนึ่งที่ต้องจำไว้คือคุณสามารถใช้ eval () เพื่อเรียกใช้โค้ดในสภาพแวดล้อมที่ จำกัด เป็นอย่างอื่น - เว็บไซต์เครือข่ายสังคมที่บล็อกฟังก์ชัน JavaScript บางครั้งอาจถูกหลอกได้ด้วยการทำลายพวกเขาในบล็อก eval -

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

ดังนั้นหากคุณต้องการเรียกใช้รหัส JavaScript ที่อาจไม่ได้รับอนุญาต ( Myspaceฉันกำลังมองคุณ ... ) ดังนั้น eval () อาจเป็นกลอุบายที่มีประโยชน์

อย่างไรก็ตามด้วยเหตุผลทั้งหมดที่กล่าวมาข้างต้นคุณไม่ควรใช้มันสำหรับรหัสของคุณเองซึ่งคุณสามารถควบคุมได้อย่างสมบูรณ์ - มันไม่จำเป็นเลยและดีกว่าที่จะลดชั้นวางของ 'แฮ็ค JavaScript แฮ็ก'


1
เพียงอัปเดตโค้ดด้านบน .. - คุณมี! - จำเป็นต้องอยู่ในเครื่องหมายคำพูดเนื่องจากเป็นสตริง eval ('al' + 'er' + 't (' + '"สวัสดีนั่น!"' + ')');
Mahesh

2
[]["con"+"struc"+"tor"]["con"+"struc"+"tor"]('al' + 'er' + 't(\'' + 'hi there!' + '\')')()
Konrad Borowski

4
ใช่มีเว็บไซต์เครือข่ายสังคมที่ จำกัด การแจ้งเตือน () แต่อนุญาต eval () ?!
joshden

12

ถ้าคุณไม่ให้ eval () เนื้อหาแบบไดนามิก (ผ่าน cgi หรืออินพุต) มันจะปลอดภัยและมั่นคงเหมือน JavaScript อื่น ๆ ทั้งหมดในหน้าของคุณ


แม้ว่าสิ่งนี้จะเป็นจริง - หากเนื้อหาของคุณไม่ได้เป็นแบบไดนามิกเหตุผลอะไรที่ทำให้ใช้ Eval ได้ คุณสามารถใส่รหัสในฟังก์ชั่นแล้วเรียกมันแทน!
Periata Breatta

ตัวอย่างเช่น - เพื่อวิเคราะห์ค่าที่ส่งคืน (เช่น JSON, สตริงที่กำหนดโดยเซิร์ฟเวอร์ ฯลฯ ) ที่มาจากการโทร Ajax
Thevs

2
อ้อเข้าใจแล้ว. ฉันจะเรียกแบบไดนามิกเหล่านั้นเพราะลูกค้าไม่ทราบล่วงหน้าว่าพวกเขาคืออะไร แต่ฉันเห็นสิ่งที่คุณหมายถึงตอนนี้
Periata Breatta

7

นอกเหนือจากคำตอบที่เหลือฉันไม่คิดว่าข้อความที่เป็นหลักฐานจะมีการย่อขนาดเล็กสุดได้


6

มีความเสี่ยงด้านความปลอดภัยที่เป็นไปได้มีขอบเขตการดำเนินการที่แตกต่างกันและค่อนข้างไม่มีประสิทธิภาพเนื่องจากจะสร้างสภาพแวดล้อมการเขียนสคริปต์ใหม่ทั้งหมดสำหรับการดำเนินการของรหัส ดูที่นี่สำหรับข้อมูลเพิ่มเติมบางส่วน: EVAL

มันค่อนข้างมีประโยชน์แม้ว่าและใช้กับการกลั่นกรองสามารถเพิ่มฟังก์ชันการทำงานที่ดีมากมาย


5

ถ้าคุณไม่แน่ใจ 100% ว่าโค้ดที่ถูกประเมินนั้นมาจากแหล่งที่เชื่อถือได้ (โดยปกติจะเป็นแอปพลิเคชันของคุณเอง) จากนั้นก็เป็นวิธีที่แน่นอนในการเปิดเผยระบบของคุณไปสู่การโจมตีสคริปต์ข้ามไซต์


1
เฉพาะในกรณีที่การรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์ของคุณแย่ การรักษาความปลอดภัยฝั่งไคลเอ็นต์นั้นไร้สาระตรง
doubleOrt

5

ฉันรู้ว่าการสนทนานี้เก่า แต่ฉันชอบวิธีนี้โดย Google และต้องการแบ่งปันความรู้สึกนั้นกับผู้อื่น;)

อีกอย่างคือดีกว่าคุณจะได้มากขึ้นคุณพยายามที่จะเข้าใจและในที่สุดคุณก็ไม่เชื่อว่ามีบางอย่างที่ดีหรือไม่ดีเพียงเพราะมีคนพูดถึงมัน :) นี่เป็นวิดีโอที่สร้างแรงบันดาลใจให้ฉัน :) การปฏิบัติที่ดีเป็นสิ่งที่ดี แต่อย่าใช้อย่างไร้เหตุผล :)


1
ใช่. ฉันได้พบแล้วอย่างน้อยใน Chrome กรณีการใช้งานที่ดูเหมือนว่ามีประสิทธิภาพมากกว่า เรียกใช้ RAF ที่ evals สตริงในตัวแปรที่กำหนดแต่ละการวนซ้ำ ใช้ setInterval เพื่อตั้งค่าเฉพาะสิ่งที่เน้นกราฟิกเช่นการแปลงการตั้งค่า ฯลฯ ในสตริงนั้น ฉันได้ลองวิธีอื่น ๆ เช่นการวนซ้ำฟังก์ชันในอาร์เรย์หรือใช้ตัวแปรเพื่อตั้งค่าการแปลงเฉพาะสำหรับองค์ประกอบที่เปลี่ยนไป แต่จนถึงตอนนี้ดูเหมือนว่าจะมีประสิทธิภาพมากที่สุด เมื่อพูดถึงแอนิเมชั่นการทดสอบม้านั่งที่แท้จริงก็คือดวงตาของคุณ
jdmayfield

5

ไม่จำเป็นว่าเลวร้ายหากคุณรู้ว่าคุณกำลังใช้บริบทอะไรอยู่

หากแอปพลิเคชันของคุณใช้eval()เพื่อสร้างวัตถุจาก JSON บางตัวซึ่งกลับมาจากXMLHttpRequestในเว็บไซต์ของคุณเองซึ่งสร้างโดยรหัสฝั่งเซิร์ฟเวอร์ที่เชื่อถือได้ของคุณนั่นอาจไม่ใช่ปัญหา

โค้ด JavaScript ฝั่งไคลเอ็นต์ที่ไม่น่าเชื่อถือไม่สามารถทำเช่นนั้นได้มาก หากสิ่งที่คุณกำลังดำเนินการeval()นั้นมาจากแหล่งข้อมูลที่สมเหตุสมผลคุณก็สบายดี


3
การใช้ eval ช้ากว่าการแยกวิเคราะห์ JSON หรือไม่
เบรนแดนลอง

@Qix - วิ่งทดสอบที่อยู่บนเบราว์เซอร์ของฉัน (Chrome 53) แสดงให้เห็นว่าevalเป็นค่อนข้างเร็วกว่าการแยกวิเคราะห์
Periata Breatta

@PerataBreatta Huh แปลก ฉันสงสัยว่าทำไม. ในขณะที่ฉันแสดงความคิดเห็นว่าไม่ใช่กรณี อย่างไรก็ตาม Chrome ไม่ได้แปลกใจเลยที่จะได้รับประสิทธิภาพที่เพิ่มขึ้นในบางพื้นที่ของรันไทม์จากรุ่นสู่รุ่น
Qix - MONICA ถูกยกเลิก

หัวข้อเก่า ๆ เล็ก ๆ ที่นี่ แต่จากสิ่งที่ฉันอ่าน - ไม่อ้างว่าฉันสืบมันกลับมาเอง - JSON.parse ในความเป็นจริง eval มันเป็นข้อมูลในขั้นตอนสุดท้าย ดังนั้นการทำงานอย่างมีประสิทธิภาพต้องใช้เวลา / งานมากขึ้น แต่ความปลอดภัยฉลาดทำไมไม่แยกแค่? eval เป็นเครื่องมือที่ยอดเยี่ยม ใช้สำหรับสิ่งที่ไม่มีวิธีอื่น ในการส่งผ่านฟังก์ชั่นผ่าน JSON มีวิธีที่จะทำได้โดยไม่ต้องใช้หลักฐาน พารามิเตอร์ที่สองใน JSON.stringify ช่วยให้คุณสามารถโทรกลับเพื่อเรียกใช้ที่คุณสามารถตรวจสอบผ่าน typeof ถ้ามันเป็นฟังก์ชั่น จากนั้นรับฟังก์ชั่น. toString () มีบทความที่ดีเกี่ยวกับเรื่องนี้ถ้าคุณค้นหา
jdmayfield


4

หากคุณต้องการให้ผู้ใช้ป้อนฟังก์ชันแบบลอจิคัลและประเมินค่าสำหรับ AND และ OR ฟังก์ชัน Eval ของ JavaScript นั้นสมบูรณ์แบบ ฉันสามารถยอมรับสองสายและeval(uate) string1 === string2อื่น ๆ


นอกจากนี้คุณยังสามารถใช้ Function () {} แต่ระวังเมื่อใช้สิ่งเหล่านี้บนเซิร์ฟเวอร์เว้นแต่คุณต้องการให้ผู้ใช้ควบคุมเซิร์ฟเวอร์ของคุณ hahahah
aoeu256

3

หากคุณเห็นการใช้ eval () ในรหัสของคุณโปรดจำไว้ว่ามนต์“ eval () เป็นสิ่งที่ชั่วร้าย”

ฟังก์ชั่นนี้ใช้สตริงที่กำหนดเองและรันเป็นโค้ด JavaScript เมื่อทราบรหัสที่เป็นปัญหาล่วงหน้า (ไม่ได้กำหนดที่รันไทม์) ไม่มีเหตุผลที่จะใช้ eval () หากโค้ดถูกสร้างขึ้นแบบไดนามิกในรันไทม์มักจะมีวิธีที่ดีกว่าในการบรรลุเป้าหมายโดยไม่ต้องใช้ eval () ตัวอย่างเช่นเพียงใช้เครื่องหมายวงเล็บเหลี่ยมเพื่อเข้าถึงคุณสมบัติแบบไดนามิกจะดีกว่าและง่ายกว่า:

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

// preferred
var property = "name";
alert(obj[property]);

การใช้งานeval()ยังมีผลกระทบด้านความปลอดภัยเนื่องจากคุณอาจกำลังเรียกใช้รหัส (ตัวอย่างเช่นมาจากเครือข่าย) ที่ได้รับการดัดแปลง นี่คือ antipattern ทั่วไปเมื่อจัดการกับการตอบสนอง JSON จากคำขอ Ajax ในกรณีเหล่านั้นควรใช้วิธีการในตัวของเบราว์เซอร์เพื่อวิเคราะห์การตอบสนอง JSON เพื่อให้แน่ใจว่าปลอดภัยและถูกต้อง สำหรับเบราว์เซอร์ที่ไม่สนับสนุนJSON.parse()โดยกำเนิดคุณสามารถใช้ไลบรารีจาก JSON.org

นอกจากนี้ยังเป็นสิ่งสำคัญที่ต้องจำไว้ว่าสตริงผ่านไปsetInterval(), setTimeout()และFunction()คอนสตรัคคือสำหรับส่วนใหญ่คล้ายกับการใช้eval()และดังนั้นจึงควรหลีกเลี่ยง

เบื้องหลัง JavaScript ยังคงต้องประเมินและรันสตริงที่คุณส่งเป็นรหัสการเขียนโปรแกรม:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

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

การใช้ตัวสร้าง Function () ใหม่คล้ายกับ eval () และควรได้รับการดูแลอย่างระมัดระวัง มันอาจเป็นสิ่งก่อสร้างที่ทรงพลัง แต่มักจะถูกใช้ในทางที่ผิด หากคุณต้องใช้อย่างแน่นอนeval()คุณสามารถพิจารณาใช้ Function () ใหม่แทน

มีประโยชน์เล็กน้อยที่อาจเกิดขึ้นเนื่องจากรหัสที่ประเมินในฟังก์ชันใหม่ () จะทำงานในขอบเขตฟังก์ชันท้องถิ่นดังนั้นตัวแปรใด ๆ ที่กำหนดด้วย var ในรหัสที่กำลังประเมินจะไม่กลายเป็นรูปกลมอัตโนมัติ

อีกวิธีหนึ่งในการป้องกันไม่ให้กลมกลืนอัตโนมัติคือการตัดการ eval()โทรเข้าฟังก์ชันการทำงานทันที


คุณช่วยแนะนำได้ไหมว่าฉันจะประเมินชื่อตัวแปรแบบไดนามิกของฟังก์ชั่นในท้องถิ่นโดยไม่ต้องทำการวิเคราะห์ได้อย่างไร? ฟังก์ชัน Eval (และคล้ายกัน) เป็นทางเลือกสุดท้ายในภาษาส่วนใหญ่ที่มีฟังก์ชั่นเหล่านั้น แต่บางครั้งก็จำเป็น ในกรณีที่ได้รับชื่อตัวแปรแบบไดนามิกโซลูชั่นใดปลอดภัยมากขึ้นหรือไม่ ไม่ว่าในกรณีใด ๆ จาวาสคริปต์เองนั้นไม่ได้มีไว้เพื่อความปลอดภัยที่แท้จริง หากคุณสนใจนี่คือกรณีการใช้งาน eval ของฉันซึ่งฉันชอบเปลี่ยน: stackoverflow.com/a/48294208
ปกติ Joe

2

นอกเหนือจากปัญหาด้านความปลอดภัยที่เป็นไปได้หากคุณกำลังเรียกใช้งานรหัสที่ผู้ใช้ส่งส่วนใหญ่มีวิธีที่ดีกว่าที่ไม่เกี่ยวข้องกับการแยกวิเคราะห์รหัสใหม่ทุกครั้งที่เรียกใช้งาน ฟังก์ชั่นที่ไม่ระบุชื่อหรือคุณสมบัติของวัตถุสามารถแทนที่การใช้ eval ส่วนใหญ่และมีความปลอดภัยและเร็วกว่ามาก


2

ปัญหานี้อาจมีปัญหามากขึ้นเนื่องจากเบราว์เซอร์รุ่นใหม่ออกมาพร้อมกับคอมไพเลอร์ JavaScript รหัสที่ดำเนินการผ่าน Eval อาจทำงานได้ไม่ดีเท่ากับ JavaScript ที่เหลือของคุณกับเบราว์เซอร์รุ่นใหม่เหล่านี้ บางคนควรทำโปรไฟล์


2

นี่เป็นหนึ่งในบทความที่ดีที่พูดถึง eval และมันไม่ใช่ความชั่วร้าย: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

ฉันไม่ได้บอกว่าคุณควรจะหมดและเริ่มใช้ eval () ทุกที่ ในความเป็นจริงมีกรณีการใช้งานที่ดีน้อยมากสำหรับการเรียกใช้ eval () เลย มีข้อสงสัยเกี่ยวกับความชัดเจนของรหัสการแก้จุดบกพร่องและประสิทธิภาพที่แน่นอนซึ่งไม่ควรมองข้าม แต่คุณไม่ควรกลัวที่จะใช้เมื่อคุณมีกรณีที่ eval () เข้าท่า พยายามอย่าใช้มันก่อน แต่อย่าให้ใครทำให้คุณกลัวว่ารหัสของคุณนั้นบอบบางหรือปลอดภัยน้อยกว่าเมื่อใช้ eval () อย่างเหมาะสม


2

eval () มีประสิทธิภาพมากและสามารถใช้เพื่อรันคำสั่ง JS หรือประเมินการแสดงออก แต่คำถามไม่ได้เกี่ยวกับการใช้งานของ eval () แต่ให้บอกว่าวิธีที่คุณใช้กับ eval () ได้รับผลกระทบจากบุคคลที่เป็นอันตราย ในตอนท้ายคุณจะใช้รหัสที่เป็นอันตราย ด้วยพลังที่มาพร้อมความรับผิดชอบที่ยอดเยี่ยม ดังนั้นจงใช้อย่างชาญฉลาดหากคุณกำลังใช้อยู่ นี่ไม่เกี่ยวข้องกับฟังก์ชัน eval () มากนัก แต่บทความนี้มีข้อมูลที่ดีพอสมควร : http://blogs.popart.com/2009/07/javascript-injection-attacks/ หากคุณกำลังมองหาพื้นฐานของ eval () ดูที่นี่: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval


2

JavaScript Engine มีจำนวนของการเพิ่มประสิทธิภาพที่มีประสิทธิภาพในระหว่างขั้นตอนการรวบรวม บางส่วนของแนวหินเหล่านี้มีความสามารถในการวิเคราะห์รหัสในขณะที่มันอยู่ในสถานะคงที่และกำหนดล่วงหน้าว่าการประกาศตัวแปรและฟังก์ชั่นทั้งหมดอยู่ที่ใดเพื่อที่จะพยายามแก้ไขตัวระบุระหว่างการดำเนินการ

แต่ถ้าเอ็นจิ้นพบ eval (.. ) ในโค้ดมันจะต้องสมมติว่าการรับรู้ตำแหน่งของตัวระบุทั้งหมดอาจไม่ถูกต้องเพราะมันไม่สามารถรู้ได้ว่าในเวลาใดที่คุณสามารถส่งรหัสไปยัง eval (.. ) เพื่อแก้ไขขอบเขตคำศัพท์หรือเนื้อหาของวัตถุที่คุณอาจส่งผ่านไปด้วยเพื่อสร้างขอบเขตคำศัพท์ใหม่ที่จะปรึกษา

กล่าวอีกนัยหนึ่งในแง่ร้ายแง่ลบการปรับให้เหมาะสมที่สุดนั้นจะไม่มีประโยชน์หากมี eval (.. ) อยู่ดังนั้นมันก็ไม่ได้ทำการปรับให้เหมาะสมเลย

สิ่งนี้อธิบายได้ทั้งหมด

เอกสารอ้างอิง:

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance


ไม่มีเครื่องมือจาวาสคริปต์ที่ไม่สามารถค้นหาและประเมินในรหัสพร้อมการรับประกัน 100% ดังนั้นมันจะต้องพร้อมสำหรับมันได้ตลอดเวลา
Jack Giffin

2

ไม่ใช่ความคิดที่ดีเสมอไป ยกตัวอย่างเช่นการสร้างรหัส ผมเพิ่งเขียนห้องสมุดที่เรียกว่าHyperbarsซึ่งเชื่อมช่องว่างระหว่างเสมือน Domและแฮนด์ มันเป็นเช่นนี้โดยการแยกแม่แบบแฮนด์บาร์และแปลงเป็นไฮเปอร์สคริปต์ซึ่งต่อมาถูกใช้โดย virtual-dom ตัวสร้างไฮเปอร์สเปคทีฟเป็นสตริงก่อนและก่อนที่จะส่งคืนeval()มันจะเปลี่ยนเป็นรหัสที่ปฏิบัติการได้ ฉันได้พบeval()ในสถานการณ์นี้ตรงข้ามกับความชั่วร้าย

โดยทั่วไปจาก

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

สำหรับสิ่งนี้

(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({}))

ประสิทธิภาพการทำงานของeval()ไม่ใช่ปัญหาในสถานการณ์เช่นนี้เนื่องจากคุณจำเป็นต้องตีความสายอักขระที่สร้างขึ้นเพียงครั้งเดียวและจากนั้นใช้งานผลลัพธ์ที่สามารถเรียกคืนได้หลายครั้ง

คุณสามารถดูวิธีการสร้างรหัสก็ประสบความสำเร็จถ้าคุณอยากรู้ที่นี่


2

ฉันจะไปไกลเท่าที่จะบอกว่ามันไม่สำคัญว่าถ้าคุณใช้eval()ในจาวาสคริปต์ที่ทำงานในเบราว์เซอร์ * (ข้อแม้)

เบราว์เซอร์สมัยใหม่ทั้งหมดมีคอนโซลผู้พัฒนาซึ่งคุณสามารถใช้งานจาวาสคริปต์ได้เองและผู้พัฒนากึ่งอัจฉริยะสามารถดูซอร์ส JS ของคุณและวางบิตใด ๆ ที่จำเป็นต้องใช้ในคอนโซล dev เพื่อทำสิ่งที่ต้องการ

* ตราบใดที่จุดปลายเซิร์ฟเวอร์ของคุณมีการตรวจสอบความถูกต้องและถูกต้องของค่าที่ผู้ใช้ระบุมันไม่สำคัญว่าจะมีการแยกวิเคราะห์และประเมินค่าอะไรในจาวาสคริปต์ฝั่งไคลเอ็นต์ของคุณ

ถ้าคุณต้องถามว่ามันเหมาะสมที่จะใช้eval()ใน PHP หรือไม่คำตอบคือไม่ยกเว้นว่าคุณอนุญาตรายการใด ๆ ที่อาจส่งผ่านไปยังคำสั่ง eval ของคุณ


ไม่เพียงมีคอนโซล dev เท่านั้นคุณยังสามารถพิมพ์ javascript: code ใน url bar เพื่อสร้างคอนโซล dev ของคุณเองบนหน้าเว็บหากไม่มีเลยดังเช่นกรณีบนเบราว์เซอร์ IE และอุปกรณ์มือถือรุ่นเก่า
Dmitry

1

ฉันจะไม่พยายามหักล้างสิ่งที่กล่าวมาก่อนหน้านี้ แต่ฉันจะเสนอการใช้ eval () นี้ที่ (เท่าที่ฉันรู้) ไม่สามารถทำได้ด้วยวิธีอื่น อาจมีวิธีอื่นในการเขียนโค้ดนี้และอาจเป็นวิธีการปรับให้เหมาะสม แต่วิธีนี้ทำมานานแล้วและไม่มีเสียงระฆังและเสียงนกหวีดเพื่อความชัดเจนเพื่อแสดงให้เห็นถึงการใช้ eval ที่ไม่มีทางเลือกอื่น ๆ นั่นคือ: ชื่อวัตถุที่สร้างขึ้นโดยทางโปรแกรม (หรือถูกต้องมากกว่า) แบบไดนามิก (ตรงข้ามกับค่า)

//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);

แก้ไข: โดยวิธีการที่ฉันจะไม่แนะนำ (ด้วยเหตุผลด้านความปลอดภัยทั้งหมดชี้ให้เห็นก่อนหน้านี้) ว่าคุณฐานคุณชื่อวัตถุในการป้อนข้อมูลของผู้ใช้ ฉันไม่สามารถจินตนาการถึงเหตุผลที่ดีที่คุณต้องการทำเช่นนั้น ยังคิดว่าฉันจะชี้ให้เห็นว่ามันจะไม่เป็นความคิดที่ดี :)


3
นี้สามารถทำได้ด้วยnamespaceToTest[namespaceParts[i]]ไม่จำเป็นต้อง eval ที่นี่ดังนั้นความif(typeof namespaceToTest[namespaceParts[i]] === 'undefined') { namespaceToTest[namespaceParts[i]] = {};แตกต่างเพียงอย่างเดียวสำหรับelse namespaceToTest = namespaceToTest[namespaceParts[i]];
user2144406

1

เก็บขยะ

คอลเล็กชันขยะของเบราว์เซอร์ไม่ทราบว่าจะสามารถลบรหัสที่มีการ eval'ed ออกจากหน่วยความจำได้หรือไม่ดังนั้นจึงเป็นเพียงการเก็บไว้จนกว่าจะโหลดหน้าเว็บอีกครั้ง ไม่เลวร้ายนักหากผู้ใช้ของคุณอยู่ในหน้าเว็บของคุณในไม่ช้า แต่อาจเป็นปัญหาสำหรับเว็บแอป

นี่คือสคริปต์เพื่อสาธิตปัญหา

https://jsfiddle.net/CynderRnAsh/qux1osnw/

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

สิ่งที่เรียบง่ายเหมือนโค้ดด้านบนจะทำให้มีหน่วยความจำเล็กน้อยที่จะจัดเก็บไว้จนกว่าแอปจะตาย นี่คือที่เลวร้ายยิ่งเมื่อสคริปต์ evaled เป็นฟังก์ชั่นใหญ่และเรียกในช่วงเวลา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.