Back to Blog
Laravel Security Best Practices: Protecting Your Application
Security is Not Optional
Security breaches destroy trust and can end businesses. Laravel provides excellent security features out of the box, but you need to use them correctly and understand what additional protections your application needs.
Input Validation
Never trust user input. Validate everything:
class StoreUserRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email', 'unique:users'],
'password' => ['required', Password::min(12)->mixedCase()->numbers()->symbols()],
'avatar' => ['nullable', 'image', 'max:2048', 'mimes:jpg,png'],
];
}
}
SQL Injection Prevention
Eloquent protects against SQL injection, but be careful with raw queries:
// SAFE: Parameterized query
DB::select('SELECT * FROM users WHERE email = ?', [$email]);
// DANGER: String concatenation
DB::select("SELECT * FROM users WHERE email = '$email'");
XSS Prevention
Blade's {{ }} syntax escapes output by default:
// SAFE: Escaped output
{{ $userInput }}
// DANGER: Unescaped output
{!! $userInput !!}
// Only use {!! !!} for trusted HTML (like from a WYSIWYG editor with server-side sanitization)
CSRF Protection
Include CSRF tokens in all forms:
<form method="POST">
@csrf
...
</form>
Authentication Security
// Rate limit login attempts
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)->by($request->ip());
});
// Invalidate sessions on password change
public function updatePassword(Request $request): void
{
$user->update(['password' => Hash::make($request->password)]);
Auth::logoutOtherDevices($request->password);
}
Authorization
// Always authorize actions
public function update(Request $request, Post $post): Response
{
$this->authorize('update', $post);
// ...
}
// Policy
class PostPolicy
{
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id
|| $user->hasRole('admin');
}
}
Encryption
// Encrypt sensitive data
$encrypted = Crypt::encryptString($sensitiveData);
$decrypted = Crypt::decryptString($encrypted);
// Use encrypted casts
protected $casts = [
'ssn' => 'encrypted',
'api_key' => 'encrypted',
];
Security Headers
// In middleware
public function handle($request, Closure $next)
{
$response = $next($request);
return $response
->header('X-Content-Type-Options', 'nosniff')
->header('X-Frame-Options', 'DENY')
->header('X-XSS-Protection', '1; mode=block')
->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
}
Dependency Security
# Regular security audits
composer audit
# Keep dependencies updated
composer update --with-dependencies
Environment Security
- Never commit .env files
- Rotate APP_KEY if compromised
- Use strong, unique passwords for databases
- Restrict database access to application servers only
Conclusion
Security is a continuous practice, not a checklist. Stay updated on vulnerabilities, regularly audit your dependencies, and never assume your application is too small to be attacked.
Related Articles
Need Help With Your Project?
I respond to all inquiries within 24 hours. Let's discuss how I can help build your production-ready system.
Get In Touch