Files
michaelschiemer/tests/e2e/livecomponents/SECURITY-TESTS.md
Michael Schiemer fc3d7e6357 feat(Production): Complete production deployment infrastructure
- Add comprehensive health check system with multiple endpoints
- Add Prometheus metrics endpoint
- Add production logging configurations (5 strategies)
- Add complete deployment documentation suite:
  * QUICKSTART.md - 30-minute deployment guide
  * DEPLOYMENT_CHECKLIST.md - Printable verification checklist
  * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle
  * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference
  * production-logging.md - Logging configuration guide
  * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation
  * README.md - Navigation hub
  * DEPLOYMENT_SUMMARY.md - Executive summary
- Add deployment scripts and automation
- Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment
- Update README with production-ready features

All production infrastructure is now complete and ready for deployment.
2025-10-25 19:18:37 +02:00

865 lines
20 KiB
Markdown

# LiveComponents Security E2E Tests
Comprehensive security testing suite for LiveComponents framework covering CSRF protection, rate limiting, idempotency, input sanitization, authorization, and session security.
## Overview
This test suite validates critical security features:
- **CSRF Protection**: Token validation for state-changing actions
- **Rate Limiting**: Protection against abuse and DoS attacks
- **Idempotency**: Preventing duplicate action execution
- **Input Sanitization**: XSS and injection prevention
- **Authorization**: Access control and permissions
- **Session Security**: Session management and hijacking prevention
- **Content Security Policy**: CSP header enforcement
## Quick Start
### Prerequisites
```bash
# Ensure Playwright is installed
npm install
# Install browser binaries
npx playwright install chromium
# Ensure development server is running
make up
```
### Running Security Tests
```bash
# Run all security tests
npm run test:security
# Run specific security test category
npx playwright test security.spec.js --grep "CSRF Protection"
npx playwright test security.spec.js --grep "Rate Limiting"
npx playwright test security.spec.js --grep "Idempotency"
# Run with visible browser (for debugging)
npm run test:security:headed
# Run with debug mode
npm run test:security:debug
```
## Test Categories
### 1. CSRF Protection (4 tests)
**Purpose:** Validate Cross-Site Request Forgery protection for all state-changing actions.
#### Test: CSRF token included in requests
**Validates:**
- CSRF token present in action requests
- Token included in headers (`X-CSRF-Token`) or POST data (`_csrf_token`)
- Framework automatically handles token management
**Expected Behavior:**
```javascript
// Request includes CSRF token
headers: {
'X-CSRF-Token': 'generated-token-value'
}
// OR in POST data
{
_csrf_token: 'generated-token-value',
action: 'increment',
params: { ... }
}
```
#### Test: Reject action without CSRF token
**Validates:**
- Requests without CSRF token are rejected
- Appropriate error message returned
- No state changes occur
**Expected Response:**
```
Status: 403 Forbidden
Error: "CSRF token validation failed"
```
#### Test: Reject action with invalid CSRF token
**Validates:**
- Invalid/expired tokens are rejected
- Token tampering detected
- Security event logged
**Test Approach:**
```javascript
// Replace token with invalid value
headers: { 'X-CSRF-Token': 'invalid-token-12345' }
// Expected: 403 Forbidden
```
#### Test: CSRF token rotation
**Validates:**
- Tokens rotate after usage (optional, framework-dependent)
- New token provided in response
- Old token invalidated
**Rotation Strategy:**
- **Per-request rotation**: New token after each action
- **Time-based rotation**: New token after TTL
- **Session-based**: Token tied to session lifetime
### 2. Rate Limiting (5 tests)
**Purpose:** Prevent abuse through excessive action calls and DoS attacks.
#### Test: Enforce rate limit on rapid calls
**Configuration:**
- **Default Limit**: 10 requests per minute
- **Window**: 60 seconds sliding window
- **Action**: Block excess requests
**Test Approach:**
```javascript
// Trigger 20 rapid action calls
for (let i = 0; i < 20; i++) {
await triggerAction();
}
// Expected: First 10 succeed, remaining 10 blocked
// Success rate: 50% (10/20)
```
**Expected Error:**
```
Status: 429 Too Many Requests
Error: "Rate limit exceeded"
Retry-After: 45 // seconds
```
#### Test: Retry-After header
**Validates:**
- `Retry-After` header present in 429 responses
- Header contains remaining cooldown time
- Client can use header for backoff
**Response Format:**
```http
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
```
#### Test: Rate limit reset after cooldown
**Validates:**
- Rate limit resets after window expires
- Actions allowed again after cooldown
- No lingering restrictions
**Timeline:**
```
00:00 - First 10 requests succeed
00:01 - Next 10 requests blocked (rate limited)
00:01 - Retry-After: 59 seconds
01:00 - Window expires, limit resets
01:01 - New requests succeed
```
#### Test: Separate limits per action type
**Validates:**
- Different actions have independent rate limits
- Hitting limit on action A doesn't affect action B
- Granular control per action
**Configuration:**
```javascript
const RATE_LIMITS = {
'increment': { limit: 10, window: 60 },
'delete': { limit: 5, window: 300 },
'search': { limit: 30, window: 60 }
};
```
#### Test: IP-based rate limiting
**Validates:**
- Rate limits applied per IP address
- Multiple users from same IP share limit
- Different IPs have independent limits
**Scenario:**
```
User A (IP: 192.168.1.1) - 10 requests
User B (IP: 192.168.1.1) - 10 requests
Result: Both users share 10-request limit for that IP
```
### 3. Idempotency (4 tests)
**Purpose:** Ensure critical operations execute exactly once, even with duplicate requests.
#### Test: Handle duplicate calls idempotently
**Validates:**
- Duplicate action calls with same idempotency key are ignored
- Operation executes exactly once
- State changes applied only once
**Test Approach:**
```javascript
// First call with idempotency key
await callAction('increment', { idempotencyKey: 'key-123' });
// Counter: 0 → 1
// Duplicate call (same key)
await callAction('increment', { idempotencyKey: 'key-123' });
// Counter: 1 (unchanged, duplicate ignored)
```
#### Test: Allow different idempotency keys
**Validates:**
- Different idempotency keys allow separate executions
- Each unique key represents distinct operation
- No interference between different keys
**Test Approach:**
```javascript
await callAction('increment', { idempotencyKey: 'key-1' }); // Executes
await callAction('increment', { idempotencyKey: 'key-2' }); // Executes
await callAction('increment', { idempotencyKey: 'key-1' }); // Ignored (duplicate)
```
#### Test: Idempotency key expiration
**Validates:**
- Keys expire after TTL (default: 24 hours)
- Expired keys allow re-execution
- Storage cleanup for old keys
**Timeline:**
```
00:00 - Action with key-123 executes
00:00 - Duplicate with key-123 ignored
24:00 - Key-123 expires
24:01 - Action with key-123 executes again (new operation)
```
#### Test: Cached result for duplicate action
**Validates:**
- Duplicate calls return cached result
- No server-side re-execution
- Consistent response for same key
**Expected Behavior:**
```javascript
const result1 = await callAction('createOrder', {
idempotencyKey: 'order-123'
});
// Returns: { orderId: 'abc', total: 100 }
const result2 = await callAction('createOrder', {
idempotencyKey: 'order-123'
});
// Returns: { orderId: 'abc', total: 100 } (cached, same result)
```
### 4. Input Sanitization & XSS Prevention (5 tests)
**Purpose:** Prevent XSS, injection attacks, and malicious input processing.
#### Test: Sanitize HTML in action parameters
**Validates:**
- HTML tags stripped or escaped
- Script tags prevented from execution
- Safe rendering of user input
**Attack Vectors Tested:**
```javascript
// XSS attempts
'<script>alert("XSS")</script>'
'<img src=x onerror=alert("XSS")>'
'<svg onload=alert("XSS")>'
'<iframe src="javascript:alert(\'XSS\')"></iframe>'
```
**Expected Output:**
```html
<!-- Input: <script>alert("XSS")</script> -->
<!-- Output: &lt;script&gt;alert("XSS")&lt;/script&gt; -->
<!-- Displayed as text, not executed -->
```
#### Test: Escape HTML entities
**Validates:**
- Special characters properly escaped
- No raw HTML injection
- Content-Type headers correct
**Entity Escaping:**
```
< → &lt;
> → &gt;
& → &amp;
" → &quot;
' → &#x27;
```
#### Test: Prevent JavaScript injection
**Validates:**
- `javascript:` protocol blocked in URLs
- Event handlers stripped
- No inline script execution
**Blocked Patterns:**
```javascript
javascript:alert('XSS')
data:text/html,<script>alert('XSS')</script>
vbscript:msgbox("XSS")
```
#### Test: Validate file paths
**Validates:**
- Path traversal attacks prevented
- Only allowed directories accessible
- Absolute paths rejected
**Attack Attempts:**
```
../../../etc/passwd
..\..\windows\system32\config\sam
/etc/passwd
C:\Windows\System32\config\SAM
```
**Expected:** All rejected with "Invalid path" error
#### Test: Prevent SQL injection
**Validates:**
- Parameterized queries used
- SQL keywords escaped
- No raw query concatenation
**Attack Vectors:**
```sql
'; DROP TABLE users; --
' OR '1'='1
admin'--
' UNION SELECT * FROM users--
```
**Expected:** Treated as literal search strings, no SQL execution
### 5. Authorization (3 tests)
**Purpose:** Enforce access control and permission checks.
#### Test: Reject unauthorized action calls
**Validates:**
- Actions requiring authentication are protected
- Anonymous users blocked
- Clear error message
**Protected Action:**
```php
#[Action]
#[RequiresAuth]
public function deleteAllData(): array
{
// Only authenticated users
}
```
**Expected Response:**
```
Status: 401 Unauthorized
Error: "Authentication required"
```
#### Test: Allow authorized action calls
**Validates:**
- Authenticated users can access protected actions
- Valid session/token accepted
- Actions execute successfully
**Flow:**
```
1. User logs in → Session created
2. Call protected action → Success
3. Action executes → Result returned
```
#### Test: Role-based authorization
**Validates:**
- Different roles have different permissions
- Role checks enforced
- Insufficient permissions rejected
**Role Matrix:**
```
Action: deleteAllData
- admin: ✅ Allowed
- moderator: ❌ Forbidden
- user: ❌ Forbidden
Action: editOwnProfile
- admin: ✅ Allowed
- moderator: ✅ Allowed
- user: ✅ Allowed
```
### 6. Session Security (3 tests)
**Purpose:** Secure session management and hijacking prevention.
#### Test: Invalidate session after logout
**Validates:**
- Session properly destroyed on logout
- Session cookie removed
- Subsequent requests rejected
**Flow:**
```
1. Login → Session active
2. Call protected action → Success
3. Logout → Session destroyed
4. Call protected action → 401 Unauthorized
```
#### Test: Detect session hijacking
**Validates:**
- Session binding to IP/User-Agent
- Suspicious activity detected
- Stolen sessions rejected
**Detection Criteria:**
- IP address change
- User-Agent change
- Geo-location anomaly
- Concurrent sessions from different locations
**Response:**
```
Status: 403 Forbidden
Error: "Session invalid - security violation detected"
Action: Session terminated, user notified
```
#### Test: Enforce session timeout
**Validates:**
- Sessions expire after inactivity
- Timeout configurable (default: 30 minutes)
- Expired sessions rejected
**Timeline:**
```
00:00 - Login
00:15 - Action call (session refreshed)
00:45 - No activity for 30 minutes
00:46 - Action call → 401 Session Expired
```
### 7. Content Security Policy (2 tests)
**Purpose:** Enforce CSP headers to prevent injection attacks.
#### Test: CSP headers present
**Validates:**
- `Content-Security-Policy` header set
- Proper directives configured
- No unsafe configurations
**Expected Header:**
```http
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-xyz123';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' wss://localhost;
font-src 'self' https://fonts.gstatic.com;
```
#### Test: Block inline scripts via CSP
**Validates:**
- Inline scripts blocked by CSP
- Console errors for violations
- CSP reports generated
**Violation Detection:**
```javascript
// Attempt to inject inline script
const script = document.createElement('script');
script.textContent = 'alert("XSS")';
document.body.appendChild(script);
// Expected Console Error:
// "Refused to execute inline script because it violates
// Content Security Policy directive: 'script-src self'"
```
## Test Page Requirements
Tests assume the following test page at `https://localhost/livecomponents/test/security`:
### Required HTML Elements
```html
<div data-component-id="counter:test">
<div id="counter-value">0</div>
<button id="trigger-action">Trigger Action</button>
<div class="action-success" style="display:none">Success</div>
<div class="error-message" style="display:none"></div>
<div class="rate-limit-error" style="display:none" data-retry-after=""></div>
</div>
<div data-component-id="text:test">
<div id="text-display"></div>
</div>
<div data-component-id="admin:test">
<div class="authorization-error" style="display:none"></div>
</div>
<!-- Login Form -->
<form id="login-form">
<input type="text" id="username" name="username" />
<input type="password" id="password" name="password" />
<button type="submit" id="login-btn">Login</button>
</form>
<div class="logged-in-indicator" style="display:none"></div>
<button id="logout-btn" style="display:none">Logout</button>
<!-- CSRF Token -->
<meta name="csrf-token" content="generated-token-value">
```
### Required Component Actions
```php
final readonly class SecurityTestComponent extends LiveComponent
{
#[Action]
#[RateLimit(requests: 10, window: 60)]
public function triggerAction(): array
{
return ['success' => true];
}
#[Action]
public function increment(string $idempotencyKey = null): array
{
// Idempotent increment
if ($idempotencyKey && $this->hasExecuted($idempotencyKey)) {
return $this->getCachedResult($idempotencyKey);
}
$newValue = $this->state->get('counter') + 1;
$this->state->set('counter', $newValue);
$result = ['value' => $newValue];
if ($idempotencyKey) {
$this->cacheResult($idempotencyKey, $result);
}
return $result;
}
#[Action]
public function setText(string $text): array
{
// Sanitize HTML
$sanitizedText = htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
$this->state->set('text', $sanitizedText);
return ['text' => $sanitizedText];
}
#[Action]
#[RequiresAuth]
#[RequiresRole('admin')]
public function performAdminAction(): array
{
return ['success' => true];
}
}
```
## Configuration
### Environment Variables
```env
# CSRF Protection
CSRF_TOKEN_TTL=7200 # 2 hours
CSRF_ROTATE_ON_ACTION=false # Rotate token after each action
# Rate Limiting
RATE_LIMIT_ENABLED=true
RATE_LIMIT_DEFAULT=60 # Requests per window
RATE_LIMIT_WINDOW=60 # Window in seconds
RATE_LIMIT_STORAGE=redis # Storage backend
# Idempotency
IDEMPOTENCY_ENABLED=true
IDEMPOTENCY_TTL=86400 # 24 hours
IDEMPOTENCY_STORAGE=redis
# Session Security
SESSION_LIFETIME=1800 # 30 minutes
SESSION_SECURE=true # HTTPS only
SESSION_HTTP_ONLY=true # No JavaScript access
SESSION_SAME_SITE=strict # SameSite cookie attribute
SESSION_BIND_IP=true # Bind to IP address
SESSION_BIND_USER_AGENT=true # Bind to User-Agent
# Content Security Policy
CSP_ENABLED=true
CSP_REPORT_ONLY=false # Enforce CSP (not just report)
CSP_REPORT_URI=/csp-report # CSP violation reporting endpoint
```
## Troubleshooting
### CSRF Tests Failing
**Symptoms:**
- CSRF token not found in requests
- All CSRF tests failing
**Solutions:**
1. **Verify CSRF middleware enabled:**
```php
// In middleware stack
new CsrfMiddleware($csrfTokenGenerator)
```
2. **Check meta tag presence:**
```html
<meta name="csrf-token" content="...">
```
3. **Verify JavaScript includes token:**
```javascript
const token = document.querySelector('meta[name="csrf-token"]').content;
// Include in requests
```
### Rate Limiting Not Working
**Symptoms:**
- All rapid requests succeed
- No 429 responses
**Solutions:**
1. **Check rate limit configuration:**
```bash
# Verify environment variables
docker exec php php -r "echo getenv('RATE_LIMIT_ENABLED');"
```
2. **Verify rate limiter initialized:**
```php
// Check DI container
$rateLimiter = $container->get(RateLimiter::class);
```
3. **Check storage backend:**
```bash
# For Redis backend
docker exec redis redis-cli KEYS "rate_limit:*"
```
### Idempotency Issues
**Symptoms:**
- Duplicate requests execute
- Idempotency keys not working
**Solutions:**
1. **Check idempotency key format:**
```javascript
// Must be unique per operation
idempotencyKey: `${userId}-${operationId}-${timestamp}`
```
2. **Verify storage:**
```bash
# For Redis
docker exec redis redis-cli KEYS "idempotency:*"
```
3. **Check TTL:**
```bash
# Verify keys not expiring too quickly
docker exec redis redis-cli TTL "idempotency:key-123"
```
### Authorization Failures
**Symptoms:**
- Authorized users rejected
- Role checks failing
**Solutions:**
1. **Verify session active:**
```javascript
const sessionActive = await page.evaluate(() => {
return window.__sessionActive === true;
});
```
2. **Check role assignment:**
```php
// Verify user roles
$user->hasRole('admin'); // Should return true
```
3. **Review authorization middleware:**
```php
// Ensure middleware in correct order
[AuthMiddleware, RoleMiddleware, ...]
```
## CI/CD Integration
### GitHub Actions
```yaml
name: Security Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * *' # Daily
jobs:
security-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npx playwright install --with-deps chromium
- name: Start dev server
run: make up
- name: Run security tests
run: npm run test:security
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: security-test-results
path: test-results/
- name: Security alert on failure
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🚨 Security Tests Failed',
labels: ['security', 'urgent'],
body: 'Security tests failed. Immediate review required.'
});
```
## Best Practices
### 1. Regular Security Testing
- Run security tests before every deployment
- Include in CI/CD pipeline
- Monitor for new vulnerabilities
- Update tests for new attack vectors
### 2. Defense in Depth
- Multiple security layers (CSRF + Rate Limit + Auth)
- Fail securely (block by default, allow explicitly)
- Log all security events
- Alert on suspicious patterns
### 3. Security Monitoring
- Track failed authentication attempts
- Monitor rate limit violations
- Alert on XSS attempts
- Log authorization failures
### 4. Incident Response
- Defined escalation procedures
- Security event playbooks
- Regular security drills
- Post-incident analysis
## Resources
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [OWASP CSRF Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
- [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
- [Content Security Policy Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)
- [Rate Limiting Best Practices](https://cloud.google.com/architecture/rate-limiting-strategies-techniques)
## Support
For security issues or questions:
1. Review this documentation
2. Check framework security documentation
3. Consult OWASP guidelines
4. **Report security vulnerabilities privately** to security@example.com
5. Create GitHub issue for non-security test failures