Skip to content

Security Hardening Guide

Security Hardening Guide

Security hardening guide for Cbox containers in production environments.

Built-in Security Features

Cbox PHP Base Images come with security features enabled by default:

Nginx Security (Default Configuration)

Feature Status Description
Server version hidden Enabled server_tokens off - Nginx version not exposed
X-Frame-Options Enabled SAMEORIGIN - Prevents clickjacking
X-Content-Type-Options Enabled nosniff - Prevents MIME sniffing
Referrer-Policy Enabled strict-origin-when-cross-origin
Permissions-Policy Enabled Restricts browser features (camera, microphone, etc.)
X-XSS-Protection Removed Deprecated and can be exploited
Content-Security-Policy Opt-in Disabled by default - too application-specific
Health endpoint restricted Enabled /health only accessible from localhost
Sensitive files blocked Enabled .env, .git, composer.json, artisan, vendor/, etc. return 404
Hidden files blocked Enabled All /. paths return 404
Upload directory protection Enabled PHP execution blocked in upload directories

SSL/TLS Security (When Enabled)

Feature Default Description
Key strength RSA 4096 Strong key generation for self-signed certificates
Protocols TLSv1.2, TLSv1.3 Modern protocols only
Cipher suite Mozilla Modern ECDHE-based ciphers with forward secrecy
HSTS Enabled 1 year max-age with includeSubDomains
Session tickets Disabled Enhanced security for session resumption

For custom TLS configuration, use the Mozilla SSL Configuration Generator to generate nginx TLS directives appropriate for your environment.

Entrypoint Security

Feature Status Description
Input validation Enabled Boolean values and paths validated
Path traversal protection Enabled .. sequences blocked in file paths
Template injection prevention Enabled envsubst used instead of eval
Signal handling Enabled Graceful shutdown on SIGTERM/SIGINT/SIGQUIT

Security Checklist

Before Production

  • Disable PHP error display
  • Restrict dangerous PHP functions
  • Enable HTTPS/TLS
  • Security headers configured
  • Secrets stored securely (not in git)
  • Container runs as non-root
  • File permissions correct
  • Rate limiting enabled
  • CVE scanning enabled

PHP Security Configuration

Disable Error Display

services:
  app:
    environment:
      - PHP_DISPLAY_ERRORS=Off
      - PHP_DISPLAY_STARTUP_ERRORS=Off
      - PHP_LOG_ERRORS=On
      - PHP_ERROR_LOG=/proc/self/fd/2

Restrict Dangerous Functions

Create docker/php/security.ini:

[Security]
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,phpinfo
expose_php = Off
allow_url_fopen = Off
allow_url_include = Off
open_basedir = /var/www/html:/tmp

; Session security
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = "Strict"
session.use_strict_mode = 1
session.use_only_cookies = 1

Mount in docker-compose.yml:

services:
  app:
    volumes:
      - ./docker/php/security.ini:/usr/local/etc/php/conf.d/zz-security.ini:ro

For a complete reference on PHP security settings, see the PHP Security documentation.

Content Security Policy

CSP is disabled by default because it is too application-specific. Enable it via environment variable:

services:
  app:
    environment:
      # Example for Laravel with Livewire and Google Fonts
      - NGINX_HEADER_CSP=default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self' wss:; frame-ancestors 'self'

For strict CSP or per-route CSP via Laravel middleware, configure at the application level. See the MDN CSP documentation for guidance on crafting policies.

Nginx Rate Limiting

# Define rate limit zones
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;

server {
    limit_req zone=general burst=20 nodelay;

    location /login {
        limit_req zone=login burst=2 nodelay;
    }

    location /api/ {
        limit_req zone=api burst=50;
    }
}

Secrets Management

Environment Variables (Basic)

Never commit secrets to git. Add to .gitignore:

.env
.env.*
!.env.example
*.key
*.pem

Docker Secrets (Docker Swarm)

services:
  app:
    image: ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.3-bookworm
    secrets:
      - app_key
      - db_password
    environment:
      - APP_KEY_FILE=/run/secrets/app_key
      - DB_PASSWORD_FILE=/run/secrets/db_password

secrets:
  app_key:
    external: true
  db_password:
    external: true

Read secrets in your application:

// Laravel - config/database.php
'password' => file_exists(env('DB_PASSWORD_FILE'))
    ? trim(file_get_contents(env('DB_PASSWORD_FILE')))
    : env('DB_PASSWORD'),

For Kubernetes secrets and Vault integration, see the Kubernetes Secrets documentation and your vault provider's docs.

Container Security

Run as Non-Root User

Cbox images already run as non-root by default:

docker exec <container> whoami
# Output: www-data

Read-Only Root Filesystem

services:
  app:
    image: ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.3-bookworm
    read_only: true
    tmpfs:
      - /tmp
      - /var/run
      - /var/cache/nginx
    volumes:
      - ./:/var/www/html:ro
      - app-storage:/var/www/html/storage

Drop Unnecessary Capabilities

services:
  app:
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # Only if binding to port <1024
      - CHOWN
      - SETGID
      - SETUID

Network Isolation

services:
  app:
    networks:
      - frontend
      - backend

  mysql:
    networks:
      - backend  # Not exposed to frontend

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No external access

CVE Management

Weekly Security Updates

Cbox images are automatically rebuilt weekly (Mondays 03:00 UTC) with the latest upstream base image patches, PHP security updates, and OS security updates.

# Pull latest image and restart
docker pull ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.3-bookworm
docker-compose build --pull
docker-compose up -d

Scanning with Trivy

Trivy detects vulnerabilities in OS packages, application dependencies, and container configuration.

# Scan Cbox image
trivy image ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.4-bookworm

# Only HIGH and CRITICAL
trivy image --severity HIGH,CRITICAL ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.4-bookworm

# Fail CI on critical vulnerabilities
trivy image --exit-code 1 --severity CRITICAL ghcr.io/cboxdk/php-baseimages/php-fpm-nginx:8.4-bookworm

Cbox CI workflows already include Trivy scanning. For setting up Trivy in your own CI pipeline, see the Trivy GitHub Action documentation.

Ignoring False Positives

Create a .trivyignore file for accepted risks:

# False positive in dev dependency
CVE-2024-12345

# Accepted risk - tracked in JIRA-123
CVE-2024-67890

PHP Dependency Scanning

# Using Symfony CLI
symfony security:check

# Or Enlightn Security Checker
docker-compose exec app composer require --dev enlightn/security-checker
docker-compose exec app php vendor/bin/security-checker security:check

Severity Response Guide

Severity Action
CRITICAL Immediate action - update base image or patch
HIGH Schedule update within 1 week
MEDIUM Address in next regular update cycle
LOW Monitor, address when convenient

Security Best Practices Checklist

Container Security

  • Run as non-root user (default in Cbox)
  • Read-only root filesystem where possible
  • Drop unnecessary capabilities
  • Regular security scanning
  • Minimal base image (use slim tier when possible)
  • No secrets in image layers

Network Security

  • HTTPS/TLS enabled
  • Network isolation configured
  • Rate limiting enabled

For detailed TLS configuration, use the Mozilla SSL Configuration Generator. For monitoring and alerting setup, see your observability platform's documentation.


Questions? Check common issues or ask in GitHub Discussions.