LARAVEL

Laravel Security Best Practices

March 20, 2024 22 min read

Introduction

Security is critical for any web application. Laravel provides many built-in security features, but understanding and properly implementing them is essential for protecting your application.

Authentication

Secure Password Storage

// Laravel automatically uses bcrypt
// Hash password
$user->password = Hash::make($request->password);

// Verify password
if (Hash::check($password, $user->password)) {
    // Password correct
}

// Check if needs rehash
if (Hash::needsRehash($user->password)) {
    $user->password = Hash::make($password);
    $user->save();
}

Rate Limiting

// In routes/web.php
Route::middleware(['throttle:5,1'])->group(function () {
    // 5 attempts per minute
});

// Custom throttle
Route::middleware('throttle:login')->group(function () {
    Route::post('/login', [AuthController::class, 'login']);
});

Two-Factor Authentication

// Using Laravel Fortify
composer require laravel/fortify

// Enable 2FA in Fortify config
'features' => [
    Features::twoFactorAuthentication(),
],

Authorization

Gates & Policies

// Define Gate
Gate::define('update-post', function ($user, $post) {
    return $user->id === $post->user_id;
});

// Check in controller
if (Gate::allows('update-post', $post)) {
    // User can update
}

// Or with policy
$this->authorize('update', $post);

Middleware Authorization

// Using can middleware
Route::put('/posts/{post}', function (Post $post) {
    // ...
})->middleware('can:update,post');

// Role-based access
Route::middleware('role:admin')->group(function () {
    // Admin routes
});

Input Validation

Form Request Validation

php artisan make:request StorePostRequest

// In StorePostRequest
public function rules(): array
{
    return [
        'title' => 'required|string|max:255',
        'body' => 'required|string',
        'category' => 'required|exists:categories,id',
        'tags' => 'array',
        'tags.*' => 'exists:tags,id',
        'publish_at' => 'nullable|date|after:now',
    ];
}

Custom Validation

// Custom rule
php artisan make:rule Uppercase

// Validator::extend
Validator::extend('no_special_chars', function ($attribute, $value) {
    return !preg_match('/[^a-zA-Z0-9]/', $value);
});

XSS & CSRF Protection

XSS Prevention

// Blade auto-escaping
{{ $user->name }}
// Outputs: <script>alert('xss')</script>

// Raw output (use carefully)
{!! $html !!}

// For HTML content
Clean::html($user->bio);

CSRF Protection

// CSRF Token
@csrf

// Or in JavaScript


// AJAX with CSRF
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

SQL Injection Prevention

Using Eloquent

// Safe: Eloquent ORM
$user = User::where('email', $email)->first();

// Safe: Query Builder with bindings
$users = DB::table('users')
    ->where('email', '=', $email)
    ->get();

// Unsafe (never do this!)
$users = DB::select("SELECT * FROM users WHERE email = '$email'");

Raw Queries with Bindings

// Safe: Parameterized query
DB::select('SELECT * FROM users WHERE id = ?', [$id]);

// Safe: Named bindings
DB::select('SELECT * FROM users WHERE id = :id', ['id' => $id]);

Encryption

Using Encryption

// Encrypt
$encrypted = Crypt::encryptString('secret data');

// Decrypt
$decrypted = Crypt::decryptString($encrypted);

// With IV (more secure)
$encrypted = encrypt($data);
$decrypted = decrypt($encrypted);

Hashing

// Hashing
$hash = Hash::make('password');

// Very secure (slower)
$hash = Hash::make('password', [
    'rounds' => 12,
]);

Summary

Laravel provides robust security features, but proper implementation is essential. Always validate input, use proper authentication and authorization, and keep your dependencies updated.

For more Laravel tutorials, check out Laravel API Authentication and Laravel Docker Deployment.