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 crypto module
  • 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_KEY must be exactly 32 characters (hex format)
  • Generated with: openssl rand -hex 16
  • Stored in .env file
  • 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_KEY means permanent data loss
  • Changing ENCRYPTION_KEY requires 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:

  1. Export your entries using the old version
  2. Update to v0.4.0+
  3. 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/webauthn file 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:

  1. Export all entries
  2. Generate new ENCRYPTION_KEY
  3. Update .env
  4. Restart application
  5. 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: SAMEORIGIN
  • X-Content-Type-Options: nosniff
  • X-XSS-Protection: 1; mode=block
  • Strict-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:

  1. 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
  2. Expected Response:

    • Acknowledgment: within 48 hours
    • Initial assessment: within 7 days
    • Fix timeline: depends on severity
  3. 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 .env securely
  • Enable HTTPS (required for WebAuthn)
  • Configure WebAuthn (RP_ID, ORIGIN)
  • Create .well-known/webauthn file
  • 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:

  1. Immediate private fix
  2. Emergency release within 24-48 hours
  3. Security advisory published
  4. All users notified via:
    • GitHub Security Advisory
    • Release notes
    • Project discussions

High Severity:

  1. Fix within 1 week
  2. Include in next release
  3. Release notes mention fix
  4. Security advisory if needed

Medium/Low Severity:

  1. Fix in regular development cycle
  2. Mentioned in changelog
  3. Included in next minor version

Security Advisory Process

When security issues are fixed:

  1. Private disclosure to maintainers
  2. Fix developed in private branch
  3. Testing in isolated environment
  4. Release with security patch
  5. Public disclosure 7 days after fix
  6. 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:

WebAuthn Resources:

Encryption Standards:

Compliance:

  • GDPR considerations for EU users
  • SOC 2 (planned)
  • ISO 27001 (planned)
  • HIPAA considerations (if applicable)

Tools:


🔐 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)