# LiveComponents Security Guide

**Production-Ready Security for Interactive Components**

This guide covers security best practices, built-in protections, and threat mitigation strategies for LiveComponents.

## Security Architecture

```
┌─────────────────────────────────────────────────┐
│           Security Layers (Defense in Depth)     │
├─────────────────────────────────────────────────┤
│  1. CSRF Protection        (Token Validation)    │
│  2. Rate Limiting          (DoS Prevention)      │
│  3. Idempotency Keys       (Replay Protection)   │
│  4. Input Validation       (XSS/Injection)       │
│  5. Action Authorization   (Access Control)      │
│  6. State Encryption       (Data Protection)     │
└─────────────────────────────────────────────────┘
```

## 1. CSRF Protection

### Automatic CSRF Protection

**All LiveComponent requests are automatically protected** against Cross-Site Request Forgery attacks.

#### How It Works

```html
<!-- 1. CSRF token in meta tag -->
<meta name="csrf-token" content="generated-token-here">

<!-- 2. Automatically included in requests -->
<button data-lc-action="deleteAccount">Delete Account</button>

<!-- 3. Server validates token -->
```

**Request Headers**:
```http
POST /livecomponent/component-id/action
X-CSRF-Token: generated-token-here
Content-Type: application/json
```

**Server Validation**:
```php
final readonly class CsrfMiddleware
{
    public function process(Request $request, callable $next): Response
    {
        if ($this->isStateChanging($request)) {
            $this->validator->validate($request);
        }

        return $next($request);
    }
}
```

### Configuration

```env
# .env
LIVECOMPONENT_CSRF_PROTECTION=true      # Enable/disable
CSRF_TOKEN_LIFETIME=7200                # 2 hours
CSRF_REGENERATE_ON_ACTION=false         # Regenerate after each action
```

### Manual CSRF Token Refresh

```javascript
// Refresh CSRF token (e.g., after long session)
LiveComponent.refreshCsrfToken().then(() => {
    console.log('CSRF token refreshed');
});
```

### Handling CSRF Errors

```php
use App\Framework\Exception\Security\CsrfTokenMismatchException;

try {
    $this->executeAction($component, $action);
} catch (CsrfTokenMismatchException $e) {
    return new JsonResponse([
        'success' => false,
        'error' => 'Your session has expired. Please refresh the page.',
        'code' => 'CSRF_TOKEN_EXPIRED'
    ], Status::FORBIDDEN);
}
```

**Client-Side Handling**:
```javascript
window.addEventListener('livecomponent:error', (e) => {
    if (e.detail.code === 'CSRF_TOKEN_EXPIRED') {
        // Refresh token and retry
        LiveComponent.refreshCsrfToken().then(() => {
            LiveComponent.retryLastAction();
        });
    }
});
```

---

## 2. Rate Limiting

### Per-Component Rate Limits

Protect against abuse and DoS attacks with intelligent rate limiting.

#### Component-Level Configuration

```php
use App\Framework\LiveComponents\Attributes\RateLimit;

#[RateLimit(requests: 10, window: 60)] // 10 requests per 60 seconds
final class SearchComponent extends LiveComponent
{
    #[LiveAction]
    #[RateLimit(requests: 5, window: 60)] // Stricter limit for this action
    public function performSearch(): void
    {
        // Expensive search operation
    }
}
```

#### Global Configuration

```env
# .env
LIVECOMPONENT_RATE_LIMIT=60             # Default: 60 requests/minute
LIVECOMPONENT_RATE_LIMIT_WINDOW=60      # Window in seconds
LIVECOMPONENT_RATE_LIMIT_BY=ip          # 'ip', 'session', or 'user'
```

### Rate Limit Strategies

**1. IP-Based** (Anonymous users):
```php
$key = RateLimitKey::forIp($request->server->getRemoteAddr());
```

**2. Session-Based** (Authenticated sessions):
```php
$key = RateLimitKey::forSession($session->getId());
```

**3. User-Based** (Logged-in users):
```php
$key = RateLimitKey::forUser($currentUser->id);
```

### Handling Rate Limit Errors

```php
use App\Framework\Exception\Http\RateLimitExceededException;

try {
    $this->executeAction($component, $action);
} catch (RateLimitExceededException $e) {
    return new JsonResponse([
        'success' => false,
        'error' => 'Too many requests. Please slow down.',
        'retry_after' => $e->getRetryAfter()->toSeconds()
    ], Status::TOO_MANY_REQUESTS);
}
```

**Client-Side**:
```javascript
window.addEventListener('livecomponent:rate-limited', (e) => {
    const retryAfter = e.detail.retryAfter;

    // Show countdown to user
    showNotification(`Too many requests. Try again in ${retryAfter} seconds.`);

    // Disable actions temporarily
    disableActionsFor(retryAfter);
});
```

---

## 3. Idempotency Keys

Prevent duplicate submissions and ensure operations execute exactly once.

### Automatic Idempotency

**Critical actions** are automatically protected with idempotency keys:

```php
use App\Framework\LiveComponents\Attributes\Idempotent;

final class PaymentComponent extends LiveComponent
{
    #[LiveAction]
    #[Idempotent] // Ensures execute-once semantics
    public function processPayment(): void
    {
        $this->paymentGateway->charge($this->amount);
        $this->orderService->createOrder($this->cartItems);
    }
}
```

### How It Works

```
Client                          Server
  │                              │
  ├─ POST (idempotency_key: abc) ─>│ 1. Store key → Execute action
  │                              │
  ├─ POST (idempotency_key: abc) ─>│ 2. Key exists → Return cached result
  │<─ Cached Result ─────────────┤    (No re-execution)
```

### Manual Idempotency Keys

```javascript
// Generate client-side idempotency key
const idempotencyKey = crypto.randomUUID();

LiveComponent.executeAction('component-id', 'processPayment', {
    amount: 99.99
}, {
    idempotencyKey: idempotencyKey
});
```

### Configuration

```env
LIVECOMPONENT_IDEMPOTENCY_ENABLED=true
LIVECOMPONENT_IDEMPOTENCY_TTL=3600      # Cache results for 1 hour
```

---

## 4. Input Validation

### Server-Side Validation (Required)

**Never trust client input**. Always validate on the server:

```php
use App\Framework\LiveComponents\Attributes\Validated;
use App\Framework\Validation\Rules;

final class RegistrationComponent extends LiveComponent
{
    #[LiveProp]
    #[Validated([
        Rules::required(),
        Rules::email(),
        Rules::maxLength(255)
    ])]
    public string $email = '';

    #[LiveProp]
    #[Validated([
        Rules::required(),
        Rules::minLength(8),
        Rules::containsUppercase(),
        Rules::containsNumber()
    ])]
    public string $password = '';

    #[LiveAction]
    public function register(): void
    {
        // Validation happens automatically before action execution
        // If validation fails, action is not executed

        $this->userService->register(
            new Email($this->email),
            new Password($this->password)
        );
    }
}
```

### Value Object Validation

**Best Practice**: Use Value Objects for automatic validation:

```php
final readonly class Email
{
    public function __construct(public string $value)
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email format');
        }

        // Additional security checks
        if ($this->containsSuspiciousPatterns($value)) {
            throw new SecurityException('Email contains suspicious patterns');
        }
    }

    private function containsSuspiciousPatterns(string $email): bool
    {
        // Detect SQL injection attempts
        if (preg_match('/[;\'"<>]/', $email)) {
            return true;
        }

        // Detect XSS attempts
        if (preg_match('/<script|javascript:/i', $email)) {
            return true;
        }

        return false;
    }
}
```

### XSS Protection

**Automatic HTML Escaping**:

```php
public function render(): string
{
    return $this->view('component', [
        'userInput' => $this->userInput  // Automatically escaped
    ]);
}
```

**Template Escaping**:
```html
<!-- Automatic escaping -->
<div>{userInput}</div>

<!-- Raw HTML (use with extreme caution) -->
<div>{!! sanitizedHtml !!}</div>
```

**Sanitization Helper**:
```php
use App\Framework\Security\HtmlSanitizer;

final class CommentComponent extends LiveComponent
{
    #[LiveProp]
    public string $comment = '';

    #[LiveAction]
    public function postComment(): void
    {
        // Sanitize before storage
        $sanitized = $this->htmlSanitizer->sanitize($this->comment);

        $this->commentRepository->save(new Comment($sanitized));
    }
}
```

### SQL Injection Protection

**Use Parameterized Queries** (framework automatic):

```php
// ✅ Safe - parameterized
$users = $this->db->query(
    'SELECT * FROM users WHERE email = ?',
    [$this->email]
);

// ❌ NEVER do this - vulnerable to SQL injection
$users = $this->db->query(
    "SELECT * FROM users WHERE email = '{$this->email}'"
);
```

---

## 5. Action Authorization

### Role-Based Access Control

```php
use App\Framework\LiveComponents\Attributes\Authorize;

final class AdminDashboard extends LiveComponent
{
    #[LiveAction]
    #[Authorize(roles: ['admin'])]
    public function deleteUser(string $userId): void
    {
        $this->userService->delete($userId);
    }

    #[LiveAction]
    #[Authorize(permissions: ['users.edit'])]
    public function updateUserRole(string $userId, string $role): void
    {
        $this->userService->updateRole($userId, $role);
    }
}
```

### Custom Authorization

```php
use App\Framework\LiveComponents\Attributes\LiveAction;

final class PostEditor extends LiveComponent
{
    #[LiveProp]
    public string $postId = '';

    #[LiveAction]
    public function publish(): void
    {
        // Custom authorization logic
        $post = $this->postRepository->find($this->postId);

        if (!$this->canPublish($post)) {
            throw new UnauthorizedException('You cannot publish this post');
        }

        $post->publish();
        $this->postRepository->save($post);
    }

    private function canPublish(Post $post): bool
    {
        // Owner can always publish
        if ($post->authorId === $this->currentUser->id) {
            return true;
        }

        // Editors can publish if approved
        if ($this->currentUser->hasRole('editor') && $post->isApproved()) {
            return true;
        }

        return false;
    }
}
```

---

## 6. State Encryption

### Sensitive Data Protection

**Encrypt sensitive component state** before sending to client:

```php
use App\Framework\LiveComponents\Attributes\Encrypted;

final class PaymentComponent extends LiveComponent
{
    #[LiveProp]
    #[Encrypted] // Encrypted in client state
    public string $creditCardNumber = '';

    #[LiveProp]
    #[Encrypted]
    public string $cvv = '';

    #[LiveProp] // Not encrypted - safe to expose
    public string $cardholderName = '';
}
```

### How It Works

```
Server → Encrypt → Client → Store encrypted → Send back → Server → Decrypt
```

**Never expose sensitive data in plain text to the client**.

### Configuration

```env
LIVECOMPONENT_STATE_ENCRYPTION=true
VAULT_ENCRYPTION_KEY=base64:your-256-bit-key-here
```

---

## 7. Security Headers

### Automatic Security Headers

Framework automatically sets security headers for LiveComponent responses:

```http
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
Referrer-Policy: strict-origin-when-cross-origin
```

### Configure CSP for LiveComponents

```php
// config/security.php
return [
    'csp' => [
        'default-src' => ["'self'"],
        'script-src' => ["'self'", "'unsafe-inline'"], // Required for inline event handlers
        'style-src' => ["'self'", "'unsafe-inline'"],  // Required for scoped styles
        'connect-src' => ["'self'", 'wss://yourdomain.com'], // For SSE
    ]
];
```

---

## 8. OWASP Top 10 Coverage

### A01: Broken Access Control
- ✅ `#[Authorize]` attribute for actions
- ✅ Custom authorization logic
- ✅ Session-based authentication

### A02: Cryptographic Failures
- ✅ Encrypted state for sensitive data
- ✅ HTTPS enforced in production
- ✅ Secure random token generation

### A03: Injection
- ✅ Parameterized queries (automatic)
- ✅ HTML escaping (automatic)
- ✅ Value Object validation

### A04: Insecure Design
- ✅ Idempotency for critical actions
- ✅ Rate limiting per component
- ✅ Defense in depth architecture

### A05: Security Misconfiguration
- ✅ Secure defaults
- ✅ Environment-based configuration
- ✅ Security headers automatic

### A06: Vulnerable Components
- ✅ Dependency scanning (Composer)
- ✅ Regular framework updates
- ✅ Minimal external dependencies

### A07: Authentication Failures
- ✅ Session-based auth
- ✅ CSRF protection
- ✅ Rate limiting on auth actions

### A08: Software Integrity Failures
- ✅ Idempotency keys
- ✅ State encryption
- ✅ Request signing

### A09: Logging Failures
- ✅ Security event logging (OWASP)
- ✅ Action audit trail
- ✅ Error tracking

### A10: Server-Side Request Forgery
- ✅ URL validation
- ✅ Whitelist-based external requests
- ✅ Network isolation

---

## Production Security Checklist

### Pre-Deployment

- [ ] Enable CSRF protection (`LIVECOMPONENT_CSRF_PROTECTION=true`)
- [ ] Configure rate limiting for all components
- [ ] Add `#[Idempotent]` to critical actions (payments, orders)
- [ ] Validate all user inputs with `#[Validated]` or Value Objects
- [ ] Add `#[Authorize]` to admin/privileged actions
- [ ] Encrypt sensitive state with `#[Encrypted]`
- [ ] Review and test all authorization logic
- [ ] Set up OWASP security event logging
- [ ] Configure security headers and CSP
- [ ] Enable HTTPS and HSTS headers

### Monitoring

- [ ] Monitor rate limit violations
- [ ] Track CSRF token errors
- [ ] Alert on repeated authorization failures
- [ ] Log all idempotency key violations
- [ ] Track input validation failures
- [ ] Monitor for unusual activity patterns

### Incident Response

- [ ] Have rollback plan for compromised components
- [ ] Document security event response procedures
- [ ] Set up automated alerts for critical security events
- [ ] Regular security audit schedule
- [ ] Penetration testing for critical components

---

## Security Best Practices

### 1. Principle of Least Privilege

```php
// ❌ Bad - expose too much
#[LiveProp]
public User $currentUser;

// ✅ Good - expose only what's needed
#[LiveProp]
public string $currentUserName;

#[LiveProp]
public bool $isAdmin;
```

### 2. Validate, Don't Filter

```php
// ❌ Bad - filtering can be bypassed
$email = filter_var($input, FILTER_SANITIZE_EMAIL);

// ✅ Good - validate and reject invalid input
if (!filter_var($input, FILTER_VALIDATE_EMAIL)) {
    throw new InvalidArgumentException('Invalid email');
}
$email = $input;
```

### 3. Fail Securely

```php
// ❌ Bad - defaults to allowing access
if ($this->currentUser->hasRole('admin') ?? true) {
    $this->deleteUser();
}

// ✅ Good - defaults to denying access
if ($this->currentUser?->hasRole('admin') === true) {
    $this->deleteUser();
} else {
    throw new UnauthorizedException();
}
```

### 4. Never Trust Client State

```php
// ❌ Bad - trust client-provided data
#[LiveProp]
public bool $isAdmin = false; // Client can modify this!

// ✅ Good - compute from server-side source of truth
public function isAdmin(): bool
{
    return $this->currentUser?->hasRole('admin') ?? false;
}
```

---

## Reporting Security Issues

**Please do not open public issues for security vulnerabilities.**

Email: security@example.com

Include:
- Component name and version
- Detailed description of vulnerability
- Steps to reproduce
- Potential impact assessment

We aim to respond within 24 hours and provide fixes within 7 days for critical vulnerabilities.

---

**Next**: [Performance Guide](performance-guide.md) →
