Security Guide
Comprehensive security practices for all HandyManny projects and infrastructure.
Security Principles
- Defense in Depth - Multiple layers of security
- Least Privilege - Minimum necessary permissions
- Zero Trust - Verify everything, trust nothing
- Secure by Default - Security built-in, not bolted-on
- Monitor Everything - Continuous security monitoring
Automated Security Monitoring
CHAROS Auditor (Scheduled Task)
Runs: Daily at 7 AM Location: Windows Task Scheduler Script: ~/projects/charos-expediente/security/auditor.ps1
Checks:
- SSL certificate expiration (30-day warning)
- Unauthorized file changes (checksum verification)
- Suspicious process detection
- Port scan detection
- Failed login attempts
- Environment variable leaks
Notifications:
- Email alerts to admin
- Telegram notifications for critical issues
- Logs to
security-audit.log
Session Monitor (Hourly)
Runs: Every 1 hour Monitors:
- Active Claude Code sessions
- MCP server processes
- Resource usage
- Unauthorized process spawning
Actions:
- Kills orphaned processes
- Cleans up temp files
- Alerts on anomalies
SSL Health Check (Every 2 hours)
Runs: Every 2 hours Checks:
- Certificate validity
- Certificate expiration
- SSL configuration
- HTTPS redirect working
- Mixed content issues
Alerts when:
- Certificate expires < 14 days
- Certificate invalid
- HTTP not redirecting to HTTPS
Application Security
Authentication Best Practices
1. Password Requirements
// Enforce strong passwords
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{12,}$/;
// Minimum 12 characters
// At least 1 uppercase, 1 lowercase, 1 number, 1 special char2. Password Hashing
// Use bcrypt with high cost factor
import bcrypt from 'bcrypt';
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);
// NEVER store plain text passwords
// NEVER use MD5 or SHA13. JWT Token Security
// Short expiration times
const accessToken = jwt.sign(payload, secret, {
expiresIn: '15m' // 15 minutes
});
const refreshToken = jwt.sign(payload, refreshSecret, {
expiresIn: '7d' // 7 days
});
// Use different secrets for access and refresh tokens
// Rotate secrets quarterly4. Session Management
// Secure session configuration
{
secret: process.env.SESSION_SECRET, // 256-bit random string
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true, // Prevent XSS
secure: true, // HTTPS only
sameSite: 'strict', // CSRF protection
maxAge: 86400000 // 24 hours
}
}API Security
1. Rate Limiting
// Prevent brute force and DDoS
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests'
});
app.use('/api/', limiter);2. Input Validation
// ALWAYS validate user input
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(12),
name: z.string().max(100).regex(/^[a-zA-Z\s]+$/)
});
// Validate before using
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ error: result.error });
}3. SQL Injection Prevention
// ✓ Use parameterized queries
await prisma.shipment.findMany({
where: { status: userInput } // Safe - Prisma handles escaping
});
// ✓ For raw SQL, use parameters
await prisma.$executeRaw`
SELECT * FROM shipments WHERE status = ${userInput}
`;
// ✗ NEVER concatenate user input
await prisma.$executeRawUnsafe(
`SELECT * FROM shipments WHERE status = '${userInput}'` // UNSAFE!
);4. XSS Prevention
// Sanitize HTML input
import DOMPurify from 'isomorphic-dompurify';
const clean = DOMPurify.sanitize(userInput);
// Use Content Security Policy headers
res.setHeader('Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
);5. CORS Configuration
// Restrict origins
app.use(cors({
origin: ['https://handymanny.cloud', 'https://charos.handymanny.cloud'],
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
// NEVER use origin: '*' in productionSecurity Headers
Essential headers for all applications:
// Express.js
import helmet from 'helmet';
app.use(helmet());
// OR manually:
app.use((req, res, next) => {
// Prevent clickjacking
res.setHeader('X-Frame-Options', 'DENY');
// Prevent MIME sniffing
res.setHeader('X-Content-Type-Options', 'nosniff');
// Enable XSS filter
res.setHeader('X-XSS-Protection', '1; mode=block');
// HSTS - Force HTTPS
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
// Referrer policy
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
// Permissions policy
res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=()');
next();
});Infrastructure Security
SSH Security
1. Key-Based Authentication Only
# Disable password authentication
sudo nano /etc/ssh/sshd_config
# Set these values:
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin prohibit-password2. SSH Key Management
# Generate strong SSH key
ssh-keygen -t ed25519 -C "your_email@example.com"
# Use passphrase-protected keys
# Store keys securely (not in git)3. SSH Hardening
# Disable empty passwords
PermitEmptyPasswords no
# Limit SSH users
AllowUsers admin deploy
# Change default SSH port (security through obscurity)
Port 2222
# Use fail2ban for brute force protection
sudo apt install fail2banFirewall Configuration
# Allow only necessary ports
ufw default deny incoming
ufw default allow outgoing
# Allow SSH (custom port)
ufw allow 2222/tcp
# Allow HTTP/HTTPS
ufw allow 80/tcp
ufw allow 443/tcp
# Enable firewall
ufw enable
# Check status
ufw status verboseDocker Security
1. Run as Non-Root User
# Dockerfile
FROM node:18-alpine
# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
# Switch to non-root user
USER appuser
# Rest of Dockerfile...2. Use Official Images
# docker-compose.yml
services:
app:
image: node:18-alpine # ✓ Official image
# NOT: some-random/node:latest # ✗ Untrusted3. Limit Container Resources
services:
app:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
memory: 256M4. Scan Images for Vulnerabilities
# Use Trivy to scan images
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
aquasec/trivy image [image-name]Environment Variables
1. Never Commit Secrets
# .gitignore
.env
.env.local
.env.production
*.pem
*.key
id_rsa*2. Use .env Files
# .env (NOT committed)
DATABASE_URL=postgresql://user:pass@localhost:5432/db
JWT_SECRET=256-bit-random-string
API_KEY=secret-api-key
# .env.example (committed)
DATABASE_URL=postgresql://user:pass@localhost:5432/db
JWT_SECRET=your-secret-here
API_KEY=your-api-key-here3. Encrypt Secrets at Rest
# Use git-crypt for encrypted secrets
git-crypt init
git-crypt add-gpg-user your-key-id
# Add to .gitattributes
.env filter=git-crypt diff=git-cryptDatabase Security
PostgreSQL Hardening
1. Strong Passwords
-- Create users with strong passwords
CREATE USER appuser WITH ENCRYPTED PASSWORD 'RandomLongPassword123!@#';
-- Grant minimal permissions
GRANT CONNECT ON DATABASE mydb TO appuser;
GRANT USAGE ON SCHEMA public TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO appuser;2. Connection Security
# postgresql.conf
ssl = on
ssl_cert_file = '/etc/ssl/certs/server.crt'
ssl_key_file = '/etc/ssl/private/server.key'
# Require SSL connections
# pg_hba.conf
hostssl all all 0.0.0.0/0 md53. Regular Backups
# Automated daily backups
0 2 * * * pg_dump -U postgres dbname > /backups/db-$(date +\%Y\%m\%d).sql
# Encrypt backups
gpg --encrypt /backups/db-20260228.sql
# Store offsite (S3, Backblaze, etc)Database Access Control
// Connection pool limits
{
max: 20, // Maximum connections
min: 2, // Minimum connections
idle: 10000, // Idle timeout
connectionTimeoutMillis: 2000
}
// NEVER use root/postgres user in applications
// Create dedicated app users with minimal permissionsSecrets Management
Where to Store Secrets
❌ Never:
- Git repositories (even private)
- Docker images
- Client-side code
- Logs or error messages
- Screenshots or documentation
✓ Use:
- Environment variables
- Secret management services (AWS Secrets Manager, HashiCorp Vault)
- Encrypted files (git-crypt)
- Password managers (1Password, LastPass)
Rotating Secrets
Quarterly rotation schedule:
| Secret Type | Rotation Frequency | Last Rotated |
|---|---|---|
| API Keys | Every 90 days | - |
| JWT Secrets | Every 90 days | - |
| Database Passwords | Every 90 days | - |
| SSH Keys | Annually | - |
| SSL Certificates | Auto (Let's Encrypt) | - |
Incident Response
Security Incident Checklist
If you discover a security issue:
Contain
- [ ] Disable affected service immediately
- [ ] Revoke compromised credentials
- [ ] Block malicious IP addresses
Assess
- [ ] Identify what was compromised
- [ ] Check logs for unauthorized access
- [ ] Determine scope of breach
Remediate
- [ ] Patch vulnerability
- [ ] Rotate all potentially compromised secrets
- [ ] Update security configurations
Verify
- [ ] Test fix thoroughly
- [ ] Scan for additional vulnerabilities
- [ ] Monitor for suspicious activity
Document
- [ ] Write incident report
- [ ] Document lessons learned
- [ ] Update security procedures
Notify
- [ ] Inform affected users (if applicable)
- [ ] Report to stakeholders
- [ ] Update team on mitigation
Emergency Contacts
Security Incident Escalation:
- Disable affected system immediately
- Notify team via Telegram
- Begin incident response checklist
- Document everything
Security Auditing
Regular Security Checks
Weekly:
- [ ] Review access logs for anomalies
- [ ] Check for failed login attempts
- [ ] Verify SSL certificates valid
- [ ] Review Docker container security
Monthly:
- [ ] Update all dependencies
- [ ] Run vulnerability scans
- [ ] Review user permissions
- [ ] Audit API keys in use
- [ ] Check for exposed secrets in git history
Quarterly:
- [ ] Rotate API keys and secrets
- [ ] Security training/review
- [ ] Penetration testing
- [ ] Third-party security audit
Security Scanning Tools
# npm audit (Node.js projects)
npm audit
npm audit fix
# Snyk (comprehensive)
npx snyk test
# OWASP Dependency Check
dependency-check --project myapp --scan .
# Git secret scanning
git-secrets --scan-history
# Trivy (Docker images)
trivy image myapp:latestCompliance & Best Practices
OWASP Top 10 Prevention
- Broken Access Control - Implement proper authorization checks
- Cryptographic Failures - Use strong encryption, HTTPS everywhere
- Injection - Parameterized queries, input validation
- Insecure Design - Security by design, threat modeling
- Security Misconfiguration - Secure defaults, minimal permissions
- Vulnerable Components - Keep dependencies updated
- Identification and Authentication Failures - Strong passwords, MFA
- Software and Data Integrity Failures - Verify dependencies, signed commits
- Security Logging Failures - Comprehensive logging and monitoring
- Server-Side Request Forgery - Validate and sanitize URLs
Security Checklist for New Projects
- [ ] HTTPS enabled (SSL certificate)
- [ ] Security headers configured
- [ ] Authentication implemented
- [ ] Authorization implemented
- [ ] Input validation on all endpoints
- [ ] SQL injection prevention (parameterized queries)
- [ ] XSS prevention (sanitize output)
- [ ] CSRF protection enabled
- [ ] Rate limiting configured
- [ ] Error handling (no sensitive data in errors)
- [ ] Secrets in environment variables (not code)
- [ ] Dependencies up to date
- [ ] Docker security (non-root user, resource limits)
- [ ] Logging configured
- [ ] Monitoring configured
Last Updated: 2026-02-28 Related SOPs: Deployment SOP, Rollback SOP