PHP-FPM Security: cách cô lập và giới hạn PHP trên Web Server

PHP-FPM Security: pool isolation, user/group, Unix socket/TCP exposure, clear_env, security.limit_extensions, resource limits và validation.

PHP-FPM Security - cô lập và giới hạn PHP trên Web Server

PHP-FPM Security là việc cấu hình FastCGI Process Manager để PHP chạy với đúng user/group, đúng pool, đúng socket/network boundary, environment tối thiểu và giới hạn resource phù hợp với từng application. Mục tiêu không phải “khóa PHP càng nhiều càng tốt”, mà là giảm blast radius khi một ứng dụng hoặc plugin bị compromise và tránh để một pool PHP có thể đọc/ghi tài nguyên của ứng dụng khác ngoài nhu cầu.

PHP manual cho biết FPM hỗ trợ pool configuration riêng, clear_env mặc định bật để loại bỏ environment variable ngoài những biến được khai báo, và security.limit_extensions dùng để giới hạn extension script FPM cho phép xử lý. Manual cũng cảnh báo không nên bind FPM ra địa chỉ có thể truy cập toàn Internet vì FastCGI có thể truyền các PHP configuration option. Vì vậy FPM hardening phải bắt đầu từ process identity + listen boundary + filesystem permission.

Pool identity và listen boundary

1. Hiểu mô hình master process và pool

PHP-FPM có master process quản nhiều worker pool. Mỗi pool có thể có user, group, socket, process manager và PHP settings riêng. Đây là boundary hữu ích khi host nhiều application.

Trước khi sửa, inventory:

php-fpm -tt 2>&1
ps -eo user,group,pid,cmd | grep '[p]hp-fpm'
ss -lntup | grep php
ss -lxnp | grep php

Tên binary/service thay đổi theo distro và PHP version, ví dụ php8.3-fpm. Dùng command phù hợp với package thực tế.

2. Tách pool theo application khi cần isolation

Nếu nhiều website chạy chung một pool/user như www-data, compromise một app có thể đọc/ghi file app khác nếu filesystem permission cho phép. Pool riêng cho từng application giúp gắn user/group, socket, log và resource limit riêng.

Pool isolation không phải container/sandbox hoàn chỉnh. Kernel, filesystem mount, root process và shared services vẫn là trust boundary chung.

3. Chạy worker bằng user/group tối thiểu

Trong pool:

[example]
user = app_example
group = app_example

User này chỉ nên có quyền đọc code và ghi các path ứng dụng thực sự cần như uploads/cache/session tùy framework. Không cho PHP worker sở hữu toàn bộ server config hoặc shared deployment tree nếu không cần.

Xem File Permission & Ownership trên Web Server để thiết kế owner/write path.

4. Unix socket hay TCP socket?

Nếu web server và FPM cùng host, Unix socket thường giúp boundary dễ quản lý bằng filesystem owner/mode. Ví dụ:

listen = /run/php/example.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Đây chỉ là ví dụ; web server user/group và distro layout có thể khác. Socket mode phải đủ cho Nginx/Apache kết nối nhưng không mở rộng cho local user không cần thiết.

5. Nếu dùng TCP, tuyệt đối kiểm soát exposure

FPM có thể listen trên IP:port. PHP manual cảnh báo FPM không nên bind vào địa chỉ worldwide-accessible. Nếu dùng TCP, ưu tiên loopback/private network theo architecture, kết hợp host/cloud firewall.

listen.allowed_clients có thể giới hạn FastCGI client khi dùng TCP; nó không áp dụng theo cùng cách cho Unix socket. Không xem đây là thay thế firewall/network segmentation.

Environment, script execution và PHP policy

6. clear_env giúp giảm rò rỉ environment

PHP-FPM manual ghi clear_env mặc định là yes: environment worker được làm sạch trước khi các biến được khai báo cho pool được thêm vào. Đây là behavior an toàn cho nhiều deployment.

Nếu ứng dụng phụ thuộc environment variable, khai báo rõ hoặc dùng secret injection mechanism phù hợp thay vì clear_env = no một cách rộng rãi.

7. security.limit_extensions

Directive này giới hạn extension script FPM cho phép parse. Manual nêu đây là cách giảm rủi ro web-server misconfiguration làm PHP thực thi file extension ngoài intended set.

Ví dụ định hướng:

security.limit_extensions = .php

Nhưng một số ứng dụng có use case khác. Trước change cần inventory endpoint/file type và test.

8. PHP settings nên khóa ở đâu?

FPM pool hỗ trợ php_admin_value và php_admin_flag; những giá trị dạng admin không thể bị override bằng ini_set(). Điều này hữu ích với baseline như error logging hoặc resource setting cần enforce ở pool.

Không dùng disable_functions như sandbox chính. Application compromise có thể có nhiều đường khác để đọc/ghi dữ liệu hoặc gọi service; least privilege ở OS/pool/filesystem mạnh hơn.

9. open_basedir có phải security boundary?

open_basedir có thể giảm một số file access của PHP và hữu ích defense-in-depth, nhưng không nên xem nó là isolation boundary tương đương container hoặc Unix permission. Nó cũng có compatibility/performance implications tùy app.

Thiết kế chính vẫn phải là pool user riêng và filesystem permission đúng.

Resource, observability và web-server integration

10. Process manager và resource limit

FPM hỗ trợ pm modes và các giá trị như child count/request lifecycle. Số worker quá cao có thể cạn RAM; quá thấp gây queue và timeout. Không có con số “hardening chuẩn” cho mọi server.

Baseline nên đo memory mỗi worker, request concurrency, upstream timeout và headroom của host trước khi đặt limit.

11. pm.max_requests hữu ích khi nào?

Giới hạn số request một child xử lý trước khi respawn có thể giúp giảm ảnh hưởng memory leak của extension/application, nhưng không sửa nguyên nhân gốc. Giá trị cần dựa vào workload và monitoring.

12. Slowlog và request timeout

FPM có slowlog/request-slowlog và timeout-related settings có thể hỗ trợ troubleshooting. Nhưng timeout quá thấp có thể kill request hợp lệ như import/report; quá cao có thể giữ worker lâu khi backend/app treo.

Log phải tránh lộ secret/request data nhạy cảm và cần rotation/retention.

13. Status endpoint phải được bảo vệ

Nếu bật FPM status/ping endpoint, chỉ expose cho monitoring path được kiểm soát. Không public status page ra Internet vì nó có thể tiết lộ operational information và tạo endpoint không cần thiết.

14. Nginx/Apache phải forward đúng script

PHP-FPM chỉ là runtime; web server quyết định request nào được chuyển vào FastCGI. Nginx/Apache mapping sai có thể khiến file không intended bị parse hoặc path resolution sai.

Với Nginx, xem Nginx Security Hardening. Nếu Apache dùng mod_proxy_fcgi, kiểm tra mapping theo vhost/app.

15. Không để FPM socket/port thành public service

Attack surface inventory phải xác minh:

sudo ss -lntup
sudo ss -lxnp

Nếu thấy FPM TCP listen trên 0.0.0.0 hoặc public interface mà architecture không yêu cầu, đây là finding ưu tiên cao. Xác minh dependency trước khi đổi listen.

16. Permission config và secret

Pool config có thể chứa path/log/environment setting nhạy cảm; chỉ admin cần quyền ghi. Secret không nên nằm trong public web root. Web worker chỉ nên đọc đúng secret cần cho application.

17. Validation trước reload/restart

Tùy distro/version, dùng config test tương ứng, ví dụ:

php-fpm -tt

Sau PASS, reload/restart theo service manager. Rồi kiểm tra:

  1. FPM service active.
  2. Pool worker chạy đúng user/group.
  3. Socket/port đúng.
  4. Nginx/Apache kết nối được.
  5. Website/API trả đúng.
  6. Upload/cache/session/cron vẫn hoạt động.
  7. Không có error/slowlog bất thường mới.

Mẫu PHP-FPM Pool Review Record

Đây là template evidence, không phải FPM state thực tế của SecureWebOps.

Control Observed Expected Evidence Result
Pool identity User/group App-scoped Config + process list PASS/FAIL
Listen Unix/TCP Local/private intended Socket + config PASS/FAIL
Environment clear_env/settings Minimal required vars Pool config PASS/FAIL
Extensions Allowed extensions App requirement only security.limit_extensions PASS/FAIL
Resource pm/limits Measured capacity Metrics + config PASS/FAIL

Checklist PHP-FPM Security

  1. Package/version còn support.
  2. Pool inventory đầy đủ.
  3. Mỗi app có identity phù hợp; tách pool khi cần.
  4. Worker không chạy root.
  5. Unix socket owner/group/mode tối thiểu.
  6. TCP listen không public ngoài intended architecture.
  7. listen.allowed_clients review nếu dùng TCP.
  8. clear_env không bị tắt rộng rãi thiếu lý do.
  9. security.limit_extensions phản ánh file type intended.
  10. php_admin settings dùng cho baseline cần enforce.
  11. Không xem disable_functions/open_basedir là sandbox chính.
  12. pm/resource limit dựa trên capacity.
  13. Status endpoint chỉ cho monitoring source.
  14. Web server FastCGI mapping đúng.
  15. Config/secret permission đúng.
  16. Config test PASS trước reload/restart.
  17. Functional test app sau change.

Nguồn kỹ thuật tham khảo

Kết luận

PHP-FPM hardening hiệu quả nhất khi pool identity, filesystem permission và listen boundary được thiết kế cùng nhau. Một pool chạy đúng user nhưng có socket public hoặc source tree world-writable vẫn chưa an toàn.

Workflow nên là pool-by-purpose → least-privilege user → local/private listen → minimal environment → measured resource limits → config test → functional read-back. FPM là một phần của web stack, nên mọi thay đổi phải được kiểm chứng cùng Nginx/Apache và application.

◇
Cần hỗ trợ kiểm tra và xử lý website?Đội ngũ SecureWebOps sẵn sàng hỗ trợ theo phạm vi phù hợp.
Liên hệ ngay →
Đoàn Trình Dục
Về tác giả Đoàn Trình Dục TD Digital · Website Operations & Security

Đoàn Trình Dục là tác giả nội dung trên SecureWebOps. Các bài viết tập trung vào bảo mật WordPress, giám sát an ninh website, malware/backdoor, hardening, backup/recovery và Incident Response theo hướng thực hành, có bước kiểm tra, bằng chứng, validation và rollback khi phù hợp.

Xem hồ sơ tác giả →