ตัวเลือก PHP 'cgi.fix_pathinfo' อันตรายจริง ๆ กับ Nginx + PHP-FPM หรือไม่


51

มีการจำนวนมากของการพูดคุยเกี่ยวกับปัญหาด้านความปลอดภัยเมื่อเทียบกับตัวเลือก PHP ใช้กับ Nginx (ปกติ PHP-FPM, CGI เร็ว) cgi.fix_pathinfo

ดังนั้นไฟล์กำหนดค่า nginx เริ่มต้นที่ใช้ในการพูด:

# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

อย่างไรก็ตามตอนนี้วิกิ Nginx "เป็นทางการ" ระบุว่า PATH_INFO สามารถจัดการได้อย่างถูกต้องโดยไม่ปิดใช้งานตัวเลือก PHP ด้านบน แล้วอะไรล่ะ

คำถาม

  • คุณช่วยอธิบายได้อย่างชัดเจนว่าcgi.fix_pathinfoทำอะไร? ( doc อย่างเป็นทางการเพิ่งพูดว่า : "สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ PATH_INFO ดูรายละเอียด CGI")
  • PHP จะทำอะไรกับตัวแปรPATH_INFOและสิ่งเหล่านี้SCRIPT_FILENAME?
  • ทำไมและอย่างไรจึงจะเป็นอันตรายกับ Nginx ( ตัวอย่างโดยละเอียด )
  • ปัญหายังคงมีอยู่ในโปรแกรมเหล่านี้รุ่นล่าสุดหรือไม่?
  • Apache มีช่องโหว่หรือไม่

ฉันพยายามเข้าใจปัญหาในแต่ละขั้นตอน ตัวอย่างเช่นฉันไม่เข้าใจว่าทำไมการใช้ซ็อกเก็ต Unix ของ php-fpm สามารถหลีกเลี่ยงปัญหานี้ได้


1
คุณอาจตอบคำถามของคุณเองโดยทำความเข้าใจความแตกต่างระหว่าง PATH_INFO และPATH_TRANSLATED
จิโอวานนี่ Tirloni

คำตอบ:


79

TL; DR - การแก้ไข (ซึ่งคุณอาจไม่จำเป็นต้องใช้) คือ VERY SIMPLE และท้ายคำตอบนี้

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

  • คำถามแรกควรเป็น "ธุรกิจข้อมูลเส้นทางนี้คืออะไร"

    • ข้อมูลพา ธ เป็นข้อมูลหลังจากสคริปต์ใน URI (ควรเริ่มต้นด้วยเครื่องหมายสแลช แต่จะสิ้นสุดก่อนอาร์กิวเมนต์อาร์กิวเมนต์ซึ่งเริ่มต้นด้วย a ?) ย่อหน้าสุดท้ายในส่วนภาพรวมของบทความ Wikipedia เกี่ยวกับ CGIสรุปได้อย่างดี ด้านล่างPATH_INFOคือ "/ This / IS / PATH / INFO":

      http://example.com/path/to/script.php/THIS/IS/PATH/INFO?query_args=foo

  • คำถามต่อไปของคุณควรเป็น: "PHP กำหนดได้อย่างไรPATH_INFOและSCRIPT_FILENAMEเป็นอย่างไร"

    • PHP เวอร์ชันก่อนหน้านี้ไร้เดียงสาและในทางเทคนิคก็ไม่ได้รับการสนับสนุนPATH_INFOดังนั้นสิ่งที่ควรจะเป็นPATH_INFOถูกรวมเข้าด้วยกันSCRIPT_FILENAMEซึ่งใช่ถูกใช้งานไม่ได้ในหลายกรณี ฉันไม่มี PHP เวอร์ชันเก่าพอที่จะทดสอบ แต่ฉันเชื่อว่ามันSCRIPT_FILENAMEเป็น shebang ทั้งหมด: "/path/to/script.php/THIS/IS/PATH/INFO" ในตัวอย่างด้านบน (นำหน้าด้วย docroot ตามปกติ)
    • ด้วยการเปิดใช้งาน cgi.fix_pathinfo PHP จะค้นหา "/ This / IS / PATH / INFO" อย่างถูกต้องสำหรับตัวอย่างข้างต้นและใส่ลงในPATH_INFOและSCRIPT_FILENAMEรับส่วนที่ชี้ไปที่สคริปต์ที่ร้องขอ (นำหน้าด้วย docroot ของหลักสูตร)
    • หมายเหตุ: เมื่อ PHP รองรับการใช้งานจริงPATH_INFOพวกเขาจะต้องเพิ่มการตั้งค่าการกำหนดค่าสำหรับคุณสมบัติใหม่เพื่อให้ผู้ใช้งานสคริปต์ที่ขึ้นอยู่กับพฤติกรรมเก่าสามารถใช้งาน PHP เวอร์ชันใหม่ได้ นั่นเป็นเหตุผลที่มีแม้กระทั่งสวิตช์การกำหนดค่าสำหรับมัน มันควรจะติดตั้งในตัว (พร้อมกับพฤติกรรม "อันตราย") ตั้งแต่เริ่มต้น
  • แต่ PHP รู้ได้อย่างไรว่าส่วนใดเป็นสคริปต์และข้อมูลเส้นทางคืออะไร? เกิดอะไรขึ้นถ้า URI เป็นเช่น:

    http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo

    • นั่นอาจเป็นคำถามที่ซับซ้อนในบางสภาพแวดล้อม สิ่งที่เกิดขึ้นใน PHP คือพบส่วนแรกของเส้นทาง URI ที่ไม่ตรงกับสิ่งใดภายใต้ docroot ของเซิร์ฟเวอร์ สำหรับตัวอย่างนี้จะเห็นว่าในเซิร์ฟเวอร์ของคุณคุณไม่มี "/docroot/path/to/script.php/THIS" แต่แน่นอนที่สุดคุณมี "/docroot/path/to/script.php" ดังนั้นตอนนี้SCRIPT_FILENAMEได้รับการพิจารณาและPATH_INFOได้รับส่วนที่เหลือ
    • ดังนั้นตอนนี้ตัวอย่างที่ดีของอันตรายที่มีรายละเอียดอย่างดีในเอกสาร Nginx และในคำตอบของ Hrvoje Špoljar (คุณไม่สามารถยุ่งเกี่ยวกับตัวอย่างที่ชัดเจนเช่นนี้) ได้ชัดเจนยิ่งขึ้น: ตัวอย่างของ Hrvoje (" http: // example" com / foo.jpg / nonexistent.php "), PHP เห็นไฟล์ใน docroot ของคุณ" /foo.jpg "แต่ไม่เห็นสิ่งที่เรียกว่า" /foo.jpg/nonexistent.php "ดังนั้นSCRIPT_FILENAMEรับ" /foo.jpg " (อีกครั้งนำหน้าด้วย docroot) และPATH_INFOรับ "/ noonexistent.php"
  • เหตุใดจึงเป็นอันตรายอย่างไรและควรชัดเจนว่า:

    • เว็บเซิร์ฟเวอร์ไม่ใช่ความผิด แต่เป็นเพียงการพร็อกซี URI ถึง PHP เท่านั้นซึ่งพบว่า "foo.jpg" มีเนื้อหา PHP จริง ๆ ดังนั้นจึงดำเนินการ (ตอนนี้คุณได้รับ pwned แล้ว!) นี่ไม่ใช่เฉพาะ Nginx ต่อ se
  • จริงปัญหาคือการที่คุณปล่อยให้เนื้อหาที่ไม่น่าเชื่อถือถูกอัปโหลดที่ใดที่หนึ่งโดยไม่ต้องฆ่าเชื้อและคุณอนุญาตการร้องขอโดยพลการอื่น ๆ ไปยังสถานที่เดียวกันซึ่ง PHP อย่างมีความสุขรันเมื่อมันสามารถ
  • Nginx และ Apache สามารถสร้างหรือกำหนดค่าเพื่อป้องกันการร้องขอโดยใช้กลอุบายนี้และมีความอุดมสมบูรณ์ของตัวอย่างสำหรับวิธีการทำที่รวมทั้งในคำตอบของ user2372674 บทความในบล็อกนี้อธิบายถึงปัญหาได้เป็นอย่างดี แต่ไม่มีวิธีแก้ไขที่เหมาะสม

  • อย่างไรก็ตามทางออกที่ดีที่สุดคือตรวจสอบให้แน่ใจว่า PHP-FPM ได้รับการกำหนดค่าอย่างถูกต้องเพื่อไม่ให้รันไฟล์เว้นแต่ว่าลงท้ายด้วย ".php" เป็นที่น่าสังเกตว่า PHP-FPM เวอร์ชันล่าสุด (~ 5.3.9 +?) มีสิ่งนี้เป็นค่าเริ่มต้นดังนั้นความเสี่ยงนี้จึงไม่เป็นปัญหาอีกต่อไป

การแก้ไขปัญหา

หากคุณมี PHP-FPM เวอร์ชันล่าสุด (~ 5.3.9 +?) คุณต้องไม่ทำอะไรเลยเนื่องจากพฤติกรรมด้านความปลอดภัยด้านล่างนี้เป็นค่าเริ่มต้นแล้ว

มิฉะนั้นค้นหาwww.confไฟล์ของ php-fpm (อาจ/etc/php-fpm.d/www.confขึ้นอยู่กับระบบของคุณ) ตรวจสอบให้แน่ใจว่าคุณมีสิ่งนี้:

security.limit_extensions = .php

อีกครั้งนั่นเป็นค่าเริ่มต้นในหลาย ๆ ที่ในวันนี้

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


5
คำตอบที่ดี! ชี้แจง: ถ้าเป็นคุณจะพูด, PHP กำหนดสิ่งที่SCRIPT_FILENAMEเป็นเหตุผลที่จะมีfastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;เส้นของฉันnginxconf? มันแทนที่ความพยายามของ PHP ในการค้นพบคุณค่าของSCRIPT_FILENAMEมันหรือไม่?
Totor

มีฟังก์ชั่นเพื่อรับค่าsecurity.limit_extensionsหรือไม่? ฉันพยายามphpinfo(), ini_get(security.limit_extensions)และini_get_all()ไม่ประสบความสำเร็จ
elbowlobstercowstand

ขอบคุณถ้า PHP-FPM รุ่นล่าสุด (~ 5.3.9 +?) มีสิ่งนี้เป็นค่าเริ่มต้นทำไม php7.1 ต้องการมัน? หรือนี้บทความผิดหรือเปล่า?
Yevgeniy Afanasyev

14

โดยพื้นฐานแล้วคุณสามารถอัปโหลดไฟล์ด้วยรหัส php ชื่อเช่น 'foo.jpg' ไปยังเว็บเซิร์ฟเวอร์ จากนั้นขอให้มันเหมือนhttp: //domain.tld/foo.jpg/nonexistent.phpและเว็บเซิร์ฟเวอร์สแต็กจะพูดผิดพลาดว่าโอ้; นี่คือ PHP; ฉันต้องการประมวลผลสิ่งนี้มันจะล้มเหลวในการค้นหา foo.jpg / nonexistent.php ดังนั้นมันจะกลับไปที่ foo.jpg และประมวลผล foo.jpg เป็นรหัส php นั่นเป็นอันตรายเพราะมันเปิดระบบเพื่อการบุกรุกที่ง่ายมาก แอปพลิเคชั่นเว็บใด ๆ ที่อนุญาตให้อัพโหลดภาพเป็นเครื่องมือในการอัพโหลดแบ็คดอร์

เกี่ยวกับการใช้ php-fpm กับซ็อกเก็ตยูนิกซ์เพื่อหลีกเลี่ยง; IMO มันจะไม่แก้ปัญหา


คุณทำซ้ำสิ่งที่อ่านบนลิงค์ที่ฉันให้ไว้เท่านั้น คุณไม่ได้อธิบายกลไกที่แท้จริง คำตอบของคุณต้องการมูลค่าเพิ่ม IMHO
Totor

6
อาจเป็นจริง แต่ชื่อของคุณมีคำถามและคำตอบสำหรับคำถามนั้นอยู่ในคำตอบของฉัน หากคุณต้องการมันอย่างชัดเจน; ใช่มันอันตราย อันตรายมาก.
Hrvoje Špoljar

1 / คำตอบของฉันไม่ได้ จำกัด อยู่ที่ชื่อ: มันมีเนื้อหา 2 / user109322ได้พิสูจน์แล้วว่าคุณผิด: ค่าสิ่งที่ใช้สำหรับcgi.fix_pathinfoเป็นไม่เป็นอันตรายเพราะ conf เริ่มต้นของphp-fpmความปลอดภัย (มันจะรันไฟล์ที่มี.phpนามสกุล)
Totor

2

ในNginx wikiเป็นมาตรการรักษาความปลอดภัย

if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

รวมอยู่ในบล็อกตำแหน่ง ในบทเรียนอื่น ๆ

try_files $uri =404;

ถูกใช้ซึ่งควรทำเช่นเดียวกัน แต่สามารถให้ปัญหาตาม Nginx wiki ด้วยตัวเลือกเหล่านี้cgi.fix_pathinfo=1ไม่ควรเป็นปัญหาอีกต่อไป ข้อมูลเพิ่มเติมสามารถพบได้ที่นี่

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