Appearance
Security Considerations
Authentication & Session
- Laravel Fortify provides the authentication backend (login, registration, password reset, 2FA); see
config/fortify.phpandroutes/auth.php. - Laravel Sanctum guards SPA sessions & API tokens. Ensure
SANCTUM_STATEFUL_DOMAINSis configured for cookie-based sessions in multi-domain setups.
Authorization
- Spatie Permission defines roles & permissions; keep them granular.
- Policies enforce model-level constraints; validate user context (
isShop()/isClient()). EnsureUserTypeShop/EnsureUserTypeClientgate whole route groups. Note they redirect (302) rather than returning 403.- Laravel Actions run
authorize()beforeasController()— a failure there is a 403.
Data Validation
- Always validate incoming data via Form Requests.
- Use DTOs (Spatie Data) internally to prevent unvalidated arrays propagating.
Sensitive Configuration
Store secrets ONLY in .env:
APP_KEY,DB_PASSWORD,SENTRY_DSN,TWILIO_AUTH_TOKEN, webhook signing secrets. Never commit.env.
Logging Hygiene
- Avoid logging PII (personally identifiable information) or credentials.
- Activity logs should capture actions (who, what, when) without sensitive payloads.
Error Reporting
- Sentry captures exceptions; configure data scrubbing rules if necessary.
- Avoid exposing stack traces in production responses (exception handling configured by Laravel).
WebSockets Security
- Private & presence channels must implement authorization callbacks (in
routes/channels.php). - Reuse permission checks; do not duplicate logic.
- Model broadcasting is intentionally per-instance (
models.{tableAlias}.{id}). Do not introduce a class-wide channel: it would authorize viaviewAny(), which is not shop-scoped, and leak newly created records across tenants.
Webhook Security
- Validate signatures with
spatie/laravel-webhook-client; secrets & profiles inconfig/webhook-client.php. bootstrap/app.phpexemptswebhook/*from CSRF — signature validation is therefore the only thing standing between the internet and those handlers. Never add an unsigned route under that prefix.- Reject unsigned or expired requests early.
- Rate limit endpoints if publicly accessible.
File & Media Handling
- Use Media Library conversions to sanitize uploads.
- Validate file types & sizes before attaching.
- Store sensitive documents on private disks (e.g., S3 with restricted ACL).
Dependencies & Updates
- Monitor Laravel, Fortify, Sanctum, Horizon, Reverb, and Sentry for security patches.
- Run
./vendor/bin/sail composer auditfor known vulnerabilities. - The Pulse dashboard carries cards for outdated (
pulse-outdated) and vulnerable (hungthai1401/vulnerable) Composer dependencies — check them periodically.
SQL & Query Safety
- Use Eloquent or parameterized queries; avoid raw concatenated SQL.
- Leverage query scopes for consistent tenancy constraints.
Rate Limiting & Throttling
- Apply throttle middleware to authentication & webhook endpoints.
- Consider per-user or per-role limits for resource-intensive operations (file uploads, PDF generation).
Input Sanitization
- Escape dynamic output in Blade (if used) or rely on Vue binding safety.
- Strip or encode HTML in user-submitted rich text if not required (XSS mitigation).
Password & Credential Management
- Rely on Laravel's hashing configuration (bcrypt/argon2id) for user passwords.
- Enforce strong password rules in Form Requests.
Transport Security
- Serve over HTTPS; ensure correct
APP_URLconfigured. - Use secure cookies in production (
SESSION_SECURE_COOKIE=true).
Session & CSRF
- CSRF protection enabled on web routes by default.
- For APIs consumed by SPAs, ensure Sanctum token / session flow is correctly set.
Backups & Disaster Recovery (Recommendations)
- Schedule DB dumps (encrypted) stored off-site.
- Maintain media backup lifecycle (versioning & retention).
Monitoring & Alerts
- Configure Sentry alerts for high error rates.
- Consider Slack/Email notifications for Horizon job failures or queue backlog thresholds.
Least Privilege Principle
- Limit roles to necessary permissions; avoid catch-all roles.
- Restrict access to administrative dashboards (Horizon, Pulse) via gate checks.
Example Channel Authorization
php
Broadcast::channel('models.cars.{id}', function (User $user, int $id) {
return $user->isShop() && Car::query()
->whereKey($id)
->where('shop_id', $user->currentShop->id)
->exists();
});Every channel callback must re-assert the tenant, not just authentication.
Consult troubleshooting.md for resolving auth-related issues.