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; includeSubDomainsThese layers together create a defense-in-depth strategy that protects against the majority of web attacks.