Domain Restrictions
⚠️ Security Note: In production, implement domain whitelist to prevent unauthorized embedding and protect against clickjacking attacks.
Test Security Features:
Security Status:
Click buttons above to test security features...
Recommended Security Headers:
// In your Cloudflare Worker/Pages Function:
const securityHeaders = {
// Prevent embedding in unauthorized domains
'X-Frame-Options': 'SAMEORIGIN',
// Content Security Policy for frame ancestors
'Content-Security-Policy': "frame-ancestors 'self' https://yourdomain.com https://example.com",
// CORS configuration
'Access-Control-Allow-Origin': 'https://yourdomain.com',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Max-Age': '86400',
// Security headers
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1; mode=block',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Permissions-Policy': 'microphone=(self "https://yourdomain.com")'
};
// Apply headers to response
return new Response(content, { headers: securityHeaders });
Rate Limiting Configuration:
// Cloudflare Rate Limiting Rules:
{
"rules": [
{
"match": "/api/*",
"threshold": 100,
"period": 60,
"action": "block",
"timeout": 300
},
{
"match": "/api/ws",
"threshold": 10,
"period": 60,
"action": "challenge"
},
{
"match": "/widget",
"threshold": 50,
"period": 60,
"action": "log"
}
]
}
// In Worker code:
async function rateLimit(request) {
const ip = request.headers.get('CF-Connecting-IP');
const key = `rate_limit:${ip}`;
// Get current count from KV
const count = await KV.get(key) || 0;
if (count > 100) {
return new Response('Rate limit exceeded', { status: 429 });
}
// Increment counter
await KV.put(key, count + 1, { expirationTtl: 3600 });
return null; // Continue processing
}
Domain Whitelist Implementation:
// Whitelist allowed domains
const ALLOWED_DOMAINS = [
'https://yourdomain.com',
'https://staging.yourdomain.com',
'https://partner.com',
'http://localhost:3000', // For development
'http://localhost:8000' // For testing
];
function validateOrigin(request) {
const origin = request.headers.get('Origin');
const referer = request.headers.get('Referer');
// Check origin header
if (origin && !ALLOWED_DOMAINS.includes(origin)) {
return new Response('Unauthorized origin', { status: 403 });
}
// Check referer for iframe embedding
if (referer) {
const refererOrigin = new URL(referer).origin;
if (!ALLOWED_DOMAINS.includes(refererOrigin)) {
return new Response('Unauthorized referer', { status: 403 });
}
}
return null; // Origin is allowed
}
// Usage in request handler
export default {
async fetch(request) {
const originCheck = validateOrigin(request);
if (originCheck) return originCheck;
// Continue with normal processing
return handleRequest(request);
}
};
Content Security Policy (CSP):
// Strict CSP for the avatar iframe content
const CSP = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"media-src 'self' https:",
"connect-src 'self' wss: https:",
"font-src 'self' https://fonts.gstatic.com",
"frame-ancestors 'self' https://yourdomain.com",
"form-action 'none'",
"base-uri 'self'"
].join('; ');
// Apply CSP header
headers['Content-Security-Policy'] = CSP;
Authentication & Session Management:
// JWT-based session tokens
import { SignJWT, jwtVerify } from 'jose';
async function createSessionToken(userId, domain) {
const secret = new TextEncoder().encode(env.JWT_SECRET);
const token = await new SignJWT({
userId: userId,
domain: domain,
permissions: ['chat', 'voice']
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('24h')
.sign(secret);
return token;
}
async function validateSessionToken(token) {
try {
const secret = new TextEncoder().encode(env.JWT_SECRET);
const { payload } = await jwtVerify(token, secret);
return payload;
} catch (error) {
return null;
}
}
// Usage with iframe
const sessionToken = await createSessionToken(userId, domain);
const iframeUrl = `https://avatar.yourdomain.com/widget?token=${sessionToken}`;
Monitoring & Logging:
// Security event logging
function logSecurityEvent(type, details, request) {
const event = {
timestamp: new Date().toISOString(),
type: type,
ip: request.headers.get('CF-Connecting-IP'),
userAgent: request.headers.get('User-Agent'),
origin: request.headers.get('Origin'),
referer: request.headers.get('Referer'),
details: details
};
// Log to analytics service
fetch('https://analytics.yourdomain.com/security', {
method: 'POST',
body: JSON.stringify(event)
});
console.log('Security Event:', event);
}
// Usage examples
logSecurityEvent('RATE_LIMIT_EXCEEDED', { limit: 100 }, request);
logSecurityEvent('UNAUTHORIZED_ORIGIN', { origin: badOrigin }, request);
logSecurityEvent('SUSPICIOUS_REQUEST', { reason: 'Invalid headers' }, request);
✅ Security Checklist:
- ✅ CORS properly configured
- ✅ Rate limiting implemented
- ✅ Domain whitelist enforced
- ✅ Security headers applied
- ✅ CSP configured
- ✅ Session management in place
- ✅ Monitoring and logging active
Production Deployment Checklist:
🔒 Before going live:
- Replace localhost domains with production URLs
- Set up proper SSL certificates
- Configure rate limiting rules
- Test from all intended domains
- Set up monitoring and alerting
- Review and test error handling
- Validate all security headers