Input Validation
Always validate user input using Form Requests:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;
class RegisterRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => [
'required',
'string',
'email:rfc,dns',
'max:255',
'unique:users',
],
'password' => [
'required',
'confirmed',
Password::min(8)
->mixedCase()
->numbers()
->symbols()
->uncompromised(),
],
];
}
}SQL Injection Prevention
Eloquent and Query Builder protect against SQL injection by default, but be careful with raw queries:
<?php
// DANGEROUS - SQL Injection vulnerability
$users = DB::select("SELECT * FROM users WHERE name = '" . $name . "'");
// SAFE - Using parameter binding
$users = DB::select("SELECT * FROM users WHERE name = ?", [$name]);
// SAFE - Using Eloquent
$users = User::where('name', $name)->get();
// SAFE - Using whereRaw with bindings
$users = User::whereRaw('LOWER(name) = ?', [strtolower($name)])->get();XSS Prevention
Blade automatically escapes output. Use {!! !!} sparingly and only with trusted content:
<?php
// In your Blade template:
// SAFE - Escaped output
{{ $user->name }}
{{ $user->bio }}
// DANGEROUS - Unescaped output (only use with trusted content)
{!! $post->content !!}
// If you must render HTML, sanitize it first:
{!! clean($post->content) !!} // Using a sanitizer packageAuthorization with Policies
Use policies to control access to resources:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
public function view(User $user, Post $post): bool
{
return $post->is_published || $user->id === $post->user_id;
}
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->isAdmin();
}
}
// In controller:
public function update(UpdatePostRequest $request, Post $post)
{
$this->authorize('update', $post);
// ...
}Rate Limiting
Protect against brute force attacks:
<?php
// In routes/api.php
Route::middleware(['throttle:api'])->group(function () {
Route::post('/login', [AuthController::class, 'login']);
});
// Custom rate limiter in AppServiceProvider
RateLimiter::for('login', function (Request $request) {
return [
Limit::perMinute(5)->by($request->ip()),
Limit::perMinute(10)->by($request->input('email')),
];
});Conclusion
Security should be built into your application from the start. Validate all input, use Laravel's built-in protections, and always follow the principle of least privilege.
Written by Abdo Shrief Senior Laravel Developer based in Cairo.
https://www.abdoshrief.tech