6.5 KiB
6.5 KiB
Security & Architecture Improvements
🔒 Current Security Issues
1. API Key Exposure in Frontend
Issue: EmailSender component stores API key in browser state
// CURRENT - INSECURE
const [apiKey, setApiKey] = useState('') // Exposed in browser
Fix: Remove frontend API key input entirely
// RECOMMENDED - Remove EmailSender from production
// Only use for development testing
2. Missing Input Validation
Issue: No validation for email addresses, URLs, or data inputs
// CURRENT - NO VALIDATION
const handleSendEmail = async () => {
// Direct use without validation
}
Fix: Add proper validation
// RECOMMENDED
import { z } from 'zod'
const emailSchema = z.object({
to: z.string().email(),
eventName: z.string().min(1).max(200),
ctaUrl: z.string().url()
})
const validateInput = (data: unknown) => {
return emailSchema.parse(data)
}
3. Missing Rate Limiting
Issue: No protection against email spam/abuse
// CURRENT - NO RATE LIMITING
await resend.emails.send(payload)
Fix: Implement rate limiting
// RECOMMENDED
import rateLimit from 'express-rate-limit'
const emailLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // limit each IP to 10 emails per windowMs
message: 'Too many emails sent, please try again later'
})
app.use('/api/send-email', emailLimiter)
4. Missing Environment Variables
Issue: No .env file or environment configuration
# MISSING
RESEND_API_KEY=
FROM_DOMAIN=
RATE_LIMIT_MAX=
Fix: Add environment configuration
# .env
RESEND_API_KEY=re_your_key_here
FROM_DOMAIN=yourdomain.com
RATE_LIMIT_MAX=10
RATE_LIMIT_WINDOW_MS=900000
5. Missing Content Security Policy
Issue: No CSP headers for XSS protection
// RECOMMENDED - Add to backend
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy',
"default-src 'self'; script-src 'none'; object-src 'none';"
)
next()
})
🏗️ Architecture Improvements
1. Add Environment Configuration
// config/email.ts
export const emailConfig = {
resend: {
apiKey: process.env.RESEND_API_KEY!,
fromDomain: process.env.FROM_DOMAIN!,
},
rateLimit: {
max: parseInt(process.env.RATE_LIMIT_MAX || '10'),
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '900000'),
}
}
2. Add Input Validation Layer
// lib/validation.ts
import { z } from 'zod'
export const invitationSchema = z.object({
to: z.string().email(),
eventName: z.string().min(1).max(200),
dateTime: z.string().min(1),
location: z.string().min(1).max(500),
ctaUrl: z.string().url(),
})
export const paymentSchema = z.object({
to: z.string().email(),
amount: z.number().positive(),
currency: z.enum(['USD', 'EUR', 'GBP']),
description: z.string().min(1).max(500),
})
3. Add Logging & Monitoring
// lib/logger.ts
export const logger = {
info: (message: string, meta?: any) => {
console.log(JSON.stringify({ level: 'info', message, meta, timestamp: new Date() }))
},
error: (message: string, error?: any) => {
console.error(JSON.stringify({ level: 'error', message, error: error?.message, timestamp: new Date() }))
}
}
// Usage in ResendService
async sendEmail(...) {
try {
logger.info('Sending email', { templateId, to })
const result = await this.resend.emails.send(payload)
logger.info('Email sent successfully', { messageId: result.data?.id })
return result
} catch (error) {
logger.error('Failed to send email', error)
throw error
}
}
4. Add Error Handling Middleware
// middleware/errorHandler.ts
export const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
logger.error('Unhandled error', err)
if (err.name === 'ValidationError') {
return res.status(400).json({ error: 'Invalid input data' })
}
if (err.message.includes('Resend')) {
return res.status(503).json({ error: 'Email service temporarily unavailable' })
}
res.status(500).json({ error: 'Internal server error' })
}
🛡️ Production Security Checklist
Backend Security
- Remove EmailSender component from production build
- Add input validation with Zod or similar
- Implement rate limiting
- Add proper error handling
- Use environment variables for all secrets
- Add request logging
- Implement CORS properly
- Add Content Security Policy headers
- Validate email addresses before sending
- Sanitize all user inputs
Email Security
- Validate all URLs before including in emails
- Use only verified domains for sending
- Implement unsubscribe links where required
- Add SPF, DKIM, DMARC records
- Monitor bounce rates and spam reports
- Implement email delivery tracking
Infrastructure Security
- Use HTTPS only
- Implement proper authentication
- Add API key rotation
- Monitor API usage
- Set up alerts for unusual activity
- Regular security audits
📋 Recommended File Structure
backend/
├── src/
│ ├── config/
│ │ ├── email.ts # Email configuration
│ │ └── security.ts # Security settings
│ ├── middleware/
│ │ ├── auth.ts # Authentication
│ │ ├── rateLimit.ts # Rate limiting
│ │ └── validation.ts # Input validation
│ ├── services/
│ │ ├── emailService.ts # Email sending logic
│ │ └── templateService.ts # Template management
│ ├── templates/ # Email templates (copied from playground)
│ ├── utils/
│ │ ├── logger.ts # Logging utility
│ │ └── validator.ts # Validation schemas
│ └── routes/
│ └── emails.ts # Email API routes
├── .env # Environment variables
├── .env.example # Environment template
└── package.json
🚀 Implementation Priority
-
High Priority (Security Critical)
- Remove API key from frontend
- Add input validation
- Implement rate limiting
- Add environment variables
-
Medium Priority (Best Practices)
- Add proper error handling
- Implement logging
- Add CORS configuration
- Content Security Policy
-
Low Priority (Nice to Have)
- Email delivery tracking
- Advanced monitoring
- Performance optimization
- A/B testing framework