เพราะเหตุใดคุณสมบัติที่คล้ายกันของ Eval จึงถือเป็นความชั่วร้ายในทางตรงกันข้ามกับคุณลักษณะที่เป็นอันตรายอื่น ๆ


51

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

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

  • กฎการเข้าถึงแบบกำหนดเองไปยังองค์ประกอบซอฟต์แวร์ (IIRC OpenERP มีวัตถุir.ruleที่สามารถใช้รหัสหลามแบบไดนามิก)
  • การคำนวณที่กำหนดเองและ / หรือเกณฑ์ (OpenERP มีฟิลด์เช่นนั้นเพื่ออนุญาตการคำนวณรหัสที่กำหนดเอง)
  • ตัวแยกวิเคราะห์รายงาน OpenERP (ใช่ฉันรู้ว่าฉันทำให้คุณประหลาดใจกับสิ่งที่ OpenERP ... แต่มันเป็นตัวอย่างหลักที่ฉันมี)
  • เอฟเฟกต์การสะกดในบางเกม RPG

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

อย่างไรก็ตาม eval เป็นสิ่งชั่วร้ายในวัฒนธรรมสมัยนิยม สิ่งที่ต้องการเจาะเข้าไปในระบบของคุณอยู่ในใจ

อย่างไรก็ตามมีฟังก์ชั่นอื่น ๆ ที่อาจเป็นอันตรายหากผู้ใช้เข้าถึง: ยกเลิกการเชื่อมโยงอ่านเขียน (ซีแมนทิกส์ไฟล์) การจัดสรรหน่วยความจำและเลขคณิตตัวชี้การเข้าถึงโมเดลฐานข้อมูล (แม้ว่าจะไม่พิจารณากรณี SQL-injectable)

ดังนั้นโดยทั่วไปแล้วส่วนใหญ่เวลาที่โค้ดใด ๆไม่ถูกเขียนอย่างถูกต้องหรือไม่ได้ดูอย่างถูกต้อง (ทรัพยากรผู้ใช้สภาพแวดล้อม ... ) รหัสนั้นชั่วร้ายและอาจนำไปสู่ผลกระทบทางเศรษฐกิจได้

แต่มีบางสิ่งที่พิเศษกับevalฟังก์ชั่น (โดยไม่คำนึงถึงภาษา)

คำถาม : มีข้อเท็จจริงทางประวัติศาสตร์สำหรับความกลัวนี้ที่กลายเป็นส่วนหนึ่งของวัฒนธรรมสมัยนิยมแทนที่จะให้ความสนใจแบบเดียวกันกับคุณลักษณะที่เป็นอันตรายอื่น ๆ หรือไม่?


11
ฉันไม่เห็นด้วยว่านี่กว้างเกินไปและเป็นหลักฐานที่ฉันนำเสนอคำตอบทั้งสี่ที่มีความยาวพอสมควร

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

13
ทำไมมันจึงกลายเป็นส่วนหนึ่งของวัฒนธรรมสมัยนิยมพร้อมความสนใจมากกว่าฟีเจอร์ที่เป็นอันตรายอื่น ๆ ? เพราะสัมผัสอักษรEVAL - ความชั่วร้ายเป็นเรื่องง่ายที่จะจำ
Bergi

5
การจัดสรรหน่วยความจำและเลขคณิตของตัวชี้ถูกมองว่าเป็นสิ่งชั่วร้าย
user253751

5
ควรสังเกตว่า OpenERP (ตอนนี้ Odoo) ไม่เพียง แต่เรียกevalว่ามันมีฟังก์ชั่นภายในที่เรียกว่าsafe_evalที่เตรียมสภาพแวดล้อมเพื่อป้องกันรหัสจากการทำสิ่งที่อันตราย อย่างไรก็ตามพบข้อบกพร่องเนื่องจาก Python เป็นภาษาที่ค่อนข้างยืดหยุ่นและควบคุมได้ยาก
AndréParamés

คำตอบ:


76

evalฟังก์ชั่นด้วยตัวเองไม่ได้เป็นความชั่วร้ายและมีจุดที่ลึกซึ้งที่ผมไม่เชื่อว่าคุณกำลังทำ:

การอนุญาตให้โปรแกรมเรียกใช้งานอินพุตผู้ใช้โดยพลการนั้นไม่ดี

ฉันเขียนโค้ดที่ใช้evalประเภทของฟังก์ชั่นและมันปลอดภัย: โปรแกรมและพารามิเตอร์นั้นมีการเข้ารหัสยาก บางครั้งไม่มีคุณสมบัติภาษาหรือไลบรารีที่จะทำสิ่งที่โปรแกรมต้องการและเรียกใช้คำสั่ง shell เป็นเส้นทางสั้น ๆ "ฉันต้องเขียนโค้ดให้เสร็จภายในสองสามชั่วโมง แต่การเขียน Java / .NET / PHP / โค้ดใด ๆ จะใช้เวลาสองวันหรือฉันสามารถทำได้evalภายในห้านาที"

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

มีข้อเท็จจริงทางประวัติศาสตร์สำหรับความกลัวนี้ที่กลายเป็นส่วนหนึ่งของวัฒนธรรมสมัยนิยมแทนที่จะให้ความสนใจแบบเดียวกันกับคุณสมบัติที่เป็นอันตรายอื่น ๆ หรือไม่?

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

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

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


2
คุณเท่านั้น :). แม้ว่าจะมีตัวอย่างที่รู้จักกันดีซึ่งเป็นส่วนหนึ่งของวัฒนธรรมนี้ฉันก็อยากจะเห็นมันในคำตอบ
Luis Masuelli

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

1
My IDE เป็นโปรแกรมที่ช่วยให้ฉัน - เป็นผู้ใช้ - เพื่อรันอินพุตโดยพลการ ฉันพบว่ามันมีประโยชน์มากกว่าที่จะไม่ดี
Den

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

3
@Den: มันเป็นสิ่งที่เรย์มอนด์เฉินสรุปว่าเป็น "อีกด้านหนึ่งของผนึก" คุณสามารถเรียกใช้แล้วrm -rf /ไม่จำเป็นต้องทำเช่นนั้นในแบบที่ซับซ้อนผ่าน IDE ปัญหาevalคือมันเปิดความสามารถนั้นให้กับนักแสดงจำนวนมากที่ไม่ควรมีความสามารถนั้น
MSalters

38

ส่วนหนึ่งของมันเป็นเพียงความแตกต่างกันนิดหน่อยที่ยาก มันง่ายที่จะพูดอย่างที่ไม่เคยใช้ goto เขตข้อมูลสาธารณะการแก้ไขสตริงสำหรับข้อความค้นหา sql หรือ eval ข้อความเหล่านี้ไม่ควรเข้าใจจริง ๆ ว่าคำว่าไม่มีเหตุผลใด ๆ ที่จะใช้มัน แต่การหลีกเลี่ยงสิ่งเหล่านี้ในฐานะกฎทั่วไปนั้นเป็นความคิดที่ดี

Eval เป็นกำลังใจอย่างมากเพราะมันรวมปัญหาที่พบบ่อยหลายประการ

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

ประการที่สองผู้เริ่มต้นมักใช้ eval เพื่อหลีกเลี่ยงโค้ดที่มีโครงสร้างไม่ดี รหัสเริ่มต้นอาจเขียนโค้ดที่มีลักษณะดังนี้:

x0 = "hello"
x1 = "world"
x2 = "how"
x3 = "are"
x4 = "you?"
for index in range(5):
   print eval("x" + index)

วิธีนี้ใช้งานได้ แต่เป็นวิธีที่ผิดจริงๆในการแก้ไขปัญหานี้ เห็นได้ชัดว่าการใช้รายการจะดีกว่า

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

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


13
กรณีที่สองของคุณมีความสำคัญมาก ในภาษาที่มีevalแต่ถูกคอมไพล์การประเมินสตริงเพื่อสร้างการอ้างอิงตัวแปรนั้นไม่สำคัญ เช่นถ้าvar x = 3; print(x)จะรวบรวม แล้วมีไม่จำเป็นต้องมีความรู้ใด ๆ เวลาทำงานว่าแหล่งที่มาใช้ชื่อ "X" เพื่อให้var x = 3; print(eval("x"))สามารถใช้งานได้จำเป็นต้องบันทึกการจับคู่นั้น นี่เป็นปัญหาจริง: ใน Common LISP (let ((x 3)) (print (eval 'x)))จะโยนข้อยกเว้นตัวแปรที่ไม่ถูกผูกไว้เนื่องจากตัวแปรคำ x ไม่มีการเชื่อมต่อใด ๆ ที่มีชื่อหลังจากโค้ดถูกคอมไพล์
Joshua Taylor

@JohnuaTaylor คุณหมายถึงเหตุผลที่สามไม่ใช่หรือ?
user253751

1
@ กลไกผมคิดว่าเขาอ้างถึงรหัสด้วยเหตุผลที่สอง แต่คุณถูกต้องมันเกี่ยวข้องกับเหตุผลที่สามอย่างแท้จริงนั่นคือประสิทธิภาพ
Winston Ewert

เห็นคำถามนี้ใช่ไหม ;)
jpmc26

@ jpmc26 ไม่ แต่ฉันเห็นมากมายเช่นนั้น
Winston Ewert

20

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

"ข้อผิดพลาดที่อาจเป็นอันตรายอื่น ๆ " อาจมีข้อ จำกัด ซึ่งหมายความว่าพวกมันสามารถ จำกัด อันตรายได้น้อยกว่าการใช้รหัสโดยอำเภอใจ


2
เพื่อประโยชน์ในการโต้แย้งการใช้พอยน์เตอร์ในทางที่ผิดก็นำไปสู่การใช้รหัสโดยอำเภอใจ แต่พอยน์เตอร์จะขมวดคิ้วน้อยกว่าevalมาก
Dmitry Grigoryev

12
@DmitryGrigoryev พวกเขาเป็นจริงเหรอ? นอกเหนือจากภาษาซีพลัสพลัสแล้วโดยทั่วไปแล้วพอยน์เตอร์จะได้รับอันตรายอย่างยิ่งและหลีกเลี่ยง ยกตัวอย่างเช่น C # สนับสนุนพอยน์เตอร์ แต่เป็นสิ่งสุดท้ายที่คุณลองหลังจากที่คุณหมดตัวเลือกอื่น ๆ (โดยทั่วไปสำหรับเหตุผลด้านประสิทธิภาพในการจัดการข้อมูล) ภาษาสมัยใหม่ส่วนใหญ่ไม่สนับสนุนตัวชี้ แม้แต่ C ++ เองก็กำลังเคลื่อนไปสู่ตัวชี้ "ปลอดภัย" ซึ่งพยายามที่จะบรรเทาปัญหาเกี่ยวกับตัวชี้ตามอำเภอใจ (เช่นการใช้รายการ / อาร์เรย์จริงแทนการใช้พอยน์เตอร์, ใช้ safe_ptr, การส่งผ่านการอ้างอิง ... )
Luaan

2
@DmitryGrigoryev: คุณสามารถให้การอ้างอิงสำหรับใครบอกว่าตัวชี้มีอันตรายน้อยกว่า eval?
JacquesB


1
@JacquesB ใช่; มันเป็นเรื่องตลก (ฉันคาดว่ารอยยิ้มจะทำให้ชัดเจนพอ) OP ทำประโยคนั้นไม่ใช่ฉันดังนั้นคุณควรถามเขาเพื่อพิสูจน์
Dmitry Grigoryev

15

มีเหตุผลเชิงปฏิบัติและเหตุผลทางทฤษฎี

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

เหตุผลทางทฤษฎีมากขึ้นคือถ้ามันยากที่จะเขียนรหัสที่ดีก็ยิ่งยากที่จะเขียนรหัสที่เขียนรหัสที่ดี ไม่ว่าคุณจะใช้ eval หรือสร้างคำสั่ง SQL โดยการรวมสตริงเข้าด้วยกันหรือเขียนคอมไพเลอร์ JIT สิ่งที่คุณพยายามมักจะยากกว่าที่คุณคาดไว้ ความเป็นไปได้ในการฉีดโค้ดที่เป็นอันตรายเป็นส่วนสำคัญของปัญหา แต่นอกเหนือจากนั้นโดยทั่วไปยากที่จะทราบว่ารหัสของคุณถูกต้องหรือไม่หากรหัสของคุณไม่มีอยู่จนกว่าจะถึงรันไทม์ ดังนั้นคำแนะนำที่ง่ายที่สุดคือการทำให้สิ่งต่าง ๆ ง่ายขึ้นสำหรับตัวคุณเอง: "ใช้เคียวรี SQL ที่กำหนดพารามิเตอร์", "อย่าใช้ eval"

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


1
ของหลักสูตรการสร้างรหัสรันไทม์สามารถทำได้อย่างถูกต้องและ EVAL สามารถเป็นประโยชน์ เช่นฉันมักใช้ eval สำหรับ metaprogramming / macro-like stuff โดยเฉพาะเมื่อฉันต้องการประสิทธิภาพมากกว่า OOP ที่“ สะอาดกว่า” หรือวิธีแก้ปัญหาที่ใช้งานได้ รหัสผลลัพธ์มักจะดีกว่าและง่ายกว่าเพราะมีจำนวนแผ่นน้อยกว่า อย่างไรก็ตามการตระหนักถึงปัญหาต่าง ๆ ที่เกี่ยวข้องกับการ sandboxing, การหลบหลีกกลไก, การฉีดโค้ด, การกำหนดขอบเขต, การรายงานข้อผิดพลาด, การปรับให้เหมาะสมเป็นต้นนั้นจำเป็นต้องมีระดับความสามารถในการใช้ภาษาที่ไม่คล่องแคล่ว
amon

11

ไม่ไม่มีข้อเท็จจริงทางประวัติศาสตร์ที่ชัดเจน

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

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

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


1
... หรือมีอินพุตที่มาจากแหล่งที่เชื่อถือได้เช่นไฟล์คำจำกัดความการสะกดสำหรับเกม
user253751

3
@immibis แต่ถ้าอินพุตถูกกำหนดไว้ล่วงหน้าและทดสอบอย่างปลอดภัยว่าทำไมใช้ eval เมื่อมันสามารถรวมอยู่ในแหล่งที่มาของระบบ?
Jules

3
@immibis - เพราะไม่มีใครเคยแฮ็กไฟล์เกม ...
Telastyn

2
... นั่นไม่ใช่สิ่งที่ "ทัวริงสมบูรณ์" หมายถึง (ทัวริงสมบูรณ์เป็นหนึ่งขั้นตอนจากที่ไม่เกี่ยวข้องกับการคำนวณในโลกแห่งความจริง)
Leushenko

1
@Telastyn: โปรแกรม Javascript ใดที่ไม่สามารถทำได้ หรือแม้แต่โปรแกรม C ++ Javascript ทำงานภายในแซนด์บ็อกซ์ (เบราว์เซอร์) ซึ่งอยู่ในแซนด์บ็อกซ์อื่น (วงแหวน 3 ใน x86 พูด) เวกเตอร์ขัดจังหวะอยู่นอกแซนด์บ็อกซ์นั้นภายใต้การควบคุม OS และกล่องทรายด้านนอกนั้นวงแหวน 3 นั้นบังคับใช้กับ CPU
MSalters

6

ฉันคิดว่ามันเดือดลงไปด้านต่อไปนี้:

  • ความจำเป็น
  • (เตรียมพร้อม) การใช้งาน
  • เข้าไป
  • ตรวจสอบได้
  • การโจมตีแบบหลายขั้นตอน

ความจำเป็น

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

(ต่อ)

ขอขอบคุณที่ซื้อมัน อย่างที่คุณเห็นมันทำงานตรงตามที่ฉันสัญญา โอ้คุณต้องการเปิดภาพหรือไม่ ไม่คุณไม่สามารถ ฉันจะไม่ใช้readวิธีการนี้เนื่องจากมันค่อนข้างไม่ปลอดภัย ประหยัด? writeไม่ฉันจะไม่ใช้

สิ่งที่ฉันพยายามจะพูดคือ: คุณต้องอ่าน / เขียนสำหรับเครื่องมือพื้นฐานเกือบ เช่นเดียวกับการจัดเก็บคะแนนสูงของเกมที่ยอดเยี่ยมของคุณ

หากไม่มีการอ่าน / เขียนโปรแกรมแก้ไขภาพของคุณจะไร้ประโยชน์ โดยไม่eval? ฉันจะเขียนปลั๊กอินที่กำหนดเองสำหรับคุณ!

(เตรียมพร้อม) การใช้งาน

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

อย่างไรก็ตามในกรณีอื่น ๆ สตริงสำหรับreadอยู่ภายใต้การควบคุมโปรแกรมเมอร์ (อาจ hardcoded?) readในกรณีที่ว่าก็คือแทบจะไม่ชั่วร้ายที่จะใช้

เข้าไป

evalตอนนี้ตัวอย่างง่ายๆอีกโดยใช้

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

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

ตรวจสอบได้

ฉันคิดว่าอีกแง่มุมหนึ่งที่สำคัญคือความง่ายในการตรวจสอบอินพุตของผู้ใช้

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

ผู้ใช้ป้อนข้อมูลในการโทรเขียน? เหมือนกัน!

การฉีด SQL? เพียงแค่หลบหนีหรือใช้ข้อความค้นหาที่เป็นพารามิเตอร์และคุณจะปลอดภัย

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

การโจมตีแบบหลายขั้นตอน

ตอนนี้ทุกครั้งที่คุณใช้อินพุตของผู้ใช้คุณต้องชั่งน้ำหนักประโยชน์ของการใช้กับอันตราย ปกป้องการใช้งานให้มากที่สุด

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

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

(การโจมตีแบบหลายขั้นตอนเดียวกันสามารถทำได้ด้วยการฉีด SQL แทน XSS หรือเขียนไฟล์โดยพลการแทนรหัสปฏิบัติการแทนการใช้eval)


2
"คุณสามารถทำงานหนักมาก แต่มันยากจริง ๆ (ถ้าเป็นไปไม่ได้) เพื่อให้ทำงานได้อย่างปลอดภัย" - มันเป็นไปไม่ได้ หลักฐานง่ายๆแทนการพยายามที่จะคิดออกว่ารหัสผู้ใช้ที่มีให้คือ "ปลอดภัย" หรือไม่เพียงแค่พยายามที่จะคิดออกบางสิ่งบางอย่างมากง่ายมากและดูวิธีการที่ยากที่มีอยู่แล้ว: ไม่รหัสที่ได้รับจากการหยุดชะงักของผู้ใช้?
Jörg W Mittag

2
@ JörgWMittag: ให้โปรแกรมที่ฉันเขียนด้วย Coq และฉันจะพิสูจน์มัน
AndréParamés

1
@ JörgWMittag: เห็นด้วย ขึ้นอยู่กับภาษาและขอบเขตของอินพุตของผู้ใช้ eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder")เป็นอย่างดีอาจจะเป็น การตรวจสอบว่าอินพุตเป็นตัวอักษรและตัวเลขเป็นไปได้ นอกจากนี้ 'ไม่หยุด' เป็นมุมฉากเพื่อ 'แก้ไข / เข้าถึงสถานะที่ไม่ควรสัมผัส' และ 'ทำวิธี cal ไม่ควรเรียก'
Sjoerd Job Postmus

3
@ JörgWMittagเป็นไปไม่ได้ที่จะพิสูจน์ว่าโปรแกรมที่กำหนดไว้จะไม่ทำอะไรเลย แต่ก็เป็นไปไม่ได้ที่จะกำหนดชุดโปรแกรมที่ จำกัด ซึ่งคุณสามารถพิสูจน์ได้อย่างอนุรักษ์นิยมและบังคับให้โปรแกรมอินพุตเป็นสมาชิกของชุดนั้น
user253751

3

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

สำหรับภาษาที่ตีความฉันสามารถใช้สถานะล่ามซึ่งเป็นเรื่องง่าย แต่เมื่อใช้ร่วมกับคอมไพเลอร์ JIT มันยังคงเพิ่มความซับซ้อนอย่างมาก

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

โค้ดชนิดนี้มีแนวโน้มที่จะบอบบางซ้ำไปซ้ำมาได้ยากและในเวลาเดียวกันก็มีข้อ จำกัด ในการเพิ่มประสิทธิภาพในคอมไพเลอร์ JIT

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


"เพื่อให้ฟีเจอร์นี้ทำงานได้ทั้งหมดหมายความว่าฉันต้องใช้เลเยอร์การสะท้อนรอบ ๆ เพื่อให้สามารถเข้าถึงสถานะภายในของโปรแกรมทั้งหมด" - ไม่เพียงแค่ชิ้นส่วนที่คุณต้องการส่งผลกระทบ ในกรณีของ OpenERP / Odoo รหัสที่ถูกวิวัฒนาการจะมีเพียงการเข้าถึงตัวแปรและฟังก์ชั่นในจำนวนที่ จำกัด ที่สามารถเรียกใช้ได้เท่านั้น
AndréParamés

1

ฉันปฏิเสธหลักฐานที่evalถือว่าเลวร้ายยิ่งกว่าตัวชี้เลขคณิตหรืออันตรายกว่าหน่วยความจำโดยตรงและการเข้าถึงระบบไฟล์ ฉันไม่รู้จักนักพัฒนาที่มีเหตุผลและใครจะเชื่อ นอกจากนี้ภาษาที่รองรับการเข้าถึงตัวชี้ทางคณิตศาสตร์ / หน่วยความจำโดยตรงไม่สนับสนุนevalและในทางกลับกันดังนั้นฉันจึงทราบว่าการเปรียบเทียบเช่นนั้นจะเกี่ยวข้องกันบ่อยเพียงใด

แต่evalอาจเป็นช่องโหว่ที่รู้จักกันดีกว่าด้วยเหตุผลง่ายๆว่า JavaScript ได้รับการสนับสนุน JavaScript เป็นภาษาที่ใช้ Sandbox โดยไม่มีหน่วยความจำโดยตรงหรือการเข้าถึงระบบไฟล์ดังนั้นจึงไม่มีช่องโหว่เหล่านี้ที่ทำให้เกิดจุดอ่อนในการนำภาษาไปใช้ Evalดังนั้นจึงเป็นหนึ่งในคุณสมบัติที่อันตรายที่สุดของภาษาเนื่องจากเปิดโอกาสในการใช้รหัสโดยอำเภอใจ ฉันเชื่อว่านักพัฒนาซอฟต์แวร์จำนวนมากพัฒนาใน JavaScript มากกว่าใน C / C ++ ดังนั้นevalสิ่งสำคัญที่ควรระวังมากกว่าการบัฟเฟอร์ล้นสำหรับนักพัฒนาส่วนใหญ่


0

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

ต้องบอกว่ามีภาษาที่ใช้ eval เหมาะสม Perl อยู่ในใจ อย่างไรก็ตามโดยส่วนตัวแล้วฉันพบว่ามันไม่ค่อยมีความต้องการในภาษาอื่น ๆ ที่ทันสมัยกว่าซึ่งสนับสนุนการจัดการข้อยกเว้นแบบมีโครงสร้าง


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

คำถามในความคิดของฉันตั้งอยู่บนพื้นฐานของหลักฐานที่ผิดดังนั้นฉันจึงตอบเป็นอย่างนั้น
user1751825

0

ฉันคิดว่าคุณครอบคลุมค่อนข้างดีในส่วนต่อไปนี้ของคำถามของคุณ (เน้นฉัน):

พวกเขาใช้งานได้ดีตราบใดที่มีการใช้อย่างเหมาะสม

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

จะมีคนที่ต้องการผลักดันขอบเขตและค้นหาช่องโหว่ด้านความปลอดภัยอยู่เสมอบางคนดีและแย่

ในส่วนของข้อเท็จจริงทางประวัติศาสตร์นั้นevalฟังก์ชั่นการพิมพ์เป็นหลักอนุญาตให้มีการใช้รหัส Arbitraryซึ่งก่อนหน้านี้ถูกใช้ในเว็บ CMS ยอดนิยม Joomla! . ด้วยJoomla! เปิดให้บริการมากกว่า 2.5 ล้านแห่งทั่วโลกนั่นเป็นความเสียหายที่อาจเกิดขึ้นไม่เพียง แต่กับผู้เข้าชมเว็บไซต์เหล่านั้นเท่านั้น แต่ยังรวมถึงโครงสร้างพื้นฐานที่โฮสต์อยู่และชื่อเสียงของเว็บไซต์ / บริษัท ที่ถูกเอาเปรียบ

Joomla! ตัวอย่างอาจเป็นแบบง่าย ๆ แต่เป็นสิ่งที่ถูกบันทึกไว้


0

มีเหตุผลที่ดีบางประการที่ทำให้ไม่สนับสนุนการใช้eval(แม้ว่าบางรายการจะใช้เฉพาะกับบางภาษา)

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

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


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

0

ในสังคมแห่งจิตใจของมินสกีบทที่ 6.4 เขากล่าว

มีวิธีหนึ่งที่จิตใจจะดูตัวเองและยังคงติดตามสิ่งที่เกิดขึ้น แบ่งสมองออกเป็นสองส่วน A และ B เชื่อมต่ออินพุตและเอาต์พุตของ A-brain กับโลกแห่งความจริงเพื่อให้สามารถรับรู้ได้ว่าเกิดอะไรขึ้นที่นั่น แต่อย่าเชื่อมโยง B-brain กับโลกภายนอกเลย เชื่อมต่อมันแทนเพื่อให้สมอง A เป็นโลกของ B-brain!

เมื่อโปรแกรมหนึ่ง (B) เขียนโปรแกรมอื่น (A) โปรแกรมจะทำงานเป็นเมตาโปรแกรม สาระสำคัญของ B คือโปรแกรม A

มีโปรแกรม C นั่นคือหนึ่งในหัวของคุณที่เขียนโปรแกรม B

อันตรายคืออาจมีใครบางคน (C ') ที่มีเจตนาร้ายที่สามารถเข้าไปแทรกแซงในกระบวนการนี้ดังนั้นคุณจึงได้รับสิ่งต่าง ๆ เช่น SQL-injection

ความท้าทายคือการทำให้ซอฟต์แวร์ฉลาดขึ้นโดยไม่ทำให้อันตรายมากขึ้น


สอง upvotes และสอง downvote ดูเหมือนว่านี่อาจจะกระทบประสาท
Mike Dunlavey

0

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

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

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