• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » An Auditor’s Checklist for Securing PHP Backends on DigitalOcean

An Auditor’s Checklist for Securing PHP Backends on DigitalOcean

PHP Version and Extension Management

A foundational security practice is ensuring your PHP installation is up-to-date and only utilizes necessary extensions. Outdated PHP versions are a primary vector for known vulnerabilities. Similarly, unneeded extensions can expand the attack surface.

On DigitalOcean, you’ll typically manage PHP via your web server configuration (e.g., Nginx with PHP-FPM) or directly through the OS package manager. For auditing, verify the exact PHP version and the loaded extensions.

Verifying PHP Version

The most straightforward method is to create a simple PHP info file. However, for security, this file should be removed immediately after auditing.

Create a file named info.php in your web root:

<?php
phpinfo();
?>

Access this file via your browser (e.g., http://your_domain.com/info.php). Note the “PHP Version” displayed prominently at the top. After noting the version, immediately delete info.php from your server.

Alternatively, you can check via the command line if PHP is installed globally or accessible:

php -v

If you are using PHP-FPM, you can check the version associated with a specific pool:

/usr/sbin/php-fpm -v

Listing Loaded PHP Extensions

Again, a temporary phpinfo() file is useful. Look for the “extension_dir” and the “module” sections. For command-line auditing:

php -m

This command lists all compiled and loaded modules. Review this list critically. For instance, extensions like disable_functions in php.ini can be used to restrict dangerous functions, but the presence of extensions like exec, shell_exec, system, passthru, popen, proc_open, pcntl_exec, eval, and assert requires careful justification and monitoring.

PHP Configuration Hardening (php.ini)

The php.ini file is central to PHP’s security posture. Auditing involves verifying specific directives are set to secure values.

Locating php.ini

The location of php.ini can vary. Use phpinfo() or the command line to find it:

php --ini

This will output the loaded configuration file and additional scanned directories. For PHP-FPM, the configuration might be in a separate file, often located in /etc/php/[version]/fpm/php.ini or similar.

Key Security Directives to Audit

  • expose_php = Off: Prevents PHP version disclosure in HTTP headers (e.g., X-Powered-By: PHP/7.4.33).
  • display_errors = Off: Crucial for production environments. Error messages can leak sensitive information. Errors should be logged to a file instead.
  • log_errors = On: Ensures errors are logged.
  • error_log = /var/log/php/php_errors.log (or a secure, non-web-accessible path): Specifies the log file. Ensure this path is protected and not served by the web server.
  • disable_functions: A powerful directive to restrict execution of dangerous functions. A common baseline includes: exec,system,passthru,shell_exec,popen,proc_open,pcntl_exec,eval,assert,create_function,dl,escapeshellarg,escapeshellcmd,phpinfo,show_source,highlight_file,is_executable,is_file,is_link,is_readable,is_writable,is_writeable,link,mkdir,move_uploaded_file,parse_ini_file,readfile,rename,rmdir,scandir,set_time_limit,symlink,tempnam,tmpfile,touch,unlink,virtual. This list should be tailored to the application’s needs.
  • allow_url_fopen = Off: Disables the ability to include or read files from remote URLs, mitigating SSRF risks.
  • allow_url_include = Off: Disables including remote files via include, require, etc. This is a more specific and critical restriction than allow_url_fopen.
  • session.cookie_httponly = 1: Makes session cookies inaccessible to JavaScript, mitigating XSS attacks.
  • session.cookie_secure = 1: Ensures session cookies are only sent over HTTPS. Requires SSL/TLS to be configured.
  • session.use_strict_mode = 1: Protects against session fixation vulnerabilities.
  • open_basedir: Restricts PHP’s file access to a specific directory tree. This is a significant security enhancement, limiting the scope of file operations. Example: open_basedir = "/var/www/html/:/tmp/".
  • disable_classes: Can be used to disable entire classes, though less commonly used than disable_functions.
  • memory_limit: Set to a reasonable, non-excessive value to prevent DoS attacks via memory exhaustion.
  • max_execution_time: Similarly, limit execution time to prevent DoS.
  • upload_max_filesize and post_max_size: Configure these to prevent excessively large uploads that could consume server resources.

After modifying php.ini, the PHP-FPM service (or the web server if using mod_php) must be restarted for changes to take effect.

sudo systemctl restart php[version]-fpm

Replace [version] with your specific PHP version (e.g., php8.1-fpm).

Web Server Configuration (Nginx Example)

The web server plays a critical role in securing the PHP backend by controlling access, handling SSL, and passing requests to PHP-FPM. We’ll focus on Nginx as it’s common on DigitalOcean.

Nginx Configuration Snippet for PHP-FPM

A typical Nginx server block configuration for serving PHP applications looks like this. Auditing focuses on specific directives.

server {
    listen 80;
    listen [::]:80;
    server_name your_domain.com www.your_domain.com;

    # Redirect HTTP to HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your_domain.com www.your_domain.com;

    # SSL Configuration
    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s; # Use your preferred DNS resolver
    resolver_timeout 5s;

    # Security Headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    # add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';" always; # CSP is highly application-specific and requires careful tuning

    root /var/www/your_domain.com/public_html;
    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Pass PHP scripts to FastCGI server
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        # Make sure this socket path matches your PHP-FPM configuration
        fastcgi_pass unix:/var/run/php/php[version]-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;

        # Security: Prevent direct access to PHP files if not intended
        # For example, if your framework handles routing, you might want to deny direct access to non-entrypoint PHP files.
        # This is often handled by framework .htaccess or similar, but can be enforced here.
        # Example: deny access to specific sensitive PHP files
        # location ~* /(config|includes|vendor)/.*\.php$ {
        #     deny all;
        # }
    }

    # Deny access to hidden files (e.g., .htaccess, .git)
    location ~ /\. {
        deny all;
    }

    # Deny access to sensitive files
    location ~* (composer\.json|composer\.lock|\.env|\.env\.example|wp-config\.php|config\.php) {
        deny all;
    }

    # Prevent access to .htaccess files, if Apache is used elsewhere or for compatibility
    location ~ /\.ht {
        deny all;
    }

    # Logging
    access_log /var/log/nginx/your_domain.com.access.log;
    error_log /var/log/nginx/your_domain.com.error.log;
}

Key Security Directives to Audit in Nginx Config

  • SSL Configuration: Ensure ssl_protocols are modern (TLSv1.2, TLSv1.3) and avoid older, insecure versions. Use strong cipher suites.
  • HTTP Strict Transport Security (HSTS): add_header Strict-Transport-Security ensures clients always connect via HTTPS.
  • X-Frame-Options: Prevents clickjacking by controlling if the page can be rendered in an iframe. SAMEORIGIN is a good default.
  • X-Content-Type-Options: nosniff: Prevents the browser from MIME-sniffing a response away from the declared content type.
  • X-XSS-Protection: 1; mode=block: Enables the browser’s built-in XSS filter.
  • Referrer-Policy: Controls how much referrer information is sent. strict-origin-when-cross-origin is a strong default.
  • Content-Security-Policy (CSP): While complex, a basic CSP can significantly mitigate XSS. The example is a starting point; actual CSP must be tailored to the application.
  • PHP-FPM Socket Path: Verify fastcgi_pass points to the correct PHP-FPM socket or IP:port.
  • Denial of Access Rules: The location ~ \.php$ block, and especially the explicit deny all; rules for hidden files, sensitive configuration files (like .env, wp-config.php), and potentially framework-specific sensitive PHP files, are critical.
  • Access and Error Logs: Ensure logs are enabled and directed to secure, non-web-accessible locations.

After modifying Nginx configuration, test the configuration and reload Nginx:

sudo nginx -t
sudo systemctl reload nginx

Database Security (MySQL/MariaDB)

Securing the database is paramount, as it often holds the most sensitive application data. This section covers common auditing points for MySQL/MariaDB, which are prevalent on DigitalOcean.

User Privileges and Access Control

The principle of least privilege must be applied to database users. Application users should only have the permissions they absolutely need.

To audit user privileges, connect to the MySQL server and run:

SHOW GRANTS FOR 'app_user'@'localhost';
SHOW GRANTS FOR 'app_user'@'%'; -- If remote access is allowed

Review the output carefully. For example, an application user should generally not have FILE, PROCESS, RELOAD, SHUTDOWN, or SUPER privileges. They should typically only have SELECT, INSERT, UPDATE, DELETE on specific tables, and potentially CREATE TEMPORARY TABLES or EXECUTE if required by the application.

Ensure that the application connects using specific, non-root users and, where possible, restricts connections to localhost or a specific IP address rather than allowing access from any host (%).

Secure Connection (SSL/TLS)

If the application server and database server are on different machines, or if there’s any risk of network eavesdropping, database connections should be encrypted using SSL/TLS.

On the MySQL server, you can check SSL status for connections:

SHOW VARIABLES LIKE 'have_ssl';
SHOW STATUS LIKE 'Ssl_cipher'; -- Check if SSL is in use for current connections

Ensure your application’s database connection string or configuration specifies SSL/TLS usage. For PHP’s PDO or MySQLi, this typically involves setting options like PDO::MYSQL_ATTR_SSL_KEY, PDO::MYSQL_ATTR_SSL_CERT, and PDO::MYSQL_ATTR_SSL_CA.

Sensitive Data Protection

Sensitive data (passwords, PII) stored in the database should be encrypted. This can be done at the application level (preferred) or, in some cases, using database-level encryption features.

Auditing involves checking schemas for fields that should be encrypted and verifying that the application implements encryption correctly (e.g., using strong, modern algorithms like AES-256 with appropriate modes and key management).

MySQL/MariaDB Configuration (my.cnf)

Key security settings in my.cnf (or files in /etc/mysql/conf.d/ or /etc/mysql/mariadb.conf.d/) include:

  • bind-address: Should be set to 127.0.0.1 to only allow local connections, unless remote access is explicitly required and secured.
  • skip-networking: If the database is only accessed locally, this directive can be used to disable TCP/IP networking entirely.
  • secure_file_priv: Restricts the LOAD DATA INFILE and SELECT ... INTO OUTFILE operations to a specific directory.
  • local_infile=0: Disables the local_infile option, which can be exploited if not properly secured.
  • general_log=0 and log_error: Ensure the general query log is off in production to avoid performance impact and sensitive data exposure. Error logging should be enabled.

After modifying MySQL/MariaDB configuration, the service must be restarted:

sudo systemctl restart mysql # or mariadb

File Permissions and Ownership

Incorrect file permissions are a common vulnerability that allows attackers to modify code, upload malicious files, or access sensitive data.

Web Root Permissions

The web server user (e.g., www-data for Nginx/Apache on Debian/Ubuntu) needs write access only to directories where the application *must* write. This typically includes:

  • Upload directories
  • Cache directories
  • Log directories (if written by the web server process)
  • Temporary directories

All other files and directories should be owned by a non-web server user and have read-only permissions for the web server user.

A common and secure setup:

# Assume web root is /var/www/your_app
# Assume web server user is www-data
# Assume application files are owned by 'deployer' user

# Set ownership for the entire application directory
sudo chown -R deployer:www-data /var/www/your_app

# Set base permissions: owner rwx, group rx, others none
sudo find /var/www/your_app -type d -exec chmod 750 {} \;
sudo find /var/www/your_app -type f -exec chmod 640 {} \;

# Grant write permissions to specific directories for the web server group (www-data)
sudo chmod -R g+w /var/www/your_app/storage/app/public # Example for Laravel uploads
sudo chmod -R g+w /var/www/your_app/storage/framework/cache
sudo chmod -R g+w /var/www/your_app/storage/logs
sudo chmod -R g+w /var/www/your_app/bootstrap/cache

# Ensure sensitive files are not readable by the web server group
sudo chmod -R g-r /var/www/your_app/config # Example: if config is sensitive
sudo chmod -R g-r /var/www/your_app/.env # Crucial: .env should NOT be web-readable

Crucially, ensure that directories containing PHP files (like vendor/, src/, app/) are NOT writable by the web server user. If they are, an attacker could potentially upload malicious PHP scripts into these directories.

Sensitive File Permissions

Files like .env, configuration files, and sensitive data files must be protected. They should ideally not be within the web root or, if they are, must have strict permissions.

# Example: Ensure .env is not readable by the web server user
sudo chown deployer:deployer /var/www/your_app/.env
sudo chmod 600 /var/www/your_app/.env

Dependency Management and Vulnerability Scanning

Modern PHP applications rely heavily on third-party libraries managed via Composer. These dependencies can introduce vulnerabilities.

Composer Security Audit

Composer has built-in tools to check for known vulnerabilities in your project’s dependencies.

# Navigate to your project root
cd /var/www/your_app

# Install dependencies (if not already done)
composer install --no-dev --optimize-autoloader

# Check for security vulnerabilities
composer audit

The composer audit command (or composer security-check in older versions) will report any known vulnerabilities in your installed packages. It’s essential to regularly review these reports and update vulnerable dependencies promptly.

Lock Files

Ensure that composer.lock is committed to your version control system. This guarantees that deployments use the exact same versions of dependencies, preventing “it works on my machine” issues and ensuring consistent security posture across environments.

Logging and Monitoring

Comprehensive logging and active monitoring are critical for detecting and responding to security incidents.

Log Aggregation and Analysis

Ensure that logs from Nginx, PHP-FPM, and your application are collected and stored securely. On DigitalOcean, consider using:

  • DigitalOcean’s Managed Databases: If applicable, ensure database logs are enabled and accessible.
  • Log Management Tools: Services like LogDNA, Datadog, or even a self-hosted ELK stack (Elasticsearch, Logstash, Kibana) can aggregate logs from various sources.
  • Systemd Journal: For services managed by systemd, logs are often accessible via journalctl.

Key log sources to audit:

  • Nginx Access and Error Logs: Look for suspicious patterns like repeated 4xx/5xx errors, SQL injection attempts (e.g., in URL parameters), directory traversal attempts (../), and brute-force login attempts.
  • PHP-FPM Error Logs: Critical for identifying runtime errors that might indicate exploits or misconfigurations.
  • Application Logs: Custom application logs should record security-relevant events, such as failed login attempts, access to sensitive data, and administrative actions.
  • Database Logs: Audit logs (if enabled and appropriate) can show suspicious queries or access patterns.

Intrusion Detection Systems (IDS) / Web Application Firewalls (WAF)

While not strictly PHP backend configuration, these are vital layers of defense. Consider:

  • ModSecurity: A popular open-source WAF that can be integrated with Nginx. Ensure it’s configured with up-to-date rule sets (e.g., OWASP Core Rule Set).
  • Cloudflare/Other CDN WAFs: Many CDNs offer WAF capabilities that can filter malicious traffic before it reaches your DigitalOcean droplet.

Regularly review WAF logs and alerts to fine-tune rules and identify emerging threats.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Disaster Recovery 101: Architecting Auto-Failovers for Redis and PHP Deployments on OVH
  • How We Audited a High-Traffic WooCommerce Enterprise Stack on Google Cloud and Mitigated Race conditions during high-concurrency payment processing
  • Disaster Recovery 101: Architecting Auto-Failovers for Elasticsearch and Magento 2 Deployments on DigitalOcean
  • An Auditor’s Checklist for Securing WordPress Backends on OVH
  • Step-by-Step: Diagnosing Perl script high CPU throttling due to unoptimized regular expressions on AWS Servers

Copyright © 2026 · Vinay Vengala