JavaScript ของ eval () ไม่ใช่ชั่วเมื่อใด


263

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

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

ดังนั้นเมื่อไรที่จะใช้มัน?


5
ไลบรารี JSON ส่วนใหญ่ไม่ได้ใช้ eval ใต้ฝากระโปรงเพื่อป้องกันความเสี่ยงด้านความปลอดภัย
Sean McMillan

11
@Sean - ทั้ง JQuery และต้นแบบการใช้ EVAL (JQuery ใช้มันผ่านฟังก์ชั่นใหม่)
เพียร

5
@plodder - คุณรับข้อมูลของคุณจากที่ไหน jQuery ใช้ประโยชน์จาก JSON.parse () ดั้งเดิมตั้งแต่ 1.4 (ย้อนกลับไปใน 1/2010)! ดูด้วยตัวคุณเอง: code.jquery.com/jquery-1.4.js
ken

3
"แน่นอนหนึ่งต้องใช้ eval () เพื่อแยก JSON" - นี่ไม่เป็นความจริงในทางตรงกันข้าม - หนึ่งไม่ควรใช้ eval เพื่อแยก JSON! ใช้ Douglas Crockfords '(ผู้สร้าง JSON) สคริปต์ json2.js จากjson.org !
TMS

11
@Tomas ความประชดที่ json2.js ใช้ eval ในการวิเคราะห์ JSON
tobyodavies

คำตอบ:


262

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

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

  • ประสิทธิภาพ - eval () เรียกใช้ตัวแปล / คอมไพเลอร์ ถ้ารหัสของคุณถูกคอมไพล์นี่เป็นสิ่งที่ฮิตมากเพราะคุณต้องเรียกคอมไพเลอร์ที่อาจมีค่ามากในช่วงเวลาทำงาน อย่างไรก็ตาม JavaScript ยังคงเป็นภาษาที่ตีความส่วนใหญ่ซึ่งหมายความว่าการเรียก eval () ไม่ใช่ประสิทธิภาพที่ยิ่งใหญ่ในกรณีทั่วไป (แต่ดูคำพูดเฉพาะของฉันด้านล่าง)
  • การฉีดโค้ด - eval () อาจเรียกใช้สตริงของรหัสภายใต้สิทธิ์ระดับสูง ตัวอย่างเช่นโปรแกรมที่ทำงานในฐานะผู้ดูแลระบบ / รูทจะไม่ต้องการ eval () อินพุตของผู้ใช้เนื่องจากอินพุตนั้นอาจเป็น "rm -rf / etc / important-file" หรือแย่กว่านั้น อีกครั้ง JavaScript ในเบราว์เซอร์ไม่มีปัญหานั้นเนื่องจากโปรแกรมกำลังทำงานในบัญชีของผู้ใช้อยู่แล้ว JavaScript ฝั่งเซิร์ฟเวอร์อาจมีปัญหานั้น

เพื่อกรณีเฉพาะของคุณ จากสิ่งที่ฉันเข้าใจคุณกำลังสร้างสตริงด้วยตัวเองดังนั้นสมมติว่าคุณระวังที่จะไม่สร้างสตริงเช่น "rm -rf some-important" ที่จะสร้างไม่มีความเสี่ยงในการฉีดรหัส (แต่โปรดจำไว้ว่ามันเป็นเรื่องที่ดีมาก ยากที่จะมั่นใจในกรณีทั่วไป) นอกจากนี้หากคุณใช้เบราว์เซอร์การฉีดโค้ดมีความเสี่ยงเล็กน้อยฉันเชื่อว่า

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


78
คุณไม่ได้แก้ไขปัญหาของรหัสที่ใช้ eval เป็นเรื่องยากที่จะแก้ปัญหา
bobobobo

48
การฉีดโค้ดเป็นเรื่องที่ร้ายแรงมากสำหรับจาวาสคริปต์หากคุณกังวลเกี่ยวกับข้อมูลผู้ใช้ของคุณ รหัสที่ถูกฉีดจะทำงาน (ในเบราว์เซอร์) ราวกับว่ามันมาจากเว็บไซต์ของคุณปล่อยให้มันทำ shenanigan ในแบบที่ผู้ใช้สามารถทำได้ด้วยตนเอง หากคุณอนุญาตให้โค้ด (บุคคลที่สาม) เข้าสู่หน้าคุณสามารถสั่งสิ่งต่าง ๆ ในนามของลูกค้าของคุณหรือเปลี่ยนรูปแบบหรือสิ่งที่พวกเขาสามารถทำได้ผ่านเว็บไซต์ของคุณ ระวังให้มาก การปล่อยให้แฮกเกอร์เป็นเจ้าของลูกค้าของคุณนั้นแย่พอ ๆ กับการปล่อยให้พวกเขาเป็นเจ้าของเซิร์ฟเวอร์ของคุณ
Sean McMillan

71
หากข้อมูลมาจากเซิร์ฟเวอร์ของคุณและสิ่งที่คุณผู้พัฒนาได้สร้างขึ้นจะไม่มีอันตรายใด ๆ ในการใช้ eval () อันตรายที่แท้จริงคือการเชื่อทุกสิ่งที่คุณอ่าน คุณเห็นคนจำนวนมากพูดว่า eval () เป็นสิ่งที่ชั่วร้ายและพวกเขาไม่รู้ว่าทำไมยกเว้นว่าพวกเขาอ่านมันที่ไหนซักแห่ง
Vince Panuccio

42
@Sean McMillan: ฉันต้องการที่จะเชื่อคุณ แต่ถ้าใครบางคนกำลังจะสกัดกั้นและเปลี่ยนจาวาสคริปต์ที่จะไปeval()จากเซิร์ฟเวอร์ของคุณพวกเขาก็สามารถเปลี่ยนแหล่งที่มาของหน้าเว็บในตอนแรกและยังควบคุมข้อมูลของผู้ใช้ . . ฉันไม่เห็นความแตกต่าง
Walt W

20
เรื่อง "การฉีดโค้ด - ... อีกครั้ง JavaScript ในเบราว์เซอร์ไม่มีปัญหานั้น" & "นอกจากนี้หากคุณใช้เบราว์เซอร์การฉีดโค้ดมีความเสี่ยงเล็กน้อยฉันเชื่อ" คุณแนะนำว่าการฉีดโค้ดในเบราว์เซอร์ไม่ใช่ปัญหาหรือไม่? XSS อยู่ใน 3 อันดับแรกในรายการ 10 อันดับแรกของ OWASP มาหลายปีแล้ว
Mike Samuel

72

eval()ไม่ใช่ความชั่วร้าย หรือถ้าเป็นก็เป็นสิ่งที่ชั่วร้ายในลักษณะเดียวกันกับที่ไฟล์ภาพ / I / O ของเครือข่ายการทำเกลียวและ IPC เป็น "ความชั่วร้าย" ในภาษาอื่น

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


5
หนึ่งในวัตถุประสงค์ดังกล่าวอาจเป็นการสร้างรหัสที่ปรับให้เหมาะสมซึ่งอาจยาวเกินไปหรือซ้ำซ้อนเกินกว่าที่จะเขียนด้วยมือ ชนิดของสิ่งที่ใน LISP จะเรียกหาแมโคร
wberry

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

2
เร็วขึ้นง่ายขึ้นชัดเจนขึ้น ... คำตอบนี้ไม่ครอบคลุมถึงผลกระทบด้านความปลอดภัยที่ดีพอ
Ruud Helderman

55

เมื่อคุณเชื่อถือแหล่งที่มา

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

ในกรณีอื่น ๆ ทั้งหมดฉันจะใช้ความพยายามอย่างยิ่งใหญ่ในการตรวจสอบให้แน่ใจว่าข้อมูลที่ผู้ใช้ให้มานั้นสอดคล้องกับกฎของฉันก่อนที่จะส่งไปให้ eval ()


13
สตริง json ควรทดสอบกับไวยากรณ์ json เสมอก่อนที่จะใช้ใน eval () ดังนั้นสตริง json "{foo: alert ('XSS')}" จะไม่ผ่านเนื่องจาก“ alert ('XSS')” ไม่ใช่ค่าที่เหมาะสม
Gumbo

3
ถ้าอย่างนั้นให้ใช้ HTTPS OTOH: man-in-the-middle ไม่ใช่สถานการณ์การโจมตีโดยทั่วไปสำหรับเว็บแอพพลิเคชั่นสวนหลากหลายในขณะที่เช่นการเขียนสคริปต์ข้ามไซต์
Tomalak

7
evalจะไม่ถูกต้องแยกสตริง JSON ที่ถูกต้องทั้งหมด ตัวอย่างเช่นJSON.parse(' "\u2028" ') === "\u2028"แต่eval(' "\u2028" ')เพิ่มข้อยกเว้นเนื่องจาก U + 2028 เป็นบรรทัดใหม่ใน JavaScript แต่ไม่ขึ้นบรรทัดใหม่เท่าที่เกี่ยวข้องกับ JSON
Mike Samuel

1
@Justin - หากโปรโตคอลถูกโจมตีโดยปกติแล้วการโหลดหน้าเริ่มต้นจะถูกส่งผ่านโปรโตคอลเดียวกันนั้นและจากนั้นก็เป็นจุดที่สงสัยเนื่องจากไคลเอนต์นั้นถูกบุกรุกแล้วเนื่องจากอาจเป็นไปได้
antinome

1
@Tomalak พูดอย่างสวยงามฉันได้พูดเรื่องนี้ในคำตอบของฉันตอนนี้! ! น่ากลัว
NiCk Newman

25

รับคนจริง ๆ :

  1. เบราว์เซอร์หลัก ๆ ทุกเครื่องมีคอนโซลในตัวซึ่งแฮกเกอร์ของคุณสามารถใช้ได้อย่างมากมายในการเรียกใช้ฟังก์ชั่นที่มีค่าใด ๆ

  2. หากใช้เวลา 0.2 วินาทีในการรวบรวม JavaScript 2,000 บรรทัดการเสื่อมประสิทธิภาพของฉันจะเป็นอย่างไรหากฉันประเมิน JSON สี่บรรทัด

แม้แต่คำอธิบายของ Crockford สำหรับ 'eval is evil' ก็อ่อนแอ

eval is Evil, ฟังก์ชั่น eval เป็นคุณสมบัติที่ใช้งานผิดพลาดมากที่สุดของ JavaScript หลีกเลี่ยงมัน

ในขณะที่คร็อคฟอร์ดเองอาจพูดว่า "ข้อความแบบนี้มีแนวโน้มที่จะสร้างโรคประสาทไม่ลงตัวอย่าซื้อเลย"

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

BTW: Prototype.js เรียกใช้ eval โดยตรงห้าครั้ง (รวมถึง evalJSON () และ evalResponse ()) jQuery ใช้มันใน parseJSON (ผ่าน Function Constructor)


10
JQuery ใช้ฟังก์ชัน JSON.parse ในตัวของเบราว์เซอร์ถ้ามี (ซึ่งเร็วกว่า & ปลอดภัยกว่า) โดยใช้ eval เป็นกลไกทางเลือกเท่านั้น คำว่า "eval is evil" เป็นแนวทางที่ดีพอสมควร
jjmontes

30
เรื่อง "ทุกเบราว์เซอร์ที่สำคัญตอนนี้มีคอนโซลในตัว ... " การฉีดรหัสเป็นปัญหาเมื่อผู้ใช้รายหนึ่งสามารถป้อนรหัสที่จะเรียกใช้ในเบราว์เซอร์ของผู้ใช้รายอื่น เบราว์เซอร์คอนโซลไม่อนุญาตให้ผู้ใช้หนึ่งคนเรียกใช้รหัสในเบราว์เซอร์ผู้ใช้รายอื่นดังนั้นพวกเขาจึงไม่เกี่ยวข้องเมื่อตัดสินใจว่าคุ้มค่าที่จะป้องกันการฉีดรหัสหรือไม่
Mike Samuel

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

5
@ Akkishore ฉันจะขอบคุณถ้าคุณมากับตัวอย่างชีวิตจริงที่สนับสนุนงบของคุณไป
Akash Kava

7
@AkashKava สิ่งที่คุณไม่สามารถตระหนักได้ก็คือถ้าฉันส่ง javascript ในช่องแสดงความคิดเห็นของฉันและ javascript นั้นทำให้มันเป็นฐานข้อมูล เมื่อผู้ใช้รายอื่นเห็นว่ามีความคิดเห็น (ที่ฉันใส่จาวาสคริปต์) eval จะใช้จาวาสคริปต์นั้นเมื่อมีการแสดงผลและประเมินผลโดยใช้ล่ามทำให้จาวาสคริปต์ในตัวของฉันทำงานบนเบราว์เซอร์ของผู้ใช้รายอื่น ด้วยการทำเช่นนี้ฉันสามารถทำให้ข้อมูลทุกประเภทเป็นประกายได้ ชื่อผู้ใช้รหัสผู้ใช้ของพวกเขาในฐานข้อมูลที่อยู่อีเมลของพวกเขา ฯลฯ นี่ไม่ใช่คำตอบที่ยากถ้าคุณมี Googled XSS คุณจะเห็นว่าประมาณ 10 วินาทีว่าทำไมมันถึงมีปัญหา
Kyle Richter

18

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

setTimeout(function() {
  alert('hi');
}, 1000);

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


2
ฉันคิดว่าข้อบกพร่องในฟอร์แมต JSON ทางฝั่งเซิร์ฟเวอร์เป็นปัญหาอย่างแน่นอน การตอบสนองจากเซิร์ฟเวอร์ขึ้นอยู่กับข้อความที่ผู้ใช้ส่งหรือไม่? จากนั้นคุณต้องดู XSS
swilliams

3
หากเว็บเซิร์ฟเวอร์ของคุณไม่ได้รับการรับรองความถูกต้องผ่าน HTTPS คุณอาจประสบกับการโจมตีแบบ Man-in-the-middle บางชนิดที่โฮสต์อื่นขัดขวางคำขอและส่งข้อมูลของตัวเอง
Ben Combee

11
หากใครบางคนสามารถทำการโจมตีคนที่อยู่ตรงกลางเขาสามารถฉีดอะไรก็ได้ลงในสคริปต์ของคุณ
el.pescado

10
คุณไม่ควรใช้โค้ดจาวาสคริปต์ของคุณเลย ... คุณไม่ต้องพึ่งพาสิ่งใดที่ทำงานบนฝั่งไคลเอ็นต์ ... ถ้ามีคนโจมตีแบบแมน - ทู - อิน - กลางทำไมเขาถึงยุ่งกับวัตถุ json ของคุณ? เขาสามารถให้บริการหน้าเว็บที่แตกต่างกันกับคุณและ js ที่แตกต่างกันไฟล์ ...
Calmarius

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

4

ฉันเห็นคนสนับสนุนไม่ใช้ eval เพราะมันชั่วร้ายแต่ฉันเห็นคนเดียวกันใช้ Function และ setTimeout แบบไดนามิกดังนั้นพวกเขาจึงใช้ eval ภายใต้หมวก : D

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

ตอนนี้บทส่งท้ายของบทความนี้คือ:

ถ้าคุณ จริงๆต้องการมัน (80% ของเวลา EVAL จะไม่จำเป็น) และคุณแน่ใจว่าสิ่งที่คุณกำลังทำเพียงแค่ใช้ EVAL (หรือฟังก์ชั่นที่ดีกว่า;)) ปิดและ OOP ครอบคลุม 80/90% ของ กรณีที่สามารถเปลี่ยน eval โดยใช้ตรรกะชนิดอื่นส่วนที่เหลือเป็นรหัสที่สร้างขึ้นแบบไดนามิก (ตัวอย่างเช่นถ้าคุณกำลังเขียนล่าม) และตามที่คุณพูดแล้วประเมิน JSON (ที่นี่คุณสามารถใช้การประเมินผลที่ปลอดภัย Crockford;))


และตามที่ Crockford ชี้ให้เห็นตัวเขาเองเว็บเบราว์เซอร์ปัจจุบันมีฟังก์ชันJSON.parse ในตัว
Ruud Helderman

4

Eval เป็นส่วนเสริมของการคอมไพล์ซึ่งใช้ในการสร้างรหัสเทมเพลต โดยการสร้างเทมเพลตฉันหมายความว่าคุณเขียนเทมเพลตที่เรียบง่ายซึ่งสร้างโค้ดเทมเพลตที่มีประโยชน์ซึ่งจะช่วยเพิ่มความเร็ว

ฉันได้เขียนเฟรมเวิร์กโดยที่นักพัฒนาไม่ได้ใช้ EVAL แต่พวกเขาใช้เฟรมเวิร์กของเราและในที่สุดเฟรมเวิร์กก็ต้องใช้ EVAL เพื่อสร้างเทมเพลต

ประสิทธิภาพของ EVAL สามารถเพิ่มขึ้นได้โดยใช้วิธีการต่อไปนี้ แทนที่จะเรียกใช้สคริปต์คุณต้องส่งคืนฟังก์ชัน

var a = eval("3 + 5");

มันควรจะจัดเป็น

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

การแคชจะปรับปรุงความเร็วอย่างแน่นอน

Chrome ยังสามารถแก้ไขข้อบกพร่องของฟังก์ชั่นดังกล่าวได้อย่างง่ายดาย

เกี่ยวกับความปลอดภัยการใช้ eval หรือไม่สร้างความแตกต่าง

  1. ก่อนอื่นเบราว์เซอร์จะเรียกใช้สคริปต์ทั้งหมดในแซนด์บ็อกซ์
  2. รหัสใด ๆ ที่เป็นความชั่วร้ายใน EVAL เป็นความชั่วร้ายในเบราว์เซอร์เอง ผู้โจมตีหรือใครก็ตามสามารถฉีดโหนดสคริปต์ใน DOM ได้อย่างง่ายดายและทำทุกอย่างถ้าเขา / เธอสามารถทำอะไรได้ การไม่ใช้ EVAL จะไม่สร้างความแตกต่างใด ๆ
  3. การรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์ส่วนใหญ่นั้นเป็นอันตราย การตรวจสอบคุกกี้ที่ไม่ดีหรือการใช้งาน ACL ที่ไม่ดีบนเซิร์ฟเวอร์ทำให้เกิดการโจมตีส่วนใหญ่
  4. ช่องโหว่ Java ล่าสุดและอื่น ๆ มีอยู่ในโค้ดเนทีฟของ Java JavaScript นั้นถูกออกแบบมาให้ทำงานในแซนด์บ็อกซ์ในขณะที่แอปเพล็ตถูกออกแบบมาให้ทำงานนอกแซนด์บ็อกซ์พร้อมใบรับรอง ฯลฯ ซึ่งนำไปสู่ช่องโหว่และสิ่งอื่น ๆ อีกมากมาย
  5. การเขียนโค้ดเพื่อเลียนแบบเบราว์เซอร์นั้นไม่ยาก สิ่งที่คุณต้องทำคือส่งคำขอ HTTP ไปยังเซิร์ฟเวอร์ด้วยสตริงตัวแทนผู้ใช้ที่คุณชื่นชอบ เครื่องมือทดสอบทั้งหมดจำลองเบราว์เซอร์ไว้แล้ว หากผู้โจมตีต้องการทำร้ายคุณ EVAL เป็นทางเลือกสุดท้ายของพวกเขา พวกเขามีวิธีอื่น ๆ ในการจัดการกับความปลอดภัยฝั่งเซิร์ฟเวอร์ของคุณ
  6. DOM เบราว์เซอร์ไม่สามารถเข้าถึงไฟล์และไม่ใช่ชื่อผู้ใช้ อันที่จริงไม่มีอะไรในเครื่องที่ eval สามารถเข้าถึงได้

หากการรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์ของคุณมั่นคงเพียงพอสำหรับทุกคนที่จะถูกโจมตีจากทุกที่คุณไม่ควรกังวลเกี่ยวกับ EVAL อย่างที่ฉันได้กล่าวไปแล้วว่าถ้าไม่มี EVAL ผู้โจมตีจะมีเครื่องมือมากมายที่จะแฮ็คเข้าสู่เซิร์ฟเวอร์ของคุณ

Eval นั้นดีสำหรับการสร้างเทมเพลตบางตัวเพื่อทำการประมวลผลสตริงที่ซับซ้อนตามสิ่งที่ไม่ได้ใช้ล่วงหน้า ตัวอย่างเช่นฉันจะชอบ

"FirstName + ' ' + LastName"

ตรงข้ามกับ

"LastName + ' ' + FirstName"

เป็นชื่อที่แสดงของฉันซึ่งสามารถมาจากฐานข้อมูลและไม่ได้ hardcoded


คุณสามารถใช้ฟังก์ชั่นแทน EVAL function (first, last) { return last + ' ' + first }-
Konrad Borowski

ชื่อของคอลัมน์มาจากฐานข้อมูล
Akash Kava

3
ภัยคุกคามของการevalเป็นส่วนใหญ่ผู้ใช้อื่นสมมติว่าคุณมีหน้าการตั้งค่าและมันช่วยให้คุณกำหนดว่าชื่อของคุณจะปรากฏต่อผู้อื่นอย่างไร สมมติว่าคุณไม่ได้คิดอย่างชัดเจนเมื่อคุณเขียนมันดังนั้นกล่องที่คุณเลือกมีตัวเลือก<option value="LastName + ' ' + FirstName">Last First</option>ดังนี้ ฉันเปิดเครื่องมือ dev ของฉันเปลี่ยนตัวvalueเลือกเป็นเลือกตัวalert('PWNED!')เลือกที่เปลี่ยนแปลงและส่งแบบฟอร์ม ตอนนี้เมื่อใดก็ตามที่บางคนสามารถเห็นชื่อที่แสดงของฉันรหัสนั้นจะทำงาน
cHao

@cHao สิ่งที่คุณกำลังพูดถึงคือตัวอย่างของการรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์ที่ไม่ดีเซิร์ฟเวอร์ไม่ควรรับข้อมูลที่สามารถเรียกใช้เป็นรหัสในเบราว์เซอร์ของใครก็ได้ อีกครั้งคุณไม่เข้าใจแนวคิดของการรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์ที่ไม่ดี
Akash Kava

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

4

เมื่อทำการดีบั๊กใน Chrome (v28.0.1500.72) ฉันพบว่าตัวแปรไม่ถูกผูกไว้กับการปิดหากไม่ได้ใช้ในฟังก์ชันซ้อนที่สร้างการปิด ฉันเดาว่าเป็นเครื่องมือเพิ่มประสิทธิภาพของ JavaScript

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

นี่คือรหัสทดสอบของฉัน:

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

สิ่งที่ฉันชอบที่จะชี้ให้เห็นที่นี่คือ eval () นั้นไม่จำเป็นต้องอ้างถึงeval()ฟังก์ชั่นพื้นฐาน ทั้งหมดขึ้นอยู่กับชื่อของฟังก์ชั่น ดังนั้นเมื่อเรียกชื่อพื้นเมืองeval()ด้วยชื่อนามแฝง (พูดvar noval = eval;แล้วในฟังก์ชันภายในnoval(expression);) การประเมินผลexpressionอาจล้มเหลวเมื่ออ้างถึงตัวแปรที่ควรเป็นส่วนหนึ่งของการปิด แต่จริง ๆ แล้วไม่ใช่



3

บรรทัดล่าง

หากคุณสร้างหรือปรุงแต่งรหัสที่คุณevalก็ไม่เคยมีความชั่วร้าย

รายละเอียดเพิ่มเติมเล็กน้อย

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

evalคือไม่ได้ชั่วร้ายถ้าทำงานบนไคลเอนต์แม้ว่าใช้อินพุต unsanitized ที่สร้างขึ้นโดยลูกค้า

เห็นได้ชัดว่าคุณควรฆ่าเชื้ออินพุตให้สะอาดอยู่เสมอเพื่อให้สามารถควบคุมโค้ดที่คุณใช้

เหตุผล

ไคลเอนต์สามารถเรียกใช้รหัสใด ๆ ที่พวกเขาต้องการแม้ว่านักพัฒนาไม่ได้รหัส นี่คือความจริงไม่เพียง แต่สำหรับสิ่งที่จะ evaled แต่เรียกร้องให้evalตัวเอง


2

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

... และ 9 คูณ 10 คุณสามารถหลีกเลี่ยงการทำเช่นนั้นซ้ำได้โดยง่าย


ทุกวันนี้มีวิธีอื่น ๆ (และดีกว่า) ในการโหลด JavaScript แบบอะซิงโครนัสจากเซิร์ฟเวอร์: w3bits.com/async-javascript
Ruud Helderman

1

evalไม่ใช่ทางเลือกที่เหมาะสม ขณะที่อาจมีหลายกรณีที่คุณสามารถบรรลุสิ่งที่คุณต้องการที่จะประสบความสำเร็จโดยการเชื่อมโยงสคริปต์ด้วยกันและทำงานได้ทันทีคุณมักจะมีประสิทธิภาพมากขึ้นและเทคนิคการบำรุงรักษาที่จำหน่ายของคุณ: สัญกรณ์เชื่อมโยงอาร์เรย์ ( obj["prop"]เป็นเช่นเดียวกับobj.prop) , การปิด, เทคนิคเชิงวัตถุ, เทคนิคการใช้งาน - ใช้มันแทน


1

เท่าที่ลูกค้าสคริปต์ไปฉันคิดว่าปัญหาด้านความปลอดภัยเป็นจุดที่สงสัย ทุกสิ่งที่โหลดลงในเบราว์เซอร์อาจมีการจัดการและควรได้รับการปฏิบัติเช่นนี้ ไม่มีความเสี่ยงในการใช้คำสั่ง eval () เมื่อมีวิธีที่ง่ายกว่าในการเรียกใช้โค้ด JavaScript และ / หรือจัดการกับวัตถุใน DOM เช่นแถบ URL ในเบราว์เซอร์ของคุณ

javascript:alert("hello");

ถ้ามีคนต้องการจัดการ DOM ของพวกเขาฉันจะบอกว่าแกว่งไป การรักษาความปลอดภัยเพื่อป้องกันการโจมตีประเภทใด ๆ ควรเป็นความรับผิดชอบของแอปพลิเคชันเซิร์ฟเวอร์ระยะเวลา

จากมุมมองในทางปฏิบัติไม่มีประโยชน์ที่จะใช้ eval () ในสถานการณ์ที่สิ่งต่าง ๆ สามารถทำได้ อย่างไรก็ตามมีบางกรณีที่ควรใช้ eval หากเป็นเช่นนั้นสามารถทำได้อย่างแน่นอนโดยไม่มีความเสี่ยงจากการระเบิดหน้าเว็บ

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

6
เรื่อง "ไม่มีความเสี่ยงในการใช้คำสั่ง eval () เมื่อมีวิธีที่ง่ายกว่าในการเรียกใช้ javascript และ / หรือจัดการกับวัตถุใน DOM" การฉีดรหัสเป็นปัญหาเมื่อผู้ใช้รายหนึ่งสามารถป้อนรหัสที่จะเรียกใช้ในเบราว์เซอร์ของผู้ใช้รายอื่น เบราว์เซอร์คอนโซลไม่อนุญาตให้ผู้ใช้หนึ่งคนเรียกใช้รหัสในเบราว์เซอร์ผู้ใช้รายอื่นดังนั้นพวกเขาจึงไม่เกี่ยวข้องเมื่อตัดสินใจว่าคุ้มค่าที่จะป้องกันการฉีดรหัสหรือไม่
Mike Samuel

ไม่<head></head>จำเป็นแม้ว่าจะว่างเปล่า?
Peter Mortensen

2
คำตอบนี้ละเว้นความเสี่ยงของXSSอย่างสมบูรณ์
Ruud Helderman

1

บนฝั่งเซิร์ฟเวอร์ eval มีประโยชน์เมื่อจัดการกับสคริปต์ภายนอกเช่น sql หรือ influxdb หรือ mongo การตรวจสอบความถูกต้องที่กำหนดเอง ณ รันไทม์สามารถทำได้โดยไม่ต้องปรับใช้บริการของคุณอีกครั้ง

ตัวอย่างเช่นบริการความสำเร็จที่มีข้อมูลเมตาดังต่อไปนี้

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

ซึ่งอนุญาตให้

  • การฉีดโดยตรงของวัตถุ / ค่าผ่านสตริงตัวอักษรใน json มีประโยชน์สำหรับตำราเทมเพลต

  • สามารถใช้เป็นเครื่องมือเปรียบเทียบกล่าวว่าเราสร้างกฎวิธีการตรวจสอบความถูกต้องของภารกิจหรือเหตุการณ์ใน CMS

แย้งของนี้

  • อาจเป็นข้อผิดพลาดในรหัสและแยกแยะสิ่งต่าง ๆ ในบริการหากไม่ผ่านการทดสอบอย่างสมบูรณ์

  • หากแฮ็กเกอร์สามารถเขียนสคริปต์บนระบบของคุณแสดงว่าคุณเมามาก

  • วิธีหนึ่งในการตรวจสอบสคริปต์ของคุณคือรักษาแฮชสคริปต์ไว้ที่ใดที่หนึ่งที่ปลอดภัยดังนั้นคุณสามารถตรวจสอบสคริปต์ก่อนทำงานได้


ดี เมื่อฉันถามคำถามที่ฉันไม่ได้คิดเกี่ยวกับ JS ฝั่งเซิร์ฟเวอร์
Richard Turner

1

ฉันคิดว่ากรณีใด ๆ ของการประเมินความชอบธรรมจะหายาก คุณมีแนวโน้มที่จะใช้มันโดยคิดว่ามันเป็นธรรมมากกว่าที่คุณจะใช้มันเมื่อมันเป็นธรรมจริง

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

หากคุณต้องการทราบข้อมูลเพิ่มเติม: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval


0

ไม่เป็นไรหากคุณสามารถควบคุมรหัสที่ส่งผ่านไปยังevalฟังก์ชันได้อย่างสมบูรณ์


2
หากคุณมีอำนาจควบคุมสิ่งที่คุณกำลังจะผ่านไปevalคำถามสำคัญก็จะกลายเป็นว่าเมื่อไรที่ควรจะเป็นสตริงแทนที่จะเป็น JS จริง
cHao

@cHao ตัวอย่างเช่นถ้าคุณมีแอปพลิเคชั่นเกมขนาดใหญ่ (Javascript ขนาด 5-10MB) มันจะดีกว่าที่จะสร้าง AJAX-Preloader โหลดเร็วแบบง่าย (1kb) ซึ่งโหลด Main-Script ขนาดใหญ่ในขณะที่กำลังโหลด - บาร์หรือสิ่งที่คล้ายกัน หลังจากดาวน์โหลดคุณสามารถใช้ "eval (แหล่งที่มา)" หรือดีกว่า "ฟังก์ชั่นใหม่ (แหล่งที่มา)" เพื่อรัน Game-Application-Script ที่โหลดไว้ วิธีนี้ทำให้ผู้ใช้สามารถเห็นแอปพลิเคชันต้องใช้เวลาในการดาวน์โหลดจนกว่าเกมจะเริ่มต้น หากไม่มีผู้ใช้จะต้องรอให้แอปพลิเคชันทั้งหมดโหลดโดยไม่มีข้อเสนอแนะทางสายตา
SammieFox

@SammieFox มีวิธีอื่น ๆ (และดีกว่า) <script async="true" src="...">การทำเช่นนี้มีความโดดเด่นที่สุด ดูเพิ่มเติมที่: w3bits.com/async-javascript
Ruud Helderman

คำตอบคือคำแนะนำที่เป็นอันตราย นักพัฒนาจำนวนมากเกินไปมีความรู้สึกผิดที่อยู่ในการควบคุม คำแนะนำนี้เหมาะสมสำหรับซอฟต์แวร์ที่ไม่ได้รับการบำรุงรักษาอีกต่อไป แต่ซอฟต์แวร์ดังกล่าวควรได้รับการพิจารณาว่าเสียชีวิต
Ruud Helderman

0

เฉพาะในระหว่างการทดสอบถ้าเป็นไปได้ โปรดทราบด้วยว่า eval () ช้ากว่าผู้ให้คำปรึกษาเฉพาะด้านอื่น ๆ มากเช่นกัน


0

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

ดังนั้น ... เมื่อใดที่จะไม่ใช้ eval ()? Eval () ไม่ควรใช้เมื่อมีโอกาสที่บุคคลที่สามสามารถเปลี่ยนได้ เช่นเดียวกับการสกัดกั้นการเชื่อมต่อระหว่างไคลเอนต์และเซิร์ฟเวอร์ของคุณ (แต่ถ้าเป็นปัญหาให้ใช้ HTTPS) คุณไม่ควร eval () สำหรับการแยกวิเคราะห์รหัสที่คนอื่นเขียนเช่นในฟอรัม


เรื่อง "ไม่มีเหตุผลที่จะไม่ใช้ eval () ตราบใดที่คุณมั่นใจได้ว่าซอร์สโค้ดนั้นมาจากคุณหรือผู้ใช้จริง" สมมติว่ามีผู้ใช้คนเดียว หลักฐานดังกล่าวไม่ได้ระบุไว้ใน OP เมื่อมีผู้ใช้หลายคนความประมาทevalของสตริงที่ประกอบด้วยเนื้อหาจากผู้ใช้รายหนึ่งสามารถอนุญาตให้ผู้ใช้นั้นเรียกใช้รหัสในเบราว์เซอร์ของผู้ใช้รายอื่น
Mike Samuel

@ MikeSamuel, eval สามารถรันโค้ดในเบราว์เซอร์ของผู้ใช้คนอื่นฉันไม่เคยได้ยินสิ่งนี้คุณได้ลองแล้วหรือยัง? สิ่งนี้ไม่เคยเกิดขึ้นในประวัติศาสตร์ของการสืบค้นคุณช่วยแสดงตัวอย่างให้เราดูได้ไหม?
Akash Kava

@AkashKava สตริงสามารถกำเนิดกับตัวแทนผู้ใช้หนึ่งถูกเก็บไว้ในฐานข้อมูลและจากนั้นให้บริการไปยังเบราว์เซอร์อื่นที่evalมัน มันเกิดขึ้นตลอดเวลา
Mike Samuel

ฐานข้อมูล @MikeSamuel ที่ไหน ใครทำหน้าที่ผิดสาย? ไม่ได้เป็นฐานข้อมูลทางฝั่งเซิร์ฟเวอร์ที่จะตำหนิ? ก่อนอื่น EVAL นั้นไม่ควรถูกตำหนิเนื่องจากโค้ดด้านเซิร์ฟเวอร์ที่เขียนไม่ดี ใช้ jsfiddle และแสดงให้โลกเห็นตัวอย่างของโลกแห่งความจริงที่สามารถก่อให้เกิดอันตรายได้
Akash Kava

2
@AkashKava ฉันไม่เข้าใจคำถามของคุณ เราไม่ได้พูดคุยเกี่ยวกับโปรแกรมเฉพาะ evalแต่เหตุผลที่จะไม่ใช้ การตำหนิเซิร์ฟเวอร์มีประโยชน์อย่างไร? หากใครควรถูกตำหนิก็ควรเป็นผู้โจมตี โดยไม่คำนึงถึงความผิดลูกค้าที่ไม่เสี่ยงต่อ XSS แม้จะมีข้อบกพร่องในเซิร์ฟเวอร์จะดีกว่าไคลเอนต์ที่มีความเสี่ยง แต่สิ่งอื่นก็เท่าเทียมกัน
Mike Samuel

0

ถ้ามันจำเป็นจริงๆ eval ไม่ใช่ความชั่วร้าย แต่ 99.9% ของการใช้ eval ที่ฉันสะดุดข้ามนั้นไม่จำเป็น (ไม่รวมสิ่ง setTimeout)

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


5
ไม่จำเป็นต้องใช้ eval สำหรับ setTimeout คุณสามารถใช้ฟังก์ชันอ้างอิงได้เช่นกัน
Matthew Crumley

0

JavaScript ของ eval () ไม่ใช่ชั่วเมื่อใด

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

แต่ฉันพบตัวอย่างหนึ่งที่ควรใช้:

เมื่อคุณต้องผ่านการแสดงออก

ตัวอย่างเช่นฉันมีฟังก์ชั่นที่สร้างgoogle.maps.ImageMapTypeวัตถุทั่วไปสำหรับฉัน แต่ฉันต้องบอกสูตรว่ามันควรสร้าง URL แบบเรียงต่อจากพารามิเตอร์zoomและcoordพารามิเตอร์อย่างไร:

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

3
ดูเหมือนว่าจะสามารถ refactored เพื่อให้ eval () ไม่จำเป็น - tileURLexpr เป็นเพียงเทมเพลตดังนั้นการใช้ replace () อย่างชาญฉลาดจะใช้แทน () ถึงกระนั้นก็ยังเตือนฉันถึงตัวอย่างที่ฉันมีอยู่ในใจเมื่อฉันส่งคำถามซึ่งจะทำอย่างไรกับการอนุญาตให้ผู้ใช้ระบุสูตรทางคณิตศาสตร์ที่จะได้รับการประเมินคล้ายกับฟังก์ชั่นสเปรดชีต แน่นอนฉันไม่ได้พูดถึงเรื่องนั้นในเวลานั้นเพราะฉันไม่ต้องการมีอิทธิพลต่อคำตอบ!
Richard Turner

8
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Casey Chu

0

ตัวอย่างของฉันของการใช้eval: นำเข้า

มันเป็นเรื่องปกติ

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

แต่ด้วยความช่วยเหลือevalและฟังก์ชั่นผู้ช่วยเล็กน้อยมันจึงดูดีขึ้นมาก:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable อาจมีลักษณะ (รุ่นนี้ไม่รองรับการนำเข้าสมาชิกที่เป็นรูปธรรม)

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

2
+1 สำหรับความคิด .replace(/name/g, name).replace('path', path)แต่คุณมีข้อผิดพลาดที่นี่: หากnameมีสตริง"path"แล้วคุณจะได้รับความประหลาดใจ
wberry

1
การประกาศหนึ่งตัวแปรสำหรับแต่ละคุณสมบัติของcomponentsคือกลิ่นรหัสที่เป็นไปได้ การเปลี่ยนรหัสใหม่อาจช่วยกำจัด 'ปัญหา' ทั้งหมดได้ วิธีแก้ปัญหาปัจจุบันของคุณเป็นเพียงน้ำตาลทราย หากคุณยืนยันในการทำเช่นนั้นฉันขอแนะนำให้เขียนตัวประมวลผลล่วงหน้าของคุณเองเพื่อดำเนินการก่อนการปรับใช้ ควรเก็บให้evalห่างจากรหัสการผลิต
Ruud Helderman

0

Eval ไม่ใช่ความชั่วร้ายเพียงแค่ใช้ในทางที่ผิด

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

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

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

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

ตอนนี้เป็นตัวอย่างที่ดีของการใช้ eval เซิร์ฟเวอร์ของคุณกำลังอ่านไฟล์ swagger ที่คุณสร้างขึ้น หลาย params URL {myParam}ที่ถูกสร้างขึ้นในรูปแบบ ดังนั้นคุณจึงต้องการอ่าน URL แล้วแปลงเป็นสตริงแม่แบบโดยไม่ต้องทำการเปลี่ยนที่ซับซ้อนเพราะคุณมีจุดปลายจำนวนมาก ดังนั้นคุณอาจทำอะไรแบบนี้ หมายเหตุนี่เป็นตัวอย่างที่ง่ายมาก

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

-1

การสร้างรหัส ผมเพิ่งเขียนห้องสมุดที่เรียกว่าHyperbarsซึ่งเชื่อมช่องว่างระหว่างเสมือน 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()ไม่ใช่ปัญหาในสถานการณ์เช่นนี้เช่นกันเพราะคุณจะต้องตีความสตริงที่สร้างเพียงครั้งเดียวแล้วใช้เอาต์พุตที่สามารถเรียกใช้งานได้หลายครั้ง

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


"hyperscript ถูกสร้างเป็นสตริงก่อน (... )" เหมาะสมกว่าในการสร้างโค้ดทั้งหมดในเฟส build เขียนโค้ด hyperscript ที่ได้ไปยังไฟล์ executable (.js) แยกต่างหากจากนั้นปรับใช้ไฟล์นั้นเพื่อทดสอบและ การผลิต ฉันชอบวิธีที่คุณใช้การสร้างรหัส เป็นเพียงevalคำใบ้ว่าความรับผิดชอบบางส่วนที่อยู่ในเวลารวบรวมได้ถูกย้ายเข้าสู่รันไทม์
Ruud Helderman

-1

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


1
การใช้งานevalจำเป็นต้องมีความปลอดภัยจากการโจมตี XSS ซึ่งไม่ใช่เรื่องง่ายเสมอไป
Benjamin

-1

Eval มีประโยชน์สำหรับการสร้างรหัสเมื่อคุณไม่มีมาโคร

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


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

หากคุณสร้างรหัสจาวาสคริปต์และต้องการดำเนินการทันที (สมมติว่ามีประโยชน์ด้านประสิทธิภาพมากกว่าการตีความโดยตรง) นั่นจะเป็นกรณีการใช้งานสำหรับการประเมินผล
Erik Haliewicz

จุดดี; ผมเห็นตัวอย่างในบทความนี้เกี่ยวกับ Blockly ฉันตกตะลึงกับคำแนะนำของ Google evalเมื่อทางเลือก ( ฟังก์ชั่น ) นั้นเร็วกว่า ( ตามที่อธิบายใน MDN ) และเชื่อถือได้มากกว่า (ป้องกันข้อผิดพลาดที่คาดเดาไม่ได้โดยแยกระหว่างรหัสที่สร้างขึ้นและรหัส 'สนับสนุน' อื่น ๆ บนหน้าเว็บเดียวกัน)
Ruud Helderman

-5

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


4
อย่าสุ่มสี่สุ่มห้าใช้evalทาย เมื่อรับข้อมูล JSON จากแหล่งบุคคลที่สาม ดูJSON ป้องกันโดยไม่ต้องใส่เครื่องหมายคำพูดในคุณสมบัติ? สำหรับวิธีที่ถูกต้องในการแยกวิเคราะห์ "JSON โดยไม่มีชื่อคีย์ที่ยกมา"
Rob W

2
ถ้ามันไม่ได้ใช้คำพูดสองรอบชื่อคุณสมบัติมันอาจจะเป็นตัวแทนสตริงของตัวอักษรวัตถุ แต่มันไม่ได้เป็นJSON JSON กำหนดชื่อคุณสมบัติเป็น a stringและกำหนด a stringเป็นลำดับของอักขระ Unicode ที่เป็นศูนย์หรือมากกว่านั้นอยู่ในเครื่องหมายคำพูดคู่โดยใช้เครื่องหมายแบคสแลช
รหัสที่ไร้ประโยชน์

ดูบทความโดย Nikolas Zakas - "eval () ไม่ใช่ความชั่วร้ายเพียงแค่เข้าใจผิด" nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood
vitmalina

@vitmalina จากบทความของ Zakas: "สิ่งนี้อาจเป็นอันตรายได้หากคุณรับข้อมูลจากผู้ใช้และเรียกใช้ผ่านทาง eval () อย่างไรก็ตามหากข้อมูลของคุณไม่ได้มาจากผู้ใช้ นั่นคือปัญหา เมื่อรหัสของคุณเติบโตเกิน 'Hello World' evalสัดส่วนได้อย่างรวดเร็วเป็นไปไม่ได้ที่จะพิสูจน์ว่าคุณไม่ได้รั่วไหลเข้าของผู้ใช้เข้าสู่ ในเว็บแอปพลิเคชั่นที่มีผู้เช่าหลายคนที่จริงจังกับนักพัฒนาหลายสิบคนที่ทำงานบนฐานรหัสเดียวกันนี่เป็นสิ่งที่ยอมรับไม่ได้
Ruud Helderman
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.