Hindi
Back to Blog
LaravelSecurityPHP

Securing Laravel Apps: Beyond the Basics

RD

Raman Daksh

January 18, 2025 · 7 min read

Laravel comes with solid security defaults — CSRF protection, SQL injection prevention, XSS escaping. But production applications need more. Here are the advanced measures I implement on every Laravel project.

Content Security Policy (CSP)

CSP headers prevent XSS attacks by whitelisting allowed content sources:

// middleware/CspMiddleware.php
class CspMiddleware
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        $response->headers->set('Content-Security-Policy', 
            "default-src 'self'; " .
            "script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; " .
            "style-src 'self' 'unsafe-inline'; " .
            "img-src 'self' data: https:; " .
            "font-src 'self' https://fonts.gstatic.com;"
        );
        return $response;
    }
}

Advanced Rate Limiting

Go beyond simple request counts. Implement multi-layered rate limiting:

// Different limits for different endpoints
RateLimiter::for('login', function (Request $request) {
    return Limit::perMinute(5)->by($request->ip());
});

RateLimiter::for('api', function (Request $request) {
    $user = $request->user();
    if ($user && $user->isAdmin()) {
        return Limit::perMinute(120)->by($user->id);
    }
    return Limit::perMinute(60)->by($request->ip());
});

Browser Fingerprinting

Detect automated attacks by fingerprinting browsers:

class FingerprintService
{
    public function generate(Request $request): string
    {
        $data = [
            $request->header('User-Agent'),
            $request->header('Accept-Language'),
            $request->header('Accept-Encoding'),
            // Canvas fingerprint, WebGL data, etc.
        ];
        return hash('sha256', implode('|', $data));
    }
    
    public function isSuspicious(Request $request): bool
    {
        $fingerprint = $this->generate($request);
        $visits = Cache::get("fp.{$fingerprint}", 0);
        
        if ($visits > 100) return true; // Too many requests from same fingerprint
        
        Cache::put("fp.{$fingerprint}", $visits + 1, 3600);
        return false;
    }
}

Bot Detection

Not all traffic is human. Implement a bot detection layer:

class BotDetection
{
    private array $suspiciousPatterns = [
        '/python-requests/i',
        '/curl/i',
        '/wget/i',
        '/headless/i',
    ];
    
    public function detect(Request $request): bool
    {
        $ua = $request->header('User-Agent', '');
        
        foreach ($this->suspiciousPatterns as $pattern) {
            if (preg_match($pattern, $ua)) return true;
        }
        
        // Check for missing headers that real browsers always send
        if (!$request->header('Accept-Language')) return true;
        if (!$request->header('Accept')) return true;
        
        return false;
    }
}

Security Headers Checklist

Always set these in production:

X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Strict-Transport-Security: max-age=31536000; includeSubDomains

These layers together create a defense-in-depth strategy that protects against the majority of web attacks.

All Posts