# 🔐 Security Best Practices - Quick Reference

## 📝 Blade Template Security

### ✅ DO (Escapeing Output)
```blade
<!-- Auto-escape HTML -->
{{ $user->name }}
{{ session('success') }}
{{ $data }}

<!-- Display unescaped (ONLY for trusted content) -->
{!! $trustedHtmlContent !!}
```

### ❌ DON'T
```blade
<!-- NEVER use for user input or flash messages -->
{!! $user->name !!}
{!! session('success') !!}
```

---

## 🛡️ Input Validation

### ✅ Always Validate
```php
$validated = $request->validate([
    'email' => 'required|email|max:255',
    'name' => 'required|string|max:255',
    'file' => 'required|image|mimes:jpeg,png,jpg|max:2048',
    'nik' => 'required|numeric|digits:16',
]);
```

### ❌ Never Trust Raw Input
```php
// BAD
$user->update($request->all());

// GOOD
$user->update($request->validated());
```

---

## 🗄️ Database Security

### ✅ Use Eloquent/Query Builder
```php
// Safe from SQL injection
User::where('email', $email)->first();
DB::table('users')->where('id', $id)->get();
```

### ❌ Avoid Raw Queries
```php
// DANGEROUS
DB::select("SELECT * FROM users WHERE email = '$email'");

// If you MUST use raw, bind parameters
DB::select("SELECT * FROM users WHERE email = ?", [$email]);
```

---

## 🔐 Authentication & Authorization

### ✅ Check Permissions
```php
// Check if authenticated
if (!Auth::check()) {
    return redirect()->route('login');
}

// Check role
if ($user->role->slug !== 'admin') {
    abort(403);
}

// Check ownership
if ($post->user_id !== Auth::id()) {
    abort(403);
}
```

### Route Protection
```php
Route::middleware(['auth', 'role:superadmin'])->group(function () {
    Route::resource('users', UserController::class);
});
```

---

## 📁 File Upload Security

### ✅ Validate EVERYTHING
```php
$request->validate([
    'photo' => [
        'required',
        'image',
        'mimes:jpeg,png,jpg',
        'max:2048', // KB
        'dimensions:min_width=100,min_height=100,max_width=4000,max_height=4000'
    ],
]);

// Generate safe filename
$extension = $file->getClientOriginalExtension();
$filename = time() . '_' . Str::random(10) . '.' . $extension;
$path = $file->storeAs('uploads', $filename, 'public');
```

### ❌ Never Trust Original Filename
```php
// DANGEROUS
$file->move('uploads/', $request->file('photo')->getClientOriginalName());
```

---

## 🔑 Mass Assignment Protection

### ✅ Define Fillable
```php
class User extends Model
{
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
    
    protected $hidden = [
        'password',
        'remember_token',
    ];
}
```

### ❌ Never Use Guarded Empty
```php
// VERY DANGEROUS
protected $guarded = [];
```

---

## 🍪 Session & Cookies

### Production .env Settings
```env
SESSION_LIFETIME=60
SESSION_ENCRYPT=true
SESSION_SECURE_COOKIE=true  # HTTPS only
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
```

### Regenerate After Login
```php
public function login(Request $request)
{
    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return redirect()->intended('dashboard');
    }
}
```

---

## 🚦 Rate Limiting

### Login Protection
```php
use Illuminate\Support\Facades\RateLimiter;

protected function checkTooManyFailedAttempts(Request $request)
{
    $key = Str::lower($request->input('email')).'|'.$request->ip();
    
    if (RateLimiter::tooManyAttempts($key, 5)) {
        $seconds = RateLimiter::availableIn($key);
        throw ValidationException::withMessages([
            'email' => "Too many attempts. Try again in $seconds seconds.",
        ]);
    }
}

// After failed attempt
RateLimiter::hit($key, 300); // 5 minutes

// After successful login
RateLimiter::clear($key);
```

### API Rate Limiting
```php
Route::middleware('throttle:60,1')->group(function () {
    Route::get('/api/data', [ApiController::class, 'index']);
});
```

---

## 🔒 CSRF Protection

### ✅ Always Include @csrf
```blade
<form method="POST" action="{{ route('users.store') }}">
    @csrf
    <!-- form fields -->
</form>
```

### API Exceptions (if needed)
```php
// app/Http/Middleware/VerifyCsrfToken.php
protected $except = [
    'webhook/*',
];
```

---

## 🌐 Security Headers Checklist

Headers automatically added by `SecurityHeaders` middleware:
- ✅ X-Frame-Options
- ✅ X-Content-Type-Options
- ✅ X-XSS-Protection
- ✅ Referrer-Policy
- ✅ Content-Security-Policy
- ✅ Permissions-Policy
- ✅ Strict-Transport-Security (production)

---

## 🔍 Common Vulnerabilities to Avoid

### 1. XSS (Cross-Site Scripting)
```blade
<!-- BAD -->
{!! $userInput !!}

<!-- GOOD -->
{{ $userInput }}
```

### 2. SQL Injection
```php
// BAD
DB::select("SELECT * FROM users WHERE id = " . $id);

// GOOD
User::find($id);
```

### 3. CSRF
```blade
<!-- BAD: Missing @csrf -->
<form method="POST">

<!-- GOOD -->
<form method="POST">
    @csrf
```

### 4. Mass Assignment
```php
// BAD
User::create($request->all());

// GOOD
User::create($request->validated());
```

### 5. Insecure File Upload
```php
// BAD
$file->move('uploads/', $file->getClientOriginalName());

// GOOD
$validated = $request->validate(['file' => 'required|image|max:2048']);
$path = $request->file('file')->store('uploads', 'public');
```

---

## 🎯 Quick Security Checklist

### Before Every Deployment
- [ ] `APP_DEBUG=false`
- [ ] `APP_ENV=production`
- [ ] SSL certificate valid
- [ ] Database credentials secure
- [ ] All inputs validated
- [ ] No raw queries with user input
- [ ] CSRF tokens on all forms
- [ ] Sessions encrypted
- [ ] Security headers enabled
- [ ] Rate limiting configured
- [ ] Error logging active
- [ ] Backups scheduled

### Code Review Checklist
- [ ] No `{!! !!}` with user input
- [ ] All forms have `@csrf`
- [ ] Validation on all `store()` and `update()`
- [ ] File uploads validated
- [ ] Authorization checks present
- [ ] No `$guarded = []`
- [ ] Passwords hashed before save
- [ ] Sensitive data in `.gitignore`

---

## 📚 Resources

- [Laravel Security Documentation](https://laravel.com/docs/security)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Security Headers Scanner](https://securityheaders.com)
- [Mozilla Observatory](https://observatory.mozilla.org)

---

**Print this and keep it visible while coding!**
