Security - PrzemekSkw/totp-sync GitHub Wiki
Security
Security policies, best practices, and vulnerability reporting for TOTP Sync.
🔒 Security Overview
TOTP Sync takes security seriously. This document outlines our security measures, best practices, and how to report vulnerabilities.
🛡️ Security Features
Current Implementation
Encryption:
- ✅ TOTP Secrets: AES-256-GCM encryption (v0.4.0+)
- ✅ Passwords: bcrypt hashing (cost factor 12)
- ✅ JWT Tokens: HS256 signing
- ✅ Database: Encrypted secrets at rest
Authentication:
- ✅ Email + password login
- ✅ WebAuthn/Passkey support (v0.5.0+)
- ✅ 2FA support (TOTP)
- ✅ Security key authentication (YubiKey, FIDO2)
- ✅ Biometric authentication (Touch ID, Face ID, Windows Hello)
- ✅ Cross-device authentication
- ✅ JWT token-based sessions
- ✅ Secure password requirements (min. 8 chars)
Network Security:
- ✅ HTTPS ready (via reverse proxy)
- ✅ HTTPS required for WebAuthn (except localhost)
- ✅ Security headers (helmet.js)
- ✅ Rate limiting
- ✅ CORS protection
- ✅ .well-known/webauthn support
What Changed in v0.5.0:
- ✅ WebAuthn/FIDO2 standard implementation
- ✅ Passwordless authentication
- ✅ Hardware security key support
- ✅ Platform authenticator support
- ✅ Cross-device authentication with QR codes
- ✅ Multiple authenticator management
What Changed in v0.4.0:
- ✅ Removed CryptoJS dependency (security improvement)
- ✅ Native Node.js crypto (better maintained)
- ✅ AES-256-GCM instead of CBC (more secure)
- ✅ Authentication tags (data integrity)
- ✅ Zero npm vulnerabilities
🔐 Encryption Details
TOTP Secret Encryption
Algorithm: AES-256-GCM (as of v0.4.0)
Previous versions (v0.3.0 and older): AES-256-CBC with CryptoJS (deprecated)
Current Implementation (v0.4.0+):
- Uses Node.js native
cryptomodule - AES-256-GCM (Galois/Counter Mode)
- 16-byte random IV (Initialization Vector) per secret
- Authentication tags for integrity verification
- Format:
iv:authTag:encryptedData(all in hex)
Process:
1. User enters TOTP secret (Base32)
2. Generate random 16-byte IV
3. Encrypt with AES-256-GCM using ENCRYPTION_KEY
4. Get authentication tag from cipher
5. Store as: iv:authTag:encryptedData
6. On retrieval: decrypt with IV and verify authTag → generate code
Key Requirements:
ENCRYPTION_KEYmust be exactly 32 characters (hex format)- Generated with:
openssl rand -hex 16 - Stored in
.envfile - Never transmitted over network
Why GCM over CBC:
- ✅ Built-in authentication (prevents tampering)
- ✅ More secure than CBC mode
- ✅ Industry standard for modern encryption
- ✅ No padding oracle attacks
- ✅ Better performance
- ✅ Native Node.js support (no external dependencies)
⚠️ Critical:
- Losing
ENCRYPTION_KEYmeans permanent data loss - Changing
ENCRYPTION_KEYrequires data migration - Secrets from v0.3.0 or older cannot be decrypted in v0.4.0+
Migration from v0.3.0: If upgrading from older versions, you must:
- Export your entries using the old version
- Update to v0.4.0+
- Re-import your entries (they will be re-encrypted with new method)
See [[Migration Guide](Migration-Guide)] for detailed instructions.
Password Hashing
Algorithm: bcrypt
Parameters:
- Cost factor: 12 rounds
- Salt: automatically generated per password
Process:
1. User enters password
2. bcrypt generates salt
3. Password + salt hashed 12 rounds
4. Hash stored in database
5. Login: hash comparison (constant time)
Why bcrypt:
- Resistant to rainbow tables
- Adaptive (can increase rounds)
- Slow by design (prevents brute force)
- Industry standard for password hashing
WebAuthn Security (v0.5.0+)
Standard: FIDO2/WebAuthn
What is WebAuthn:
- W3C standard for passwordless authentication
- Public-key cryptography (asymmetric encryption)
- Private key never leaves the device
- Phishing-resistant authentication
- Replay attack protection
Security Model:
Registration:
1. Server generates challenge
2. Client creates key pair (public/private)
3. Private key stored in authenticator (hardware/platform)
4. Public key sent to server
5. Server verifies and stores public key
Authentication:
1. Server generates challenge
2. Client signs challenge with private key
3. Server verifies signature with stored public key
4. No password involved!
Authenticator Types:
Platform Authenticators (built-in):
- Touch ID (Mac/iOS)
- Face ID (iOS)
- Windows Hello (Windows)
- Android biometrics
- Stored in device's Secure Enclave/TPM
Roaming Authenticators (external):
- YubiKey (USB/NFC)
- Google Titan Key
- Feitian Keys
- Any FIDO2-compatible device
Security Benefits:
- ✅ Phishing-resistant - Domain-bound credentials
- ✅ No shared secrets - Public-key cryptography
- ✅ Hardware-backed - Keys stored in secure hardware
- ✅ Replay protection - Challenge-response mechanism
- ✅ Privacy-preserving - No tracking across sites
- ✅ MFA built-in - "Something you have" + biometrics
Implementation Details:
- Library:
@simplewebauthn/server(server),@simplewebauthn/browser(client) - Algorithm: ES256 (ECDSA with P-256 and SHA-256)
- Attestation: None (privacy-preserving)
- User Verification: Preferred (biometrics when available)
- Resident Key: Required (for cross-device/passwordless)
Data Stored:
webauthn_credentials table:
- credential_id (base64url, unique identifier)
- public_key (base64, for signature verification)
- counter (integer, replay protection)
- transports (array, connection methods)
- name (string, user-friendly label)
HTTPS Requirement:
- ✅ Required in production (security requirement)
- ✅ Localhost allowed for testing (HTTP OK)
- ✅ Prevents man-in-the-middle attacks
- ✅ Ensures credential privacy
Domain Binding:
- Credentials are bound to
RP_ID(Relying Party ID) - Must match the domain where app is hosted
- Prevents credential theft across domains
.well-known/webauthnfile verifies domain ownership
JWT Tokens
Algorithm: HS256 (HMAC-SHA256)
Payload:
{
"userId": 123,
"email": "[email protected]",
"iat": 1234567890,
"exp": 1234654290
}
Expiration: 24 hours
Storage: Browser localStorage
Refresh: Not yet implemented (planned v0.7.0)
🚨 Known Vulnerabilities
LOW SEVERITY:
-
🟢 No Session Timeout - JWT tokens don't auto-expire after inactivity
- Impact: Stolen tokens remain valid until expiration
- Mitigation: Logout when done, enable WebAuthn
- Status: Planned for v0.7.0
-
🟢 Limited Rate Limiting - Some endpoints lack rate limiting
- Impact: Potential brute force attacks
- Mitigation: Use strong passwords, enable 2FA/WebAuthn
- Status: Planned for v0.7.0
Mitigated by WebAuthn (v0.5.0+):
- ✅ Phishing attacks - WebAuthn is phishing-resistant
- ✅ Password reuse - No passwords needed with passkeys
- ✅ Credential stuffing - Public-key cryptography prevents this
- ✅ Weak passwords - Hardware-backed authentication
🔒 Security Best Practices
For Users
1. Strong Passwords (if not using WebAuthn)
# Generate secure password
openssl rand -base64 24
Minimum requirements:
- ✅ 8+ characters
- ✅ Mix of letters, numbers, symbols
- ✅ No common words or patterns
- ✅ Unique to this application
2. Enable WebAuthn/Passkeys (v0.5.0+)
Best practice: Register multiple authenticators
Primary: YubiKey (most secure, offline)
Backup: Touch ID / Windows Hello (convenient)
Backup: Android phone (cross-device)
Why multiple authenticators:
- ✅ Don't lose access if one device is lost
- ✅ Convenience (use phone when laptop unavailable)
- ✅ Security levels (hardware key for sensitive operations)
3. Secure Environment Variables
# Never commit .env to git
echo ".env" >> .gitignore
# Restrict file permissions
chmod 600 .env
# Backup safely offline
cp .env .env.backup
# Store on encrypted USB drive
4. HTTPS in Production (REQUIRED for WebAuthn)
WebAuthn will NOT work without HTTPS (except localhost):
# Redirect HTTP to HTTPS
server {
listen 80;
return 301 https://$host$request_uri;
}
# HTTPS configuration
server {
listen 443 ssl http2;
server_name totp.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
}
5. Configure .well-known/webauthn
For WebAuthn to work properly:
location /.well-known/webauthn {
default_type application/json;
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
}
File content (/web/public/.well-known/webauthn):
{
"origins": ["https://totp.yourdomain.com"]
}
6. Firewall Configuration
# Allow only necessary ports
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 443/tcp # HTTPS only (WebAuthn requires this)
sudo ufw enable
7. Regular Backups
For PostgreSQL:
# Weekly backup script
#!/bin/bash
DATE=$(date +%Y%m%d)
docker exec totp-sync-db pg_dump -U totp_user totp_sync | \
gpg --symmetric --cipher-algo AES256 > backup-$DATE.sql.gpg
For SQLite:
# Simple file copy
DATE=$(date +%Y%m%d)
docker cp totp-sync-backend:/data/totp-sync.db backup-$DATE.db
# Encrypt it
gpg --symmetric --cipher-algo AES256 backup-$DATE.db
8. Monitor Access Logs
# Check for suspicious activity
docker compose logs web | grep -E "40[13]|50[0-9]"
docker compose logs backend | grep -i "error\|fail"
docker compose logs backend | grep "WebAuthn" # Monitor passkey usage
For Administrators
1. WebAuthn Configuration (v0.5.0+)
Correct configuration is critical for security:
# .env configuration
RP_NAME="TOTP Sync" # Your app name
RP_ID="totp.yourdomain.com" # Your domain (no protocol/port)
ORIGIN="https://totp.yourdomain.com" # Full URL with protocol
# WRONG examples:
# RP_ID="https://totp.yourdomain.com" # ❌ Don't include protocol
# RP_ID="totp.yourdomain.com:443" # ❌ Don't include port
# ORIGIN="totp.yourdomain.com" # ❌ Must include https://
Testing locally:
RP_ID="localhost"
ORIGIN="http://localhost:5173" # HTTP allowed for localhost only
2. Network Isolation
# docker-compose.yml
networks:
frontend:
internal: false
backend:
internal: true # No external access
services:
postgres:
networks:
- backend # Database not exposed
3. Secret Rotation
Rotate secrets periodically:
# Generate new JWT secret
openssl rand -base64 32
# Update .env
nano .env
# Restart (logs out all users)
docker compose restart backend
⚠️ Warning: Cannot rotate ENCRYPTION_KEY without data migration!
To rotate ENCRYPTION_KEY:
- Export all entries
- Generate new
ENCRYPTION_KEY - Update
.env - Restart application
- Re-import entries (will be encrypted with new key)
4. Audit Logging
Enable detailed logs:
NODE_ENV=production
LOG_LEVEL=info
AUDIT_LOG=true
Monitor WebAuthn usage:
# Track passkey registrations
docker compose logs backend | grep "register-verify"
# Track passkey authentications
docker compose logs backend | grep "login-verify"
5. Security Headers
Already enabled via helmet.js:
X-Frame-Options: SAMEORIGINX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockStrict-Transport-Security(when HTTPS)Content-Security-Policy
6. Database Security
PostgreSQL:
# Use strong database password
POSTGRES_PASSWORD=$(openssl rand -base64 32)
# Limit connections (in postgresql.conf):
max_connections = 20
# Enable SSL for database (future feature)
SQLite:
# Restrict file permissions
chmod 600 /path/to/totp-sync.db
# Regular backups (file is small)
cp totp-sync.db totp-sync.db.backup
7. Registration Control (v0.5.0+)
Disable public registration after initial setup:
ALLOW_REGISTRATION=false
When to disable:
- ✅ After all authorized users registered
- ✅ Single-user or family deployments
- ✅ Prevent unauthorized signups
- ✅ Reduce attack surface
When to enable:
- ✅ Multi-user environments
- ✅ Team/organization deployments
- ✅ Public instances (with proper security)
🐛 Reporting Vulnerabilities
Security Issue Reporting
DO NOT open public GitHub issues for security vulnerabilities!
Instead:
-
Email: [email protected]
- Subject:
[SECURITY] TOTP Sync Vulnerability - Include:
- Vulnerability description
- Steps to reproduce
- Impact assessment
- Proof of concept (if applicable)
- Suggested fix (optional)
- Your preferred contact method
- Subject:
-
Expected Response:
- Acknowledgment: within 48 hours
- Initial assessment: within 7 days
- Fix timeline: depends on severity
-
Disclosure Policy:
- We'll work on a fix privately
- Credit given to reporter (if desired)
- Public disclosure after fix released
- Security advisory published on GitHub
Severity Levels:
- Critical: Remote code execution, data breach
- High: Authentication bypass, privilege escalation
- Medium: Information disclosure, denial of service
- Low: Configuration issues, minor information leaks
🏆 Security Researchers
Hall of Fame
Security researchers who responsibly disclosed vulnerabilities:
No vulnerabilities reported yet.
Bug Bounty
Currently no bug bounty program.
Rewards:
- 🏅 Credit in release notes
- ⭐ Special mention in README
- 💖 Eternal gratitude
- 🎁 Small token of appreciation (for critical findings)
📋 Security Checklist
Before Deployment
- Change all default passwords
- Generate unique
JWT_SECRET - Generate unique
ENCRYPTION_KEY - Backup
.envsecurely - Enable HTTPS (required for WebAuthn)
- Configure WebAuthn (
RP_ID,ORIGIN) - Create
.well-known/webauthnfile - Configure firewall (allow 443/tcp only)
- Enable 2FA for admin accounts
- Register multiple authenticators (YubiKey + biometrics)
- Set up monitoring
- Configure automated backups
- Review security headers
- Test disaster recovery
- Consider disabling registration (
ALLOW_REGISTRATION=false)
Regular Maintenance
- Weekly: Check logs for anomalies
- Weekly: Verify backups are working
- Weekly: Monitor WebAuthn usage
- Monthly: Update Docker images
- Monthly: Backup verification (test restore)
- Monthly: Review registered authenticators
- Quarterly: Security audit
- Quarterly: Rotate JWT secret
- Quarterly: Review user access
- Quarterly: Test WebAuthn on different devices
- Yearly: Full security assessment
- Yearly: Review access controls
- Yearly: Update SSL certificates
🔄 Security Updates
How We Handle Security Issues
Critical Vulnerabilities:
- Immediate private fix
- Emergency release within 24-48 hours
- Security advisory published
- All users notified via:
- GitHub Security Advisory
- Release notes
- Project discussions
High Severity:
- Fix within 1 week
- Include in next release
- Release notes mention fix
- Security advisory if needed
Medium/Low Severity:
- Fix in regular development cycle
- Mentioned in changelog
- Included in next minor version
Security Advisory Process
When security issues are fixed:
- Private disclosure to maintainers
- Fix developed in private branch
- Testing in isolated environment
- Release with security patch
- Public disclosure 7 days after fix
- CVE assigned for critical issues
🛠️ Planned Security Improvements
See [[Roadmap](Roadmap)] for timeline:
v0.6.0 - Security Hardening:
- Enhanced rate limiting per endpoint
- Failed login attempt monitoring
- Account lockout policies
- IP-based access controls
v0.7.0 - Session Management:
- Session management and auto-logout
- JWT refresh tokens
- Comprehensive audit logging
- Failed login notifications
- Device fingerprinting
v0.8.0 - Advanced WebAuthn:
- Conditional UI (passkey autofill)
- Backup state sync for authenticators
- WebAuthn attestation verification
- Authenticator metadata service
v0.9.0 - OAuth/OIDC:
- Reduces password exposure
- Leverages provider security
- Optional 2FA enforcement
- Social login options
v1.0.0 - Enterprise Security:
- SAML 2.0 support
- LDAP integration
- Advanced hardware key features
- Compliance certifications (SOC 2, ISO 27001)
- Security Information and Event Management (SIEM) integration
📚 Additional Resources
Security Guides:
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Docker Security Best Practices](https://docs.docker.com/engine/security/)
- [Node.js Security Checklist](https://nodejs.org/en/docs/guides/security/)
- [NIST Cybersecurity Framework](https://www.nist.gov/cyberframework)
- [FIDO Alliance Security Reference](https://fidoalliance.org/specifications/)
WebAuthn Resources:
- [WebAuthn Specification (W3C)](https://www.w3.org/TR/webauthn-2/)
- [WebAuthn Guide](https://webauthn.guide/)
- [FIDO2 Overview](https://fidoalliance.org/fido2/)
- [SimpleWebAuthn Documentation](https://simplewebauthn.dev/)
Encryption Standards:
- [AES-256-GCM](https://en.wikipedia.org/wiki/Galois/Counter_Mode)
- [bcrypt](https://en.wikipedia.org/wiki/Bcrypt)
- [JWT Best Practices](https://jwt.io/introduction)
- [OWASP Cryptographic Storage](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html)
Compliance:
- GDPR considerations for EU users
- SOC 2 (planned)
- ISO 27001 (planned)
- HIPAA considerations (if applicable)
Tools:
- [npm audit](https://docs.npmjs.com/cli/v8/commands/npm-audit) - Dependency vulnerability scanning
- [Snyk](https://snyk.io/) - Advanced security scanning
- [OWASP ZAP](https://www.zaproxy.org/) - Web application security testing
- [Burp Suite](https://portswigger.net/burp) - Web vulnerability scanner
🔐 Responsible Disclosure
We believe in responsible disclosure and appreciate security researchers who:
✅ Give us reasonable time to fix issues (typically 90 days) ✅ Don't exploit vulnerabilities beyond proof-of-concept ✅ Don't access user data unnecessarily ✅ Coordinate disclosure timing with maintainers ✅ Provide detailed reproduction steps ✅ Suggest remediation when possible
What we promise:
- Timely response and acknowledgment
- Transparent communication throughout the process
- Public credit (unless you prefer anonymity)
- Good faith effort to fix issues quickly
- No legal action for good-faith research
Thank you for helping keep TOTP Sync secure! 🙏
Last Updated: November 2024
Current Version: v0.5.0-beta
Security Contact: [email protected]
📞 Contact
For security issues: [email protected]
For general questions: [GitHub Discussions](https://github.com/PrzemekSkw/totp-sync/discussions)
For bug reports: [GitHub Issues](https://github.com/PrzemekSkw/totp-sync/issues)