Published
04 Apr, 2025
Category
DevOps / Hosting
Approach I Made To Defend My Site From Common Cyberattacks on Shared Hosting

Cyberattacks hit every public site especially small apps within minutes of going live. This article shares the practical, copy-pasteable hardening routine I use to keep a Laravel/PHP site safe on shared hosting: lock down secrets and permissions, tighten auth and input handling, secure uploads, add security headers, rate-limit behind a WAF, and set up monitoring and backups. No theory just a baseline you can implement today and improve over time.

My Baseline Hardening Checklist

  • APP_DEBUG=false, HTTPS only, regular updates (composer update on schedule), composer audit.
  • Secrets in .env outside public_html; strict file/dir permissions.
  • Strong auth + 2FA for admins; throttle logins; secure session cookies.
  • Validate input everywhere; prefer Blade {{ }}; avoid DB::raw() unless sanitized.
  • Secure file uploads; block PHP execution in upload directories.
  • Security headers: HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy.
  • Rate limiting on auth/API; WAF (e.g., Cloudflare) in front; CAPTCHA on public forms.
  • Monitoring & alerts (logs + Sentry/Bugsnag); tested backups + restore drill.
  • Disable dev tools in prod; no directory listing; never expose /vendor.

1) Lock Down Production Basics

.env essentials:

APP_ENV=production 
APP_DEBUG=false 
APP_URL=https://example.com  

LOG_CHANNEL=stack 
LOG_LEVEL=warning  

SESSION_SECURE_COOKIE=true 
SESSION_HTTP_ONLY=true 
SESSION_SAME_SITE=lax
Server Hygiene (Shared Hosting)
  • Force HTTPS (use your panel’s SSL + redirect in .htaccess).
  • Keep PHP and extensions updated (use PHP 8.2/8.3).
  • Schedule a monthly dependency pass: composer update --with-all-dependencies (test locally first) and composer audit.
Apache redirect to HTTPS (in public_html/.htaccess):

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
2) Secrets & Permissions

Keep .env out of public_html (place it in /home/USER/laravel/.env). Permissions (typical baseline):

# from project root (NOT public_html)
find . -type f -exec chmod 0644 {} \;
find . -type d -exec chmod 0755 {} \;
chmod -R 0775 storage bootstrap/cache
chmod 0640 .env
Least-privilege database user:

  • Create a dedicated DB user with only the database it needs (no global privileges).
  • Rotate credentials when staff change or after incidents.
3) Authentication & Sessions

Password policy (in App\Providers\AuthServiceProvider or a dedicated provider):

use Illuminate\Validation\Rules\Password;

Password::defaults(function () {
    return Password::min(12)->mixedCase()->numbers()->symbols()->uncompromised();
});

Throttle logins (in App\Providers\RouteServiceProvider):

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

public function boot(): void
{
    RateLimiter::for('login', function (Request $request) {
        $email = (string) $request->input('email');
        return Limit::perMinute(5)->by($email.$request->ip());
    });
}

Apply middleware to login route: ->middleware('throttle:login').

2FA: If you use Jetstream/Fortify, enable TOTP; otherwise, add a lightweight package or an SMS/Email code for admin logins.

Session hardening: already set via .env. Also set a short session lifetime for admin areas.

4) Input Validation, XSS & SQL Injection

Always validate requests:

$request->validate([
  'title' => ['required','string','max:120'],
  'email' => ['required','email'],
  'page'  => ['nullable','integer','min:1','max:1000'],
]);
Escape output in Blade:

Use {{ $title }} (escaped) rather than {!! $title !!} (only use unescaped when you fully trust/sanitize the content).

Avoid raw SQL: Eloquent and the query builder use prepared statements by default. If you must use DB::raw(), sanitize carefully and prefer bindings.

CSRF: All forms need @csrf. APIs should be in routes/api.php (stateless, no CSRF).