Files
2026-07-31 11:47:31 +09:00

392 lines
9.7 KiB
Markdown

# Security Checklist for Production Deployment
This checklist helps ensure your LinkForty deployment on Fly.io follows security best practices.
## ✅ Pre-Deployment Security Checklist
### Environment Variables & Secrets
- [ ] All sensitive values are set using `fly secrets set` (never in `fly.toml`)
- [ ] `DATABASE_URL` includes `?sslmode=require` for PostgreSQL
- [ ] `REDIS_URL` includes authentication credentials
- [ ] `CORS_ORIGIN` is set to your actual frontend domain(s), not `*`
- [ ] `NODE_ENV` is set to `"production"`
- [ ] No secrets are committed to version control
- [ ] `.env` files are in `.gitignore`
### Database Security
- [ ] PostgreSQL uses SSL/TLS connections (`sslmode=require`)
- [ ] Database password is strong (20+ characters, random)
- [ ] Database is not publicly accessible (Fly Postgres is private by default)
- [ ] Connection pooling is configured (default: 2-10 connections)
- [ ] Database backups are enabled (see [fly.postgres.md](./fly.postgres.md))
- [ ] Backup retention policy is configured
### Redis Security
- [ ] Redis requires authentication (Upstash Redis includes this by default)
- [ ] Redis connection uses TLS (`rediss://` protocol)
- [ ] Redis is not publicly accessible
- [ ] Connection timeout is configured
### Application Security
- [ ] CORS is properly configured (not set to `*` in production)
- [ ] Rate limiting is enabled for link creation endpoints
- [ ] Input validation is active (Zod schemas)
- [ ] SQL injection protection via parameterized queries (pg library handles this)
- [ ] Health check endpoint (`/health`) exposes no sensitive data
- [ ] Error messages don't leak sensitive information
- [ ] Logging doesn't include secrets or PII
### Network Security
- [ ] HTTPS is enforced (`force_https = true` in fly.toml)
- [ ] HTTP is redirected to HTTPS
- [ ] Health checks use HTTPS
- [ ] No sensitive services are exposed publicly
### Access Control
- [ ] Fly.io account uses strong password + 2FA
- [ ] Fly.io organization access is limited to required team members
- [ ] Deploy tokens (if used in CI/CD) have minimum required permissions
- [ ] Database credentials are rotated regularly (quarterly minimum)
---
## 🔐 Security Configuration Details
### 1. Database URL Security
Your `DATABASE_URL` should look like:
```
postgresql://user:password@host:5432/dbname?sslmode=require
```
Key requirements:
- `sslmode=require` - Forces SSL/TLS encryption
- Strong password (20+ characters)
- Host should be internal Fly network (`.internal` domain) if using Fly Postgres
Set it securely:
```bash
fly secrets set DATABASE_URL="postgresql://user:password@host:5432/dbname?sslmode=require"
```
### 2. Redis URL Security
Your `REDIS_URL` should look like:
```
rediss://default:password@host:6379
```
Key requirements:
- `rediss://` protocol (TLS encrypted)
- Authentication password included
- Upstash Redis (recommended) includes TLS by default
Set it securely:
```bash
fly secrets set REDIS_URL="rediss://default:password@host:6379"
```
### 3. CORS Configuration
For production, set specific origins:
```bash
# Single origin
fly secrets set CORS_ORIGIN="https://yourdomain.com"
# Multiple origins (comma-separated)
fly secrets set CORS_ORIGIN="https://yourdomain.com,https://app.yourdomain.com"
```
Never use `*` in production - this allows any website to make requests to your API.
### 4. Rate Limiting
LinkForty includes built-in rate limiting. Verify it's enabled in your deployment:
- Link creation: Limited by IP address
- Analytics queries: Limited by userId
- Redirect endpoints: Unlimited (by design for fast redirects)
Monitor rate limit metrics:
```bash
fly logs | grep "rate limit"
```
### 5. Input Validation
LinkForty uses Zod for input validation. Ensure validation errors are logged:
```bash
fly logs | grep "validation"
```
Common validation issues to monitor:
- Invalid URLs
- Malformed userId
- Invalid UTM parameters
- Expired links
---
## 🔄 Secret Rotation Policy
Rotate secrets regularly to minimize compromise risk.
### Quarterly Rotation (Every 3 months)
1. **Database Password**
```bash
# On Fly Postgres
fly postgres connect -a linkforty-db
ALTER USER your_user WITH PASSWORD 'new-strong-password';
\q
# Update secret
fly secrets set DATABASE_URL="postgresql://user:new-password@host:5432/dbname?sslmode=require"
```
2. **Redis Password**
```bash
# Generate new Upstash Redis credentials
# In Upstash dashboard: Reset password
# Update secret
fly secrets set REDIS_URL="rediss://default:new-password@host:6379"
```
3. **API Keys** (if you add API authentication)
```bash
fly secrets set API_KEY="new-random-key"
```
### After Security Incident
Rotate ALL secrets immediately:
- Database credentials
- Redis credentials
- Any API keys
- Fly.io deploy tokens (if compromised)
---
## 🔍 Security Monitoring
### Log Monitoring
Monitor these security-relevant events:
```bash
# Failed database connections
fly logs | grep "connection refused"
# Rate limit hits
fly logs | grep "rate limit"
# Validation errors
fly logs | grep "validation error"
# Suspicious activity patterns
fly logs | grep "error"
```
### Metrics to Watch
- **Unusual traffic spikes** - Potential DDoS or abuse
- **High error rates** - Potential attack or misconfiguration
- **Database connection errors** - Credential issues or network problems
- **Redis connection failures** - Service degradation
Access metrics:
```bash
fly dashboard # Web UI with graphs
fly status # Current health
```
### Automated Alerts (Recommended)
Set up alerts for:
- High error rates (>5% of requests)
- Service downtime
- Database connection failures
- Unusual traffic patterns
Fly.io integrates with:
- Sentry (error tracking)
- Datadog (monitoring)
- Prometheus (metrics)
---
## 🛡️ Incident Response Plan
### If Secrets Are Compromised
1. **Immediately rotate all secrets**
```bash
# See "Secret Rotation Policy" section above
```
2. **Review access logs**
```bash
fly logs --all
```
3. **Check for unauthorized database changes**
```bash
fly postgres connect -a linkforty-db
SELECT * FROM users ORDER BY created_at DESC LIMIT 100;
SELECT * FROM links ORDER BY created_at DESC LIMIT 100;
```
4. **Review Fly.io access logs**
- Check Fly.io dashboard for recent deploys
- Review team member access
- Check for unknown IP addresses
5. **Deploy with new secrets**
```bash
fly deploy
```
6. **Document the incident**
- What was compromised?
- How was it discovered?
- What actions were taken?
- How to prevent in the future?
### If Database Is Compromised
1. **Restore from backup**
```bash
# See fly.postgres.md for backup/restore instructions
```
2. **Analyze what data was accessed/modified**
3. **Notify affected users** (if PII was compromised)
4. **Review and strengthen security measures**
---
## 🔒 Data Protection
### Personal Identifiable Information (PII)
LinkForty collects:
- IP addresses (for geolocation)
- User agent strings (for device detection)
- Referrer URLs (for analytics)
- User IDs (provided by you)
**Your responsibilities:**
- Comply with GDPR, CCPA, or relevant privacy laws
- Implement data retention policies
- Provide user data deletion endpoints
- Maintain privacy policy
- Obtain user consent where required
### Data Retention
Consider implementing:
- Automatic deletion of click events older than X days
- User data export functionality
- Data anonymization for old analytics
Example cleanup query:
```sql
DELETE FROM click_events WHERE created_at < NOW() - INTERVAL '90 days';
```
Schedule via cron or Fly.io scheduled tasks.
### Encryption
- **In transit:** HTTPS/TLS for all connections (enforced by Fly.io)
- **At rest:** Fly Postgres encrypts data at rest automatically
- **Application level:** Consider encrypting sensitive user data in JSONB fields
---
## 🚨 Security Vulnerabilities
### Reporting Security Issues
**DO NOT** open public GitHub issues for security vulnerabilities.
Instead:
- Email security@yourdomain.com (set up a security contact)
- Use GitHub Security Advisories (private disclosure)
- Allow 90 days for responsible disclosure
### Keeping Dependencies Updated
```bash
# Check for vulnerabilities
npm audit
# Fix automatically where possible
npm audit fix
# Review and update dependencies quarterly
npm outdated
npm update
```
Subscribe to security advisories:
- Node.js security releases
- Fastify security updates
- PostgreSQL security announcements
---
## ✅ Security Checklist Summary
Print and complete this checklist before every production deployment:
**Pre-Deploy:**
- [ ] Secrets set via `fly secrets set` (not in code)
- [ ] Database uses SSL (`sslmode=require`)
- [ ] CORS configured for specific domains
- [ ] HTTPS enforced in `fly.toml`
- [ ] No secrets in version control
**Post-Deploy:**
- [ ] Health check passes
- [ ] HTTPS redirect works
- [ ] CORS allows only intended domains
- [ ] Database connection successful
- [ ] Redis connection successful
- [ ] Rate limiting active
- [ ] Error logging working
**Ongoing:**
- [ ] Secrets rotated quarterly
- [ ] Dependencies updated monthly
- [ ] Logs monitored weekly
- [ ] Backups verified monthly
- [ ] Access control reviewed quarterly
---
## 📚 Additional Resources
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Fly.io Security Best Practices](https://fly.io/docs/reference/security/)
- [PostgreSQL Security](https://www.postgresql.org/docs/current/runtime-config-connection.html#RUNTIME-CONFIG-CONNECTION-SSL)
- [Node.js Security Best Practices](https://nodejs.org/en/docs/guides/security/)
- [Fastify Security](https://www.fastify.io/docs/latest/Guides/Security/)
---
**Last Updated:** 2025-01-13
Review and update this checklist quarterly or after any security incident.