อะไรทำให้“ การใช้งานไม่เหมาะสม” ของคุณสมบัติ javascript Eval? [ปิด]


13

Eval เป็นคุณสมบัติทางภาษาที่มีการถกเถียงกันอย่างมาก Douglas Crockford แบนออกปฏิเสธมัน ฉันสงสัยว่าความเสี่ยงเฉพาะใดที่ Eval นำมาใช้ ตามคำถามนี้ , Improper use of eval opens up your code for injection attacks.

อะไรคือการใช้คำสั่ง Eval ที่ไม่เหมาะสมและพวกเขาเปิดรูโหว่อะไร

คำตอบ:


31

ย้อนกลับไปตอนที่ฉันติดตั้งเอ็นจิ้น JScript ฉันสนับสนุนให้มีการพิมพ์EVAL IS EVILแต่มันน่าเศร้าที่เราไม่เคยไปไหนมาไหน

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

สำหรับความคิดเพิ่มเติมในหลอดเลือดดำนี้ดูบทความของฉันในปี 2003 ในหัวข้อ:

ความชั่วร้ายทั่วไป:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

ความชั่วร้ายโจมตีฉีด:

http://blogs.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


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

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

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

4

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

ในฐานะที่เป็นตัวอย่างที่ไร้สาระและไร้ประโยชน์เครื่องคิดเลข JavaScript อย่างง่าย:

textbox1.value = eval(textbox2.value);

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


1

มีบางสิ่งที่เป็นไปไม่ได้ที่จะทำใน JS โดยไม่ต้องมีฟังก์ชั่น EVAL-ชอบ ( eval, Functionและบางทีอาจจะมากกว่า)

ใช้applyตัวอย่างเช่น มันใช้งานง่ายเมื่อใช้กับการเรียกใช้ฟังก์ชันทั่วไป:

foo.apply(null, [a, b, c])

แต่คุณจะทำสิ่งนี้กับวัตถุที่คุณสร้างด้วยไวยากรณ์ใหม่ได้อย่างไร

new Foo.apply(null, [a, b, c]) ไม่ทำงานหรือทำแบบฟอร์มที่คล้ายกัน

แต่คุณสามารถหลีกเลี่ยงข้อ จำกัด นี้ผ่านevalหรือFunction(ฉันใช้Functionในตัวอย่างนี้):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

ตัวอย่าง:

Foo.New.apply(null, [a, b, c]);

แน่นอนว่าคุณสามารถสร้างฟังก์ชั่นที่Function.prototype.Newใช้ด้วยตนเองแต่ไม่เพียง แต่จะให้ความหมายที่ชัดเจนและ clunky มัน (โดยนิยาม) จะต้องมีขอบเขต Functionอนุญาตให้โค้ดทำงานกับอาร์กิวเมนต์จำนวนเท่าใดก็ได้


2
จริง แต่คำถามของ OP คือ " อะไรคือการใช้คำสั่ง Eval ที่ไม่เหมาะสมอะไรบ้างและพวกเขาเปิดรูโหว่ด้านความปลอดภัยอะไร? " ไม่ใช่ " อะไรคือการใช้ที่ดีeval()? "
Ross Patterson

1
@RossPatterson: เดาฉันส่วนใหญ่ดูที่ชื่อคำถาม haha
Thomas Eding

ยัง +1 สำหรับการค้นหาการใช้งานที่ดีสำหรับคุณสมบัติภาษาที่ไม่ดี :-)
Ross Patterson

1

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

สิ่งที่เป็นอันตรายที่อาจเกิดขึ้นได้ในกรณีนี้ก็อาจเกิดขึ้นได้โดยผู้พัฒนาเปิดเครื่องมือ F12 ของพวกเขา


0

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

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

ชุดย่อยของ Javascript ที่มีข้อ จำกัด นี้ไม่อนุญาตให้ฉันฉีดโค้ดที่สร้างจากรันไทม์ลงในรหัสที่คอมไพล์เมื่อคอมไพล์แล้ว

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


0

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

ที่ถูกกล่าวว่าฉันสนุกกับการใช้evalสำหรับสองสิ่ง (แม้ว่าอาจจะมีทางเลือกที่ดีกว่าและดีกว่าความชั่วร้ายน้อยกว่า):

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

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

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


-3

ฉันมีสถานการณ์ที่ eval ดูเหมือนว่าจะไปประเมินสตริงและกลับตัวแปรที่มีอยู่ที่มีชื่อเป็นสตริง

ฉันมีหลายตาราง: table1ResultsTable, table2ResultsTable, tableNResultsTable ฉันมีตัวแปรตั้งค่าด้วยชื่อเดียวกันนั่นคือ jQuery datatable object ฉันใช้สิ่งเหล่านี้เพื่อตั้งค่าตารางและเรียกใช้ฟังก์ชั่น DataTable jQuery กับพวกเขา

แต่ละตารางมี class = "resultsTable" ที่ได้รับมอบหมาย ตอนนี้ฉันต้องรับตัวแปรเมื่อตารางถูกคลิก ฉันทำสิ่งนี้:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

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


1
ทำไมคุณต้องใช้ eval ID ควรเป็นสตริงธรรมดาไม่ใช่รหัส อย่างไรก็ตามevent.target.parentElement.parentElement.parentElementมันช่างน่ากลัว นอกจากนี้ฉันคาดหวังว่าการเรียกใช้ eval เพื่อสร้างข้อผิดพลาด "อ้างอิงข้อผิดพลาด: [id] ไม่ได้กำหนดไว้" ยกเว้นว่าคุณตั้งใจใช้รหัสที่ประเมินได้ (ซึ่งแตกหักผิดและอาจทำให้สิ่งแปลก ๆ เกิดขึ้นถ้าคุณจบ สร้างรหัสที่ซ้ำกันขึ้นไป)
Brian

บางทีฉันไม่ได้ทำให้ตัวเองชัดเจน id คือสตริงธรรมดา มันเป็นรหัสของตารางที่ถูกคลิก ฉันยังมีตัวแปรวัตถุ (ตั้งค่าด้วยวิธี jQuery datatable () อ้างอิงตารางเดียวกัน) ด้วยชื่อเดียวกันกับ id ฉันพยายามรับตัวแปรนั้นเพื่อเข้าถึงฟังก์ชั่นของมัน (อันที่จริงแล้วเพื่อเพิ่มคลาส "row_selected" ให้กับแถวที่เลือก) เมื่อตารางถูกคลิก อย่างไรก็ตามตั้งแต่ที่ฉันเขียนสิ่งนี้ฉันได้รับการปรับปรุงให้ดีขึ้น ฉันเพิ่งใส่การอ้างอิงวัตถุทั้งหมดในอาร์เรย์ตั้งชื่อองค์ประกอบเหมือนกับ id และเสียบสตริง id ลงไปเพื่อรับการอ้างอิงวัตถุ
BobRodes

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

1
บางทีฉันไม่ได้ทำให้ตัวเองชัดเจน หากคุณเรียกใช้ eval บนสตริงธรรมดา (เช่นที่ไม่ใช่ JS) คุณจะพบข้อยกเว้น ดังนั้นการใช้ eval ของคุณจึงไม่สมเหตุสมผล หากคุณกำลังสร้างตัวแปรวัตถุที่มีชื่อเดียวกันกับรหัสรหัสของคุณจะใช้งานได้ แต่จะทำให้ฉันเสีย ฉันต้องการสร้างตัวแปรโดยใช้document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(ไม่ต้องบอกว่ายอดเยี่ยม แต่อย่างใดดีกว่า eval) ดังที่ Eric Lippert ชี้ให้เห็นว่า "ทุกวัตถุใน JScript เป็นตารางค้นหาแล้ว"
ไบรอัน

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