25 Essential PHP Security Best Practices for Hardened Web Servers

This guide presents 25 practical PHP security best practices, covering configuration files, module management, error handling, file uploads, remote code execution, SQL safety, resource limits, user permissions, SELinux, firewall rules, and additional tools, to help administrators harden PHP deployments on Linux servers.

Art of Distributed System Architecture Design
Art of Distributed System Architecture Design
Art of Distributed System Architecture Design
25 Essential PHP Security Best Practices for Hardened Web Servers

PHP is a widely used open‑source server‑side scripting language, but misconfiguration can expose many vulnerabilities. The following 25 best practices provide a comprehensive checklist for securing PHP on Linux servers, assuming root access and a typical Apache (or Lighttpd/Nginx) environment.

Environment Overview

DocumentRoot: /var/www/html Web server: Apache (alternatives Lighttpd, Nginx)

PHP config file: /etc/php.ini Additional module configs: /etc/php.d/ Custom security config: /etc/php.d/security.ini OS: RHEL/CentOS/Fedora (commands also apply to Debian/Ubuntu, OpenBSD, FreeBSD, HP‑UX, etc.)

Best Practice 1 – Know Your Threats

Common PHP attack vectors include XSS, SQL injection, unsafe file uploads, remote file inclusion, use of eval(), and CSRF. Mitigation requires input validation, disabling dangerous functions, and configuring the web server to limit exposure.

Best Practice 2 – Audit Built‑in Modules

List compiled modules with php -m. Remove unnecessary modules to reduce attack surface, e.g.:

# rm /etc/php.d/sqlite3.ini
# mv /etc/php.d/sqlite3.ini /etc/php.d/sqlite3.disable

Recompile PHP with only required extensions (GD, MySQL, FastCGI) using a configure command similar to:

./configure --with-libdir=lib64 --with-gd --with-mysql --prefix=/usr \
    --exec-prefix=/usr --bindir=/usr/bin --sbindir=/usr/sbin \
    --sysconfdir=/etc --datadir=/usr/share --includedir=/usr/include \
    --enable-fastcgi --enable-force-cgi-redirect

Best Practice 3 – Hide PHP Version Information

Disable expose_php in /etc/php.d/security.ini: expose_php=Off Also set ServerTokens and ServerSignature in the Apache configuration to hide server details.

Best Practice 4 – Minimize Loaded Extensions

Comment out or rename unneeded .ini files in /etc/php.d/. Example to disable the GD extension:

# cd /etc/php.d/
# mv gd.{ini,disable}
# /sbin/service httpd restart

To re‑enable, reverse the rename.

Best Practice 5 – Log All PHP Errors

Turn off on‑screen error display and log errors to a file:

display_errors=Off
log_errors=On
error_log=/var/log/httpd/php_scripts_error.log

Best Practice 6 – Control File Uploads

Disable uploads globally: file_uploads=Off If uploads are needed, enable them and set a size limit:

file_uploads=On
upload_max_filesize=1M

Best Practice 7 – Disable Remote Code Execution

Turn off allow_url_fopen and allow_url_include:

allow_url_fopen=Off
allow_url_include=Off

Best Practice 8 – Enable SQL Safe Mode

Activate sql.safe_mode and disable magic_quotes_gpc:

sql.safe_mode=On
magic_quotes_gpc=Off

Best Practice 9 – Limit POST Request Size

Restrict maximum POST data to 1 KB (adjust as needed): post_max_size=1K Also limit HTTP methods in Apache:

<Directory /var/www/html>
    <LimitExcept GET POST>
        Order allow,deny
    </LimitExcept>
</Directory>

Best Practice 10 – Resource Controls

Set execution time, input time, and memory limits:

max_execution_time=30
max_input_time=30
memory_limit=40M

Best Practice 11 – Install Suhosin

Suhosin provides advanced hardening for PHP core and extensions. Follow the project’s installation guide for Linux.

Best Practice 12 – Disable Dangerous Functions

Use disable_functions to block high‑risk calls:

disable_functions=exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

Best Practice 13 – Enforce cgi.force_redirect

Enable cgi.force_redirect to prevent direct CGI execution:

cgi.force_redirect=On

Best Practice 14 – Run PHP as a Non‑Root User

Configure Apache’s suEXEC or mod_suPHP so PHP runs under a low‑privilege account (e.g., phpcgi).

Best Practice 15 – Restrict Filesystem Access

Set open_basedir to limit PHP to specific directories:

open_basedir="/var/www/html/"

Best Practice 16 – Secure Session Storage

Define a dedicated session directory with proper permissions:

session.save_path="/var/lib/php/session"
upload_tmp_dir="/var/lib/php/session"

Best Practice 17 – Keep Software Updated

Regularly apply updates via package managers:

# yum update
# apt-get update && apt-get upgrade

Best Practice 18 – Harden File Permissions

Run Apache as a non‑root user and set read‑only permissions for web files:

# chown -R apache:apache /var/www/html/
# chmod -R 0444 /var/www/html/
# find /var/www/html/ -type d -exec chmod 0445 {} \;

Best Practice 19 – Make Configuration Files Immutable

Use chattr +i to protect critical config files:

# chattr +i /etc/php.ini
# chattr +i /etc/php.d/*
# chattr +i /etc/httpd/conf/httpd.conf

Best Practice 20 – Enable SELinux

Leverage SELinux policies to restrict Apache and PHP actions. Example to view HTTPD booleans: # getsebool -a | grep httpd Disable CGI support if not needed:

# setsebool -P httpd_enable_cgi off

Best Practice 21 – Deploy ModSecurity

Install ModSecurity and add simple filters:

SecFilter /etc/
SecFilter "delete[[:space:]]+from"
SecFilter "select.+from"

Best Practice 22 – Use chroot Jails

Run Apache/PHP inside a chroot or container (FreeBSD jail, XEN, KVM, OpenVZ) to isolate the filesystem.

Best Practice 23 – Restrict Outbound Connections

Configure iptables to limit outbound traffic for the Apache user:

# /sbin/iptables -A OUTPUT -o eth0 -m owner --uid-owner apache -j REJECT

Best Practice 24 – Log Monitoring and Auditing

Continuously tail Apache and PHP error logs and use grep or egrep to spot suspicious entries. Enable auditd for SELinux and file change auditing.

Best Practice 25 – Service Segmentation

Distribute services across multiple servers or VMs (static assets on Lighttpd/Nginx, dynamic PHP on Apache, MySQL on a dedicated host, Memcached for caching, and an Nginx load balancer in front).

Additional Tools

Consider PHPIDS for intrusion detection and PhpSecInfo for automated security reporting.

Disclaimer: The content is compiled from public sources for reference only; original copyrights belong to the authors.
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendWebLinuxSecurityPHP
Art of Distributed System Architecture Design
Written by

Art of Distributed System Architecture Design

Introductions to large-scale distributed system architectures; insights and knowledge sharing on large-scale internet system architecture; front-end web architecture overviews; practical tips and experiences with PHP, JavaScript, Erlang, C/C++ and other languages in large-scale internet system development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.