Tùy chọn PHP 'cgi.fix_pathinfo' có thực sự nguy hiểm với Nginx + PHP-FPM không?


51

Hiện đã có một rất nhiều của nói về một vấn đề an ninh liên quan đến các cgi.fix_pathinfotùy chọn PHP sử dụng với Nginx (thường là PHP-FPM, CGI nhanh).

Do đó, tệp cấu hình nginx mặc định được sử dụng để nói:

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

Tuy nhiên, bây giờ, wiki Nginx "chính thức" tuyên bố rằng PATH_INFO có thể được xử lý chính xác mà không vô hiệu hóa tùy chọn PHP ở trên. Vậy thì sao?

Câu hỏi

  • Bạn có thể giải thích rõ ràng những gì cgi.fix_pathinfolàm? ( tài liệu chính thức chỉ nói : "Để biết thêm thông tin về PATH_INFO, hãy xem thông số kỹ thuật CGI")
  • PHP sẽ thực sự làm gì với những điều này PATH_INFOSCRIPT_FILENAMEcác biến?
  • Tại sao và làm thế nào nó có thể nguy hiểm với Nginx? ( ví dụ chi tiết )
  • Có phải vấn đề vẫn tồn tại trong các phiên bản gần đây của các chương trình này?
  • Apache có dễ bị tổn thương không?

Tôi đang cố gắng để hiểu vấn đề ở mỗi bước. Ví dụ, tôi không hiểu tại sao sử dụng ổ cắm Unix php-fpm có thể tránh được vấn đề này.


1
Bạn có thể trả lời câu hỏi của riêng bạn bằng cách tìm hiểu sự khác biệt giữa PATH_INFO và PATH_TRANSLATED: blogs.msdn.com/b/david.wang/archive/2005/08/04/...
Giovanni Tirloni

Câu trả lời:


79

TL; DR - bản sửa lỗi (mà bạn thậm chí không cần) là RẤT ĐƠN GIẢN và ở cuối câu trả lời này.

Tôi sẽ cố gắng giải quyết các câu hỏi cụ thể của bạn, nhưng sự hiểu lầm của bạn về PATH_INFO là gì khiến bản thân các câu hỏi hơi sai.

  • Câu hỏi đầu tiên phải là "Kinh doanh thông tin đường dẫn này là gì?"

  • Câu hỏi tiếp theo của bạn nên là: "Làm thế nào để PHP xác định cái gì PATH_INFOSCRIPT_FILENAMElà gì?"

    • Các phiên bản trước của PHP là ngây thơ và về mặt kỹ thuật thậm chí không hỗ trợ PATH_INFO, do đó, những gì được cho là PATH_INFOđã được đưa vào SCRIPT_FILENAME, trong đó, bị hỏng trong nhiều trường hợp. Tôi không có phiên bản PHP đủ cũ để thử nghiệm, nhưng tôi tin rằng nó đã thấy SCRIPT_FILENAMEtoàn bộ shebang: "/path/to/script.php/THIS/IS/PATH/INFO" trong ví dụ trên (có tiền tố là các docroot như bình thường).
    • Với cgi.fix_pathinfo được bật, PHP bây giờ tìm thấy chính xác "/ NÀY / IS / PATH / INFO" cho ví dụ trên và đặt nó vào PATH_INFOSCRIPT_FILENAMEchỉ lấy phần được chỉ ra cho tập lệnh được yêu cầu (dĩ nhiên là tiền tố với docroot).
    • Lưu ý: khi PHP thực sự hỗ trợ PATH_INFO, họ phải thêm cài đặt cấu hình cho tính năng mới để mọi người chạy các tập lệnh phụ thuộc vào hành vi cũ có thể chạy các phiên bản PHP mới. Đó là lý do tại sao thậm chí có một công tắc cấu hình cho nó. Nó nên được tích hợp sẵn (với hành vi "nguy hiểm") ngay từ đầu.
  • Nhưng làm thế nào để PHP biết phần nào là tập lệnh và thông tin đường dẫn của nó là gì? Điều gì xảy ra nếu URI giống như:

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

    • Đó có thể là một câu hỏi phức tạp trong một số môi trường. Điều xảy ra trong PHP là nó tìm thấy phần đầu tiên của đường dẫn URI không tương ứng với bất cứ thứ gì trong docroot của máy chủ. Trong ví dụ này, nó thấy rằng trên máy chủ của bạn, bạn không có "/docroot/path/to/script.php/THIS" nhưng bạn chắc chắn có "/docroot/path/to/script.php" vì vậy bây giờ SCRIPT_FILENAMEđã được xác định và PATH_INFOnhận phần còn lại.
    • Vì vậy, bây giờ ví dụ điển hình về sự nguy hiểm được chi tiết độc đáo trong các tài liệu Nginx và trong câu trả lời của Hrvoje Špoljar (bạn không thể cầu kỳ về một ví dụ rõ ràng như vậy) càng trở nên rõ ràng hơn: ví dụ của Hrvoje (ví dụ http: //. com / foo.jpg / nonexistent.php "), PHP thấy một tệp trên docroot của bạn" /foo.jpg "nhưng nó không thấy bất cứ thứ gì gọi là" /foo.jpg/nonexistent.php "vì vậy SCRIPT_FILENAMEđược" /foo.jpg " (một lần nữa, tiền tố với docroot) và PATH_INFOđược "/nonexistent.php".
  • Tại sao và làm thế nào nó có thể nguy hiểm bây giờ nên rõ ràng:

    • Máy chủ web thực sự không có lỗi - nó chỉ đơn thuần là ủy quyền URI cho PHP, mà vô tình thấy rằng "foo.jpg" thực sự có chứa nội dung PHP, vì vậy nó thực thi nó (bây giờ bạn đã bị xóa!). Điều này KHÔNG đặc biệt đối với Nginx mỗi se.
  • Các REAL vấn đề là bạn hãy để nội dung không tin cậy được tải lên ở đâu đó mà không vệ sinh và bạn cho phép các yêu cầu tùy ý khác để cùng một vị trí, mà PHP vui vẻ thực hiện khi nó có thể.
  • Nginx và Apache có thể được xây dựng hoặc định cấu hình để ngăn chặn các yêu cầu sử dụng mánh khóe này và có rất nhiều ví dụ về cách thực hiện điều đó, bao gồm cả câu trả lời của user2372674 . Bài viết blog này giải thích vấn đề độc đáo, nhưng nó thiếu giải pháp đúng.

  • Tuy nhiên, giải pháp tốt nhất là chỉ cần đảm bảo PHP-FPM được cấu hình đúng để nó sẽ không bao giờ thực thi một tệp trừ khi kết thúc bằng ".php". Điều đáng chú ý là các phiên bản gần đây của PHP-FPM (~ 5.3.9 +?) Có mặc định này, vì vậy mối nguy hiểm này không còn là vấn đề nữa.

Giải pháp

Nếu bạn có phiên bản PHP-FPM gần đây (~ 5.3.9 +?), Thì bạn không cần phải làm gì, vì hành vi an toàn dưới đây đã là mặc định.

Mặt khác, tìm www.conftệp của php-fpm (có thể /etc/php-fpm.d/www.conf, tùy thuộc vào hệ thống của bạn). Hãy chắc chắn rằng bạn có điều này:

security.limit_extensions = .php

Một lần nữa, đó là mặc định ở nhiều nơi trong những ngày này.

Lưu ý rằng điều này không ngăn kẻ tấn công tải lên tệp ".php" vào thư mục tải lên WordPress và thực hiện bằng cách sử dụng cùng một kỹ thuật. Bạn vẫn cần phải có bảo mật tốt cho các ứng dụng của bạn.


5
Câu trả lời tốt đẹp! Để làm rõ: nếu, như bạn nói, PHP xác định cái gì SCRIPT_FILENAMElà, tại sao lại có một fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;dòng trong nginxconf của tôi ? Liệu nó có ghi đè lên nỗ lực của PHP để tự khám phá giá trị của SCRIPT_FILENAMEnó không?
Toto

Có một chức năng để có được giá trị của security.limit_extensions? Tôi đã cố gắng phpinfo(), ini_get(security.limit_extensions)ini_get_all()không có thành công.
khuỷu tay khuỷu tay

Cảm ơn bạn, nếu các phiên bản gần đây của PHP-FPM (~ 5.3.9 +?) Có mặc định này, tại sao php7.1 cần nó? Hoặc là này sai bài viết?
Yevgeniy Afanasyev

14

Về bản chất, không có điều này, bạn có thể tải tệp có mã php có tên như 'foo.jpg' lên máy chủ web; sau đó yêu cầu nó như http: //domain.tld/foo.jpg/nonexistent.php và ngăn xếp máy chủ web sẽ nói nhầm oh; đây là một PHP; Tôi cần xử lý việc này, nó sẽ không tìm thấy foo.jpg / nonexistent.php vì vậy nó sẽ quay trở lại foo.jpg và xử lý foo.jpg dưới dạng mã php. Điều đó là nguy hiểm vì nó mở hệ thống để xâm nhập rất dễ dàng; bất kỳ ứng dụng web nào cho phép tải lên hình ảnh chẳng hạn trở thành công cụ để tải lên cửa sau.

Về việc sử dụng php-fpm với ổ cắm unix để tránh nó; IMO nó sẽ không giải quyết vấn đề.


Bạn chỉ lặp lại những gì có thể được đọc trên các liên kết tôi cung cấp. Bạn không giải thích cơ chế thực sự. Câu trả lời của bạn cần thêm giá trị IMHO.
Típ

6
Điều đó có thể đúng, nhưng tiêu đề của bạn có câu hỏi và câu trả lời cho câu hỏi đó nằm trong câu trả lời của tôi. Nếu bạn muốn nó rõ ràng; vâng, nó nguy hiểm; rất nguy hiểm.
Hrvoje Špoljar

1 / Câu trả lời của tôi không giới hạn ở tiêu đề của nó: nó có một cơ thể. 2 / user109322 đã chứng minh bạn sai: bất kỳ giá trị nào được sử dụng cgi.fix_pathinfođều không nguy hiểm, vì conf mặc định php-fpmlà an toàn (nó sẽ chỉ thực thi các tệp có .phpphần mở rộng).
Toto

2

Trong wiki Nginx là biện pháp bảo mật

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

được bao gồm trong khối vị trí. Trong các hướng dẫn khác

try_files $uri =404;

được sử dụng, nên làm như vậy, nhưng có thể gây ra vấn đề theo wiki Nginx. Với các tùy chọn này, cgi.fix_pathinfo=1không còn là vấn đề nữa. Thông tin thêm có thể được tìm thấy ở đây .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.