| Check | Vue + Laravel Implementation |
|---|---|
| Passwords hashed | bcrypt() / Hash::make() — NEVER store plain text |
| Brute force protection | Laravel throttle middleware (5 attempts/min) |
| Token storage | httpOnly cookie or flutter_secure_storage — NOT localStorage |
| Token expiry | Short-lived tokens (1h access, 7d refresh) |
| Logout | Delete/revoke token server-side, not just client |
| Password reset | Signed time-limited URL, single-use token |
// Laravel throttle example
Route::middleware('throttle:5,1')->post('/login', ...); // 5 per minute
// Check token revocation on logout
public function logout(Request $request) {
$request->user()->currentAccessToken()->delete(); // Sanctum
return response()->json(['message' => 'Logged out']);
}
// BAD - Anyone with a token can delete any product
public function destroy(Product $product) {
$product->delete(); // ❌ No ownership check!
}
// GOOD - Check ownership first
public function destroy(Product $product) {
if ($product->user_id !== auth()->id()) {
return response()->json(['message' => 'Forbidden'], 403);
}
$product->delete();
}
// Or use Laravel Policy (cleaner)
$this->authorize('delete', $product);
// Policy (app/Policies/ProductPolicy.php)
public function delete(User $user, Product $product): bool {
return $user->id === $product->user_id || $user->isAdmin();
}
// Always validate on server-side (client-side alone is not enough)
$data = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'price' => 'required|numeric|min:0|max:999999',
'url' => 'nullable|url|max:500',
]);
// SQL Injection — Eloquent/QueryBuilder is safe by default
Product::where('name', $request->name)->get(); // ✅ parameterized
DB::table('products')->where('name', '?', [$name])->get(); // ✅
// NEVER do this:
DB::select("SELECT * FROM products WHERE name = '{$request->name}'"); // ❌ SQL injection!
// XSS Prevention — Blade auto-escapes
{{ $userInput }} // ✅ escaped — safe
{!! $userInput !!} // ❌ unescaped — only use for trusted HTML
# Run this to check for accidentally tracked secrets git log --all --oneline | head -20 git diff HEAD~1 -- .env # check if .env was committed # .gitignore MUST include: .env .env.local .env.production # Use environment variables for ALL secrets: APP_KEY=base64:... DB_PASSWORD=... JWT_SECRET=... STRIPE_SECRET=... # Audit existing git history for secrets: git log -p | grep -i "password\|secret\|token\|key" | head -50 # If secret was committed — rotate it immediately: 1. Change the secret in the service 2. git filter-repo to remove from history (destructive) 3. Force push and notify team
// Laravel — CSRF is auto-enabled for web routes
// Every form needs @csrf:
<form method="POST" action="/products">
@csrf
...
</form>
// API routes (Sanctum SPA) — use CSRF cookie
// Step 1: GET /sanctum/csrf-cookie (sets cookie)
// Step 2: Include X-XSRF-TOKEN header in every POST/PUT/DELETE
// Axios auto-handles this with withCredentials: true
axios.defaults.withCredentials = true;
// Excluded from CSRF: routes/api.php (stateless Sanctum token auth)
# PHP/Composer — check for known vulnerabilities composer audit # or composer require enlightn/security-checker --dev # Node.js/npm npm audit npm audit fix # auto-fix safe patches # Check for outdated packages composer outdated npm outdated # Key packages to keep updated: # - Laravel framework itself # - laravel/sanctum # - Authentication libraries # - Any package that handles user input
# Nginx security headers (add to server block)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
# Verify with: https://securityheaders.com
# HTTPS enforce in Laravel
# AppServiceProvider.php
if (app()->environment('production')) {
URL::forceScheme('https');
}
// Log security events
use Illuminate\Support\Facades\Log;
public function login(Request $request) {
if (!auth()->attempt($creds)) {
Log::warning('Failed login', ['email' => $request->email, 'ip' => $request->ip()]);
return response()->json(['message' => 'Invalid credentials'], 401);
}
Log::info('User logged in', ['user_id' => auth()->id(), 'ip' => $request->ip()]);
...
}
// Laravel telescope (dev) or Sentry (production)
composer require sentry/sentry-laravel
// Monitor log files on server
sudo tail -f /var/www/myapp/api/storage/logs/laravel.log
sudo tail -f /var/log/nginx/error.log
Portfolio → Vue CRUD → Laravel API → Flutter App → Deploy → Security Review
Full-Stack Developer Journey Complete! Portfolio ပြပြီး job ရဖို့ ကြိုးစားပါ 💪