Appearance
🔒 Security Best Practices
Comprehensive security guidelines for Laravel applications. This section covers authentication, authorization, data protection, and vulnerability prevention.
🛡️ Input Validation
Always validate and sanitize user input to prevent security vulnerabilities.
✅ Good Example
php
<?php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class CreateUserRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()->can('create', User::class);
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255', 'regex:/^[a-zA-Z\s]+$/'],
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
'password' => [
'required',
'string',
'min:12',
'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/',
],
'role' => ['required', 'string', 'in:user,moderator,admin'],
];
}
public function messages(): array
{
return [
'password.regex' => 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character.',
'name.regex' => 'Name can only contain letters and spaces.',
];
}
protected function prepareForValidation(): void
{
$this->merge([
'email' => strtolower(trim($this->email)),
'name' => trim($this->name),
]);
}
}❌ Bad Example
php
<?php
// No validation - security risk
class UserController extends Controller
{
public function store(Request $request)
{
// Direct creation without validation
$user = User::create([
'name' => $request->name, // No validation
'email' => $request->email, // No validation
'password' => $request->password, // No validation
'role' => $request->role, // No validation
]);
return response()->json($user);
}
}🔐 Authentication & Authorization
Password Security
✅ Good Example
php
<?php
namespace App\Services;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class PasswordService
{
public function validatePassword(string $password): array
{
$validator = Validator::make(['password' => $password], [
'password' => [
'required',
'string',
'min:12',
'max:128',
'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/',
],
]);
return [
'valid' => !$validator->fails(),
'errors' => $validator->errors()->get('password', []),
];
}
public function hashPassword(string $password): string
{
return Hash::make($password);
}
public function verifyPassword(string $password, string $hash): bool
{
return Hash::check($password, $hash);
}
}❌ Bad Example
php
<?php
// Weak password handling
class UserController extends Controller
{
public function store(Request $request)
{
// Weak password requirements
$request->validate([
'password' => 'required|min:6', // Too weak
]);
// Direct password storage without proper hashing
$user = User::create([
'password' => md5($request->password), // MD5 is not secure
]);
}
}Authorization Policies
✅ Good Example
php
<?php
namespace App\Policies;
use App\Models\User;
use App\Models\Post;
class PostPolicy
{
public function viewAny(User $user): bool
{
return $user->hasPermission('posts.view');
}
public function view(User $user, Post $post): bool
{
return $user->hasPermission('posts.view') ||
$post->user_id === $user->id;
}
public function create(User $user): bool
{
return $user->hasPermission('posts.create');
}
public function update(User $user, Post $post): bool
{
return $user->hasPermission('posts.update') ||
($post->user_id === $user->id && $user->hasPermission('posts.update.own'));
}
public function delete(User $user, Post $post): bool
{
return $user->hasPermission('posts.delete') ||
($post->user_id === $user->id && $user->hasPermission('posts.delete.own'));
}
}❌ Bad Example
php
<?php
// No authorization checks - security risk
class PostController extends Controller
{
public function update(Request $request, Post $post)
{
// No authorization check
$post->update($request->all());
return response()->json($post);
}
public function delete(Post $post)
{
// No authorization check
$post->delete();
return response()->json(['message' => 'Post deleted']);
}
}🛡️ Data Protection
Sensitive Data Handling
✅ Good Example
php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class User extends Model
{
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
'api_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
'password' => 'hashed',
'is_active' => 'boolean',
];
protected function password(): Attribute
{
return Attribute::make(
set: fn (string $value) => Hash::make($value),
);
}
protected function email(): Attribute
{
return Attribute::make(
get: fn (string $value) => strtolower($value),
set: fn (string $value) => strtolower(trim($value)),
);
}
}❌ Bad Example
php
<?php
// Exposing sensitive data
class User extends Model
{
// No fillable array - mass assignment vulnerability
// No hidden fields - sensitive data exposed
// No casts - data not properly handled
public function toArray()
{
return $this->attributes; // Exposes all data including passwords
}
}SQL Injection Prevention
✅ Good Example
php
<?php
namespace App\Repositories;
use App\Models\User;
use Illuminate\Database\Eloquent\Builder;
class UserRepository
{
public function searchUsers(string $query): Collection
{
// Use Eloquent ORM - automatically prevents SQL injection
return User::where('name', 'LIKE', "%{$query}%")
->orWhere('email', 'LIKE', "%{$query}%")
->get();
}
public function getUsersByRole(string $role): Collection
{
// Use parameterized queries
return User::where('role', $role)
->where('is_active', true)
->get();
}
}❌ Bad Example
php
<?php
// SQL injection vulnerability
class UserController extends Controller
{
public function search(Request $request)
{
$query = $request->get('q');
// Direct SQL query - vulnerable to SQL injection
$users = DB::select("SELECT * FROM users WHERE name LIKE '%{$query}%'");
return response()->json($users);
}
}🔒 CSRF Protection
✅ Good Example
php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class VerifyCsrfToken extends Middleware
{
protected $except = [
'api/webhooks/*', // Only exclude necessary endpoints
];
public function handle(Request $request, Closure $next)
{
if ($this->shouldPassThrough($request)) {
return $next($request);
}
if ($this->isReading($request) ||
$this->runningUnitTests() ||
$this->inExceptArray($request) ||
$this->tokensMatch($request)) {
return $next($request);
}
throw new TokenMismatchException('CSRF token mismatch.');
}
}❌ Bad Example
php
<?php
// Disabling CSRF protection - security risk
class VerifyCsrfToken extends Middleware
{
protected $except = [
'*', // Disables CSRF for all routes
];
}🛡️ Rate Limiting
✅ Good Example
php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
class AuthController extends Controller
{
public function login(Request $request)
{
$key = 'login.' . $request->ip();
if (RateLimiter::tooManyAttempts($key, 5)) {
$seconds = RateLimiter::availableIn($key);
return response()->json([
'message' => 'Too many login attempts. Please try again in ' . $seconds . ' seconds.',
], 429);
}
RateLimiter::hit($key, 300); // 5 minutes
// Login logic here
}
}❌ Bad Example
php
<?php
// No rate limiting - vulnerable to brute force attacks
class AuthController extends Controller
{
public function login(Request $request)
{
// No rate limiting
// Vulnerable to brute force attacks
if (Auth::attempt($request->only('email', 'password'))) {
return response()->json(['message' => 'Login successful']);
}
return response()->json(['message' => 'Invalid credentials'], 401);
}
}🔐 API Security
✅ Good Example
php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ApiSecurityMiddleware
{
public function handle(Request $request, Closure $next)
{
// Add security headers
$response = $next($request);
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('X-Frame-Options', 'DENY');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
$response->headers->set('Content-Security-Policy', "default-src 'self'");
return $response;
}
}❌ Bad Example
php
<?php
// No security headers
class ApiController extends Controller
{
public function index()
{
// No security headers
// Vulnerable to various attacks
return response()->json(['data' => 'sensitive data']);
}
}📋 Security Checklist
✅ Do's
- Validate All Input - Use form requests and validation rules
- Use Strong Passwords - Enforce complex password requirements
- Implement Authorization - Use policies and gates
- Protect Sensitive Data - Use hidden fields and proper casts
- Enable CSRF Protection - Protect against CSRF attacks
- Implement Rate Limiting - Prevent brute force attacks
- Use HTTPS - Encrypt data in transit
- Add Security Headers - Protect against common attacks
- Keep Dependencies Updated - Regular security updates
- Log Security Events - Monitor for suspicious activity
❌ Don'ts
- Don't trust user input - Always validate and sanitize
- Don't store passwords in plain text - Always hash passwords
- Don't expose sensitive data - Use hidden fields
- Don't disable CSRF protection - Keep it enabled
- Don't ignore rate limiting - Implement proper limits
- Don't use weak encryption - Use strong algorithms
- Don't skip security headers - Add all necessary headers
- Don't ignore security updates - Keep everything updated
🔒 Security First: Security should be considered from the beginning of development, not as an afterthought. Regular security audits and penetration testing are essential.