ประเมินความชั่วร้ายใน php เมื่อใด


84

ในช่วงหลายปีที่ผ่านมาฉันได้พัฒนา php ฉันได้ยินมาตลอดว่าการใช้ไฟล์ eval()เป็นสิ่งชั่วร้าย

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

// $type is the result of an SQL statement
// e.g. SHOW COLUMNS FROM a_table LIKE 'a_column';
// hence you can be pretty sure about the consistency
// of your string
$type = "enum('a','b','c')";

// possibility one
$type_1 = preg_replace('#^enum\s*\(\s*\'|\'\s*\)\s*$#', '', $type);
$result = preg_split('#\'\s*,\s*\'#', $type_1);

// possibility two
eval('$result = '.preg_replace('#^enum#','array', $type).';');

2
eval เป็นสิ่งที่ชั่วร้ายเสมอมีวิธีที่ดีกว่าในการเขียนโค้ดเสมอเนื่องจาก PHP เปิดตัวฟังก์ชันที่ไม่ระบุตัวตน ในกรณีนี้ฉันจะใช้$result = array(); preg_replace_callback('#^enum\s*\(\s*\'|\'\s*\)\s*$#', function($m) use($result) { $result[] = $m[1]; }, $type);
Geoffrey

จริงๆแล้วฉันคิดว่าปัญหาหลักของ php ไม่ใช่ภาษา แต่เป็นคนที่ใช้ คำตอบที่ถูกต้องสามข้อสำหรับคำถามนี้ (ของ thomasrutter, braincracking และของฉัน) ทั้งหมดได้รับการโหวตโดยไม่ต้องมีใครโต้แย้ง ในทางกลับกันคำตอบหนึ่งอ้างว่า "บางครั้ง eval () เป็นวิธีเดียว / วิธีแก้ปัญหาที่ถูกต้อง" โดยไม่มีตัวอย่างหรือคำอธิบายและได้รับคะแนนสูงสุดสำหรับมัน ...
Francois Bourgeois

คำตอบ:


134

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

ปัญหาหลักของ eval () คือ:

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

ปัญหาหลักในการใช้ eval () จริงมีเพียงปัญหาเดียว:

  • นักพัฒนาที่ไม่มีประสบการณ์ซึ่งใช้งานโดยไม่ได้รับการพิจารณาอย่างเพียงพอ

ตามกฎทั่วไปฉันมักจะทำตามสิ่งนี้:

  1. บางครั้ง eval () เป็นทางออกเดียว / ทางเลือกที่เหมาะสม
  2. ส่วนใหญ่ควรลองอย่างอื่น
  3. หากไม่แน่ใจให้ไปที่ 2
  4. อย่างอื่นระวังให้มาก

4
สิ่งนี้สามารถถูก refactored เพื่อหลีกเลี่ยง eval () ได้เช่นกันโดยเฉพาะอย่างยิ่งถ้า $ className อยู่ในรายการที่อนุญาตพิเศษซึ่งจะต้องเป็นไปเพื่อความบันเทิงในการใช้ eval () แม้ว่าข่าวดีก็คือ ณ 5.3 $ foo :: bar () นั้นใช้ได้
rojoca

@rojoca: คุณช่วยยกตัวอย่างวิธีการทำโดยไม่ต้อง eval () ใน PHP 5.2 ได้ไหม?
Michał Rudnicki

30
ฉันไม่แน่ใจว่านับเป็น eval หรือไม่ แต่ $ result = call_user_func (array ('Foo', 'bar')); ทำงานเหมือนมีเสน่ห์
Ionuț G. Stan

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

อินพุตที่ไม่ปลอดภัยสามารถหลีกเลี่ยงได้
thepowerlies

40

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

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

ตามหลักทั่วไป: ลืมมันไปซะ เมื่อ eval คือคำตอบที่คุณตั้งคำถามผิด! ;-)


6
บางครั้งการประเมินคือคำตอบ เราทำงานเกี่ยวกับแอปพลิเคชันเกมออนไลน์และเป็นการยากมากที่จะหลีกเลี่ยงการหลบเลี่ยงที่นั่นเนื่องจากความสัมพันธ์ที่ซับซ้อนมากระหว่างหน่วยงาน ... แต่ IMHO ใน 90% ของกรณีที่ eval ไม่ใช่คำตอบ
เจ็ท

19
ฉันอยากรู้อยากเห็นสถานการณ์ที่มีเพียง eval เท่านั้นที่เป็นคำตอบ
Ionuț G. Stan

2
@Ionut G. Stan ทริกเกอร์แบบกำหนดเองที่จัดเก็บฐานข้อมูลสำหรับวัตถุ / เอนทิตี?
Kuroki Kaze

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

4
@ คริสเตียน: คุณควรเขียนตัวอย่างก่อน (ใช้pastebin.comและวางลิงก์ที่นี่) ซึ่งคุณคิดว่าการหลีกเลี่ยงการใช้eval()เป็นไปไม่ได้นี่เป็นแนวทางที่ดีกว่า หลายคนบอกว่าeval()เป็นสิ่งที่หลีกเลี่ยงไม่ได้ในบางกรณี แต่พวกเขาไม่ได้กล่าวถึงตัวอย่างใด ๆ ที่เราสามารถโต้แย้งได้ - วิธีนี้การถกเถียงนี้ไม่สมเหตุสมผล ดังนั้นขอให้คนที่บอกว่าeval()หนีไม่พ้นพิสูจน์ก่อน!
Sk8erPeter

19

ประเมินว่า "ชั่วร้าย" เท่าเทียมกันตลอดเวลา

ถ้าคุณเห็นว่า eval () เป็นความชั่วร้ายมันก็ชั่วตลอดเวลา มันไม่ได้สูญเสียความชั่วร้ายไปอย่างน่าอัศจรรย์ขึ้นอยู่กับบริบท

ในความคิดของฉันถามว่า "ประเมิน () ไม่ชั่วเมื่อไหร่" ดูเหมือนจะบอกเป็นนัยว่าข้อเสียของการใช้ eval () หายไปอย่างน่าอัศจรรย์ในบางบริบท

โดยทั่วไปการใช้ eval () เป็นความคิดที่ไม่ดีเนื่องจากจะลดความสามารถในการอ่านโค้ดความสามารถในการคาดคะเนเส้นทางรหัส (และผลกระทบด้านความปลอดภัยที่เป็นไปได้) ก่อนรันไทม์และด้วยเหตุนี้จึงทำให้ความสามารถในการวิเคราะห์และดีบักโค้ดลดลง การใช้ eval () ยังสามารถป้องกันไม่ให้โค้ดที่ประเมินและโค้ดที่อยู่รอบ ๆ ถูกปรับให้เหมาะสมโดย opcode cache เช่น Zend Opcache ที่รวมอยู่ใน PHP 5.5 ขึ้นไปหรือโดยคอมไพเลอร์ JIT เช่นใน HHVM

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

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


2
คุณทำให้โปรแกรมเมอร์ตกนรก
คริสเตียน

1
"นอกจากนี้ไม่มีสถานการณ์ใดที่จำเป็นอย่างยิ่งที่จะต้องใช้ eval ()" - แล้วถ้าฉันต้องการรันโค้ดที่เก็บไว้ในฐานข้อมูลตามตัวอย่างที่ระบุในเอกสาร PHP ล่ะ?
Yarin

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

13
มันเพิ่มเวกเตอร์การโจมตีอื่น - การฉีด SQL สามารถเรียกใช้โค้ด PHP โดยพลการบนเว็บเซิร์ฟเวอร์ ต้องใช้ eval () ไม่สามารถปรับให้เหมาะสมโดยแคช bytecode มันละเมิดหลักการแยกรหัสและข้อมูลของคุณ สามารถทำให้แอปพลิเคชันของคุณพกพาได้น้อยลง - ในการอัปเดต / แก้ไข PHP คุณต้องอัปเดตฐานข้อมูลด้วย
thomasrutter

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

15

ในกรณีนี้ eval น่าจะปลอดภัยเพียงพอตราบใดที่ผู้ใช้ไม่สามารถสร้างคอลัมน์ตามอำเภอใจในตารางได้

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

$json = str_replace(array(
    'enum', '(', ')', "'"), array)
    '',     '[', ']', "'"), $type);
$result = json_decode($json);

การแสดงออกปกติน่าจะเป็นวิธีที่ชัดเจนที่สุด คุณสามารถใช้นิพจน์ทั่วไปเดียวเพื่อแยกค่าทั้งหมดจากสตริงนี้:

$extract_regex = '/
    (?<=,|enum\()   # Match strings that follow either a comma, or the string "enum("...
    \'      # ...then the opening quote mark...
    (.*?)       # ...and capture anything...
    \'      # ...up to the closing quote mark...
    /x';
preg_match_all($extract_regex, $type, $matches);
$result = $matches[1];

1
แม้ว่าสิ่งนี้จะไม่ตอบคำถามต่อคำถาม แต่นี่เป็นคำตอบที่ดีมากสำหรับคำถาม: อะไรคือวิธีที่ดีที่สุดในการแยกวิเคราะห์ enum () …ขอบคุณ;)
Pierre Spring

13

eval() ช้า แต่ฉันจะไม่เรียกมันว่าชั่วร้าย

เป็นการใช้งานที่ไม่ดีที่เราทำซึ่งอาจนำไปสู่การแทรกโค้ดและเป็นสิ่งชั่วร้าย

ตัวอย่างง่ายๆ:

$_GET = 'echo 5 + 5 * 2;';
eval($_GET); // 15

ตัวอย่างที่เป็นอันตราย:

$_GET = 'system("reboot");';
eval($_GET); // oops

ฉันขอแนะนำให้คุณไม่ใช้ eval()แต่ถ้าคุณทำโปรดตรวจสอบให้แน่ใจว่าคุณได้ตรวจสอบความถูกต้อง / อนุญาตให้ป้อนข้อมูลทั้งหมดแล้ว


12

เมื่อคุณใช้ข้อมูลแปลกปลอม (เช่นอินพุตของผู้ใช้) ภายใน eval

ในตัวอย่างของคุณด้านบนนี่ไม่ใช่ปัญหา


7

ฉันจะขโมยเนื้อหาที่นี่อย่างโจ่งแจ้ง:

  1. การประเมินโดยธรรมชาติมักจะเป็นปัญหาด้านความปลอดภัย

  2. นอกจากความกังวลด้านความปลอดภัยแล้วการประเมินยังมีปัญหาของการทำงานช้าอย่างไม่น่าเชื่อ ในการทดสอบ PHP 4.3.10 ของฉันช้ากว่าโค้ดปกติ 10 เท่าและช้ากว่า 28 เท่าใน PHP 5.1 beta1

blog.joshuaeichorn.com: การใช้-eval-in-php


5

eval()เป็นเสมอความชั่วร้าย

  • ด้วยเหตุผลด้านความปลอดภัย
  • ด้วยเหตุผลด้านประสิทธิภาพ
  • ด้วยเหตุผลด้านความสามารถในการอ่าน / การนำกลับมาใช้ใหม่
  • ด้วยเหตุผล IDE / เครื่องมือ
  • สำหรับเหตุผลในการดีบัก
  • มีวิธีที่ดีกว่าเสมอ

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

3
ตรงไปตรงมาฉันคิดว่าคำตอบของ@MichałRudnickiบอกว่าดีที่สุด อย่าเข้าใจฉันผิดเมื่อใดก็ตามที่ฉันถามคำถาม ( ตัวเอง ) และคำตอบคือeval()ทันทีที่ฉันคิดว่าฉันถามคำถามผิด ไม่ค่อยเป็นคำตอบที่ "ถูกต้อง" แต่หากต้องการปกปิดความชั่วร้ายมักจะไม่ถูกต้องเสมอไป
Dan Lugg

ถ้าฉันต้องการจัดเก็บรหัสในฐานข้อมูล? ฉันจะดำเนินการได้อย่างไร
Konstantin XFlash Stratigenas

@KonstantinXFlashStratigenas คุณควรถามตัวเองว่าทำไมคุณถึงเก็บรหัสปฏิบัติการไว้ในฐานข้อมูล ฐานข้อมูลมีไว้สำหรับข้อมูลที่เกิดจากรหัสของคุณไม่ใช่รหัสของคุณ อย่างน้อยที่สุดคุณกำลังเพิ่มเวกเตอร์การโจมตี
Jack B

4

ฉันจะให้ความสำคัญกับคนที่ดูแลรหัสของคุณด้วย

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


4

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

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

และแน่นอน PHP ของคุณดูเหมือน Perl;)

มีปัญหาสำคัญสองประการเกี่ยวกับ eval () (เป็นสถานการณ์ "ฉีดยาโจมตี"):

1) อาจก่อให้เกิดอันตราย 2) อาจเกิดความผิดพลาด

และสิ่งที่มากกว่าสังคมมากกว่าเทคนิค:

3) มันจะล่อลวงให้ผู้คนใช้มันอย่างไม่เหมาะสมเป็นทางลัดที่อื่น

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

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

ฉันขอแนะนำว่าในตัวอย่างนี้คุณกำลังเขียนโค้ดโดยบังเอิญมากกว่าการเข้ารหัสพฤติกรรม ใช่คำสั่ง SQL enum (และคุณแน่ใจหรือไม่ว่า enum ของฟิลด์นั้น - คุณเรียกฟิลด์ที่ถูกต้องของตารางที่ถูกต้องของฐานข้อมูลเวอร์ชันที่ถูกต้องหรือไม่มันตอบจริงหรือไม่) ดูเหมือนไวยากรณ์การประกาศอาร์เรย์ใน PHP แต่ฉันขอแนะนำสิ่งที่คุณต้องการทำจริงๆไม่ใช่หาเส้นทางที่สั้นที่สุดจากอินพุตไปยังเอาต์พุต แต่จะจัดการกับงานที่ระบุ:

  • ระบุว่าคุณมี enum
  • แยกรายชื่อด้านใน
  • แกะค่ารายการ

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

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

ด้วย preg_version ผลลัพธ์ที่แย่ที่สุดของคุณน่าจะเป็น $ result = null โดยรุ่น eval จะไม่ทราบเวอร์ชันที่แย่ที่สุด แต่อย่างน้อยก็เกิดข้อขัดข้อง


3

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


3

PHP ขอแนะนำให้คุณเขียนโค้ดของคุณในลักษณะที่สามารถเรียกใช้งานผ่าน call_user_func แทนที่จะทำแบบชัดเจน


2

อีกสาเหตุหนึ่งevalคือความชั่วร้ายคือไม่สามารถแคชโดย PHP bytecode แคชเช่น eAccelertor หรือ ACP


2

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


2

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

ฉันทำนายว่าคุณจะมีปัญหาร้ายแรงในไม่ช้า ...

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

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

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


เหตุผลของ"ว่าคุณพยายามระมัดระวังการรักษาความปลอดภัยรหัสของคุณเกี่ยวกับคุณลักษณะ X ไม่มีแฮกเกอร์สมาร์ทเสมอหนึ่งก้าวไปข้างหน้า ..."สามารถนำไปใช้เทคนิคอื่น ๆ ที่ไม่ได้เป็นเพียง X eval== ดังนั้นสำหรับคุณลักษณะใด ๆ X: X จึงเป็นรากฐานของการประเมินทั้งหมด ... เอ้อ ... ชั่วร้ายดังนั้นควรเลิกเขียนโปรแกรมโดยสิ้นเชิง (ดังนั้นการดึงพรมจากแฮกเกอร์โง่ ๆ เหล่านั้น แต่ก็ยังชิงไหวชิงพริบในที่สุด)
Sz.

"ไม่มีการใช้งานที่ดีอย่างแน่นอนสำหรับฟังก์ชันที่สูงเกินไปเช่น eval" -> ใครก็ตามที่สามารถใช้คำอย่าง "อย่างแน่นอน" ไม่ว่าจะเป็นมือใหม่ในการเขียนโปรแกรมหรือโปรแกรมเมอร์ที่ไม่ดี
unity100

2

นี่คือวิธีการเรียกใช้โค้ด PHP ที่ดึงมาจากฐานข้อมูลโดยไม่ต้องใช้ eval อนุญาตสำหรับฟังก์ชันและข้อยกเว้นทั้งหมดในขอบเขต:

$rowId=1;  //database row id
$code="echo 'hello'; echo '\nThis is a test\n'; echo date(\"Y-m-d\");"; //php code pulled from database

$func="func{$rowId}";

file_put_contents('/tmp/tempFunction.php',"<?php\nfunction $func() {\n global \$rowId;\n$code\n}\n".chr(63).">");

include '/tmp/tempFunction.php';
call_user_func($func);
unlink ('/tmp/tempFunction.php');

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


ดูเหมือนเป็นการตอบสนองต่อคำตอบ กรุณาโพสต์ไว้เมื่อคุณทำได้
rfornal

1

ฉันเคยใช้ eval () มามาก แต่ฉันพบว่าส่วนใหญ่คุณไม่ต้องใช้ eval เพื่อทำเทคนิค คุณมี call_user_func () และ call_user_func_array () ใน PHP ดีพอที่จะเรียกวิธีใด ๆ แบบคงที่และแบบไดนามิก

ในการดำเนินการโทรแบบคงที่จะสร้างการเรียกกลับของคุณเป็นอาร์เรย์ ('class_name', 'method_name') หรือแม้กระทั่งเป็นสตริงธรรมดาเช่น 'class_name :: method_name' ในการดำเนินการเรียกแบบไดนามิกให้ใช้สไตล์การโทรกลับอาร์เรย์ ($ object, 'method')

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


0

นอกเหนือจากข้อกังวลด้านความปลอดภัยแล้วไม่สามารถรวบรวม eval (), ปรับให้เหมาะสมหรือแคช opcode ได้ดังนั้นมันจะช้า - ช้ากว่าโค้ด php ปกติ ดังนั้นจึงไม่มีประสิทธิภาพที่จะใช้ eval แม้ว่าจะไม่ทำให้มันชั่วร้ายก็ตาม ( gotoเป็นความชั่วevalเป็นเพียงการปฏิบัติที่ไม่ดี / รหัสที่มีกลิ่นเหม็น / น่าเกลียด)


evalได้รับคะแนนความชั่วร้ายต่ำกว่าgoto? ตรงข้ามกันวันไหน?
JLRishe

เป็นเพียงการที่ฉันไม่พอใจกับ php devs สำหรับการใช้งานจริงgotoใน 5.3
Aron Cederholm

1
ไม่ถึงgoto-fobians: มีเครื่องมือและมีช่างฝีมือที่ใช้มัน (หรือไม่) มันเป็นไม่เคยเครื่องมือที่จะทำให้ดูเป็นมืออาชีพเหมือนคนงี่เง่าเมื่อทำผิดพลาด แต่ไม่สามารถที่จะใช้เครื่องมือที่เหมาะสม (ต้อง) แต่มันเป็นเครื่องมือในการตำหนิเสมอ ...
Sz.

0

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

สำหรับฉันส่วนที่แย่ที่สุดคือการลดความสามารถในการบำรุงรักษาโค้ดของคุณ:

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