An Auditor’s Checklist for Securing Laravel Backends on DigitalOcean
DigitalOcean Droplet Hardening for Laravel Applications
Securing a Laravel backend deployed on DigitalOcean begins with a robustly hardened Droplet. This section outlines essential steps for minimizing the attack surface and establishing a secure foundation.
SSH Access Control
Restrict SSH access to authorized users and implement key-based authentication. Disabling password authentication is a critical first step.
Edit the SSH daemon configuration file:
sudo nano /etc/ssh/sshd_config
Ensure the following directives are set:
PasswordAuthentication no PermitRootLogin no AllowUsers your_ssh_user another_ssh_user
After making changes, restart the SSH service:
sudo systemctl restart sshd
Generate SSH keys if you haven’t already:
ssh-keygen -t rsa -b 4096
Copy your public key to the Droplet:
ssh-copy-id your_ssh_user@your_droplet_ip
Firewall Configuration (UFW)
Utilize Uncomplicated Firewall (UFW) to permit only necessary inbound traffic. For a typical Laravel application, this includes SSH, HTTP, and HTTPS.
sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow ssh sudo ufw allow http sudo ufw allow https sudo ufw enable
Verify the status:
sudo ufw status verbose
Regular System Updates
Automate or schedule regular updates for the operating system and installed packages to patch known vulnerabilities.
sudo apt update && sudo apt upgrade -y
Consider using tools like unattended-upgrades for automated security updates.
sudo apt install unattended-upgrades sudo dpkg-reconfigure --priority=low unattended-upgrades
Web Server Configuration (Nginx)
Nginx is a common choice for serving Laravel applications. Secure its configuration to mitigate common web vulnerabilities.
Nginx Security Headers
Implement essential security headers in your Nginx configuration to protect against XSS, clickjacking, and other attacks.
server {
listen 80;
server_name your_domain.com www.your_domain.com;
return 301 https://$host$request_uri; # Redirect HTTP to HTTPS
}
server {
listen 443 ssl http2;
server_name your_domain.com www.your_domain.com;
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;
# Security Headers
add_header Strict-Transport-Security "max-age=31536000; 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; # Uncomment and configure CSP carefully
root /var/www/your_laravel_app/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # Adjust PHP version as needed
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Prevent access to sensitive files
location ~* (composer\.json|composer\.lock|\.env|\.env\.example) {
deny all;
}
}
Reload Nginx to apply changes:
sudo systemctl reload nginx
Database Security (MySQL/PostgreSQL)
Secure your database by enforcing strong passwords, limiting user privileges, and configuring network access.
MySQL/MariaDB Specifics
Run the MySQL secure installation script:
sudo mysql_secure_installation
This script will guide you through setting the root password, removing anonymous users, disallowing remote root login, and removing the test database.
Create a dedicated database user for your Laravel application with minimal necessary privileges. Avoid using the root user.
-- Connect to MySQL as root mysql -u root -p -- Create the database CREATE DATABASE your_laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- Create a user for the application CREATE USER 'your_app_user'@'localhost' IDENTIFIED BY 'your_strong_password'; -- Grant privileges to the user on the specific database GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP, EXECUTE ON your_laravel_db.* TO 'your_app_user'@'localhost'; -- Apply the changes FLUSH PRIVILEGES; -- Exit MySQL EXIT;
Update your Laravel application’s .env file with these credentials:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=your_laravel_db DB_USERNAME=your_app_user DB_PASSWORD=your_strong_password
PostgreSQL Specifics
Create a dedicated user and database for your Laravel application.
# Connect to PostgreSQL as the default postgres user sudo -u postgres psql -- Create the database CREATE DATABASE your_laravel_db; -- Create a user for the application CREATE USER your_app_user WITH PASSWORD 'your_strong_password'; -- Grant privileges to the user on the specific database GRANT ALL PRIVILEGES ON DATABASE your_laravel_db TO your_app_user; -- Exit PostgreSQL \q
Update your Laravel application’s .env file:
DB_CONNECTION=pgsql DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=your_laravel_db DB_USERNAME=your_app_user DB_PASSWORD=your_strong_password
Laravel Application Security Best Practices
Beyond infrastructure, securing the Laravel application itself is paramount. This involves leveraging framework features and adhering to secure coding principles.
Environment Configuration (.env)
Ensure your .env file is never committed to version control. It contains sensitive credentials. Store it securely on the server and restrict file permissions.
# On the server, after deploying: chmod 600 .env chown www-data:www-data .env # Or the user your web server runs as
For enhanced security, consider using environment variable management tools like HashiCorp Vault or AWS Secrets Manager, integrated via custom Laravel service providers or packages.
HTTPS Enforcement
Laravel’s APP_SECURE configuration (or `APP_ENV=production` with `SESSION_SECURE_COOKIE=true` and `SESSION_HTTP_ONLY=true`) should be set correctly. The Nginx configuration above already enforces HTTPS redirection.
APP_ENV=production APP_DEBUG=false SESSION_SECURE_COOKIE=true SESSION_HTTP_ONLY=true
CSRF Protection
Laravel’s built-in Cross-Site Request Forgery (CSRF) protection is enabled by default. Ensure the VerifyCsrfToken middleware is active in app/Http/Kernel.php for all relevant routes.
protected $middleware = [
// ... other middleware
\App\Http\Middleware\VerifyCsrfToken::class,
// ... other middleware
];
For API routes that do not require CSRF protection (e.g., using token-based authentication), you can exclude them from the middleware group:
protected $middlewareGroups = [
'web' => [
// ...
\App\Http\Middleware\VerifyCsrfToken::class,
// ...
],
'api' => [
// ...
],
];
protected $routeMiddleware = [
// ...
];
Alternatively, exclude specific API routes within the api.php routes file:
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
'api/*',
];
Input Validation
Always validate and sanitize all user input. Laravel’s validation system is robust and should be used extensively.
// In your controller
public function store(Request $request)
{
$validatedData = $request->validate([
'title' => 'required|string|max:255',
'body' => 'required|string',
'email' => 'required|email|unique:users',
'publish_date' => 'nullable|date',
]);
// ... process validated data
}
Secure File Uploads
If your application handles file uploads, implement strict validation on file types, sizes, and store them outside the web root or in a dedicated, non-executable directory. Use Laravel’s Filesystem abstraction.
// Example: Storing uploads in storage/app/uploads
public function upload(Request $request)
{
$request->validate([
'photo' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048', // Max 2MB
]);
$path = $request->file('photo')->store('uploads', 'local'); // Stores in storage/app/uploads
return "File uploaded successfully to: " . $path;
}
Ensure the storage directory is symlinked correctly during deployment and that the web server user has write permissions only to necessary subdirectories (e.g., storage/app/uploads if direct access is required, otherwise keep uploads outside the web root entirely).
Dependency Management (Composer)
Regularly audit your project’s dependencies for known vulnerabilities. Use tools like:
composer audit(built-in since Composer 2.0.11)- Snyk
- Dependabot (GitHub integration)
composer audit
Update vulnerable dependencies promptly. Be cautious with major version upgrades, as they may introduce breaking changes.
Logging and Monitoring
Comprehensive logging and proactive monitoring are crucial for detecting and responding to security incidents.
Laravel Logging Configuration
Configure Laravel’s logging to capture relevant security events. For production, it’s recommended to log to a file or a remote logging service.
// config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['daily'],
'ignore_exceptions' => false,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'days' => 14, // Keep logs for 14 days
],
// Consider adding a 'syslog' or 'remote_syslog' channel for centralized logging
],
'default' => env('LOG_CHANNEL', 'stack'),
Ensure the storage/logs directory is writable by the web server user but not directly accessible via HTTP.
DigitalOcean Monitoring and Alerts
Leverage DigitalOcean’s built-in monitoring to track Droplet performance and set up alerts for unusual activity (e.g., high CPU/memory usage, network traffic spikes).
Integrate external monitoring tools like Prometheus/Grafana, Datadog, or Sentry for more granular application-level monitoring and error tracking.
Regular Audits and Penetration Testing
A proactive security posture requires regular verification. Schedule periodic audits and penetration tests.
Automated Security Scanners
Utilize tools like OWASP ZAP, Nessus, or commercial vulnerability scanners to identify common web application vulnerabilities.
Manual Code Reviews
Conduct thorough manual code reviews, focusing on security-critical areas such as authentication, authorization, input handling, and database interactions.
Penetration Testing
Engage third-party security professionals for independent penetration testing to simulate real-world attacks and uncover vulnerabilities missed by automated tools.