Skip to content

Security: JavaDogWebDesign/HealthReceipts

Security

SECURITY.md

Security Guide - HSA/FSA Tracker

This document outlines the security features implemented in the HSA/FSA Tracker and best practices for secure deployment.

Table of Contents

Security Features

1. Authentication & Session Management

Features:

  • Secure password hashing using Werkzeug's generate_password_hash()
  • Session-based authentication with HttpOnly cookies
  • SameSite cookie attribute for CSRF protection
  • 24-hour session lifetime
  • Secure session cookies in production (HTTPS-only)

Configuration:

app.config['SESSION_COOKIE_HTTPONLY'] = True   # Prevents JavaScript access
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'  # CSRF protection
app.config['SESSION_COOKIE_SECURE'] = True      # HTTPS only (production)
app.config['PERMANENT_SESSION_LIFETIME'] = 86400 # 24 hours

2. CSRF Protection

Implementation: Flask-WTF

  • All POST/PUT/DELETE/PATCH requests require CSRF tokens
  • Tokens included via meta tag in HTML templates
  • JavaScript helper function addCSRFToken() for AJAX requests

Usage in Forms:

<form method="POST">
    <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
    <!-- form fields -->
</form>

Usage in JavaScript:

fetch('/api/endpoint', addCSRFToken({
    method: 'POST',
    body: formData
}))

3. Rate Limiting

Implementation: Flask-Limiter

  • Default limits: 200 requests/day, 50 requests/hour per IP
  • Login endpoint: 5 attempts per minute
  • Registration endpoint: 3 attempts per hour

Configuration:

limiter = Limiter(
    app=app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"],
    storage_uri="memory://",
    strategy="fixed-window"
)

4. Secret Key Management

Security:

  • Required SECRET_KEY environment variable in production
  • Random key generation for development
  • Application refuses to start if SECRET_KEY missing in production

Setup:

# Generate a secure secret key
python -c 'import secrets; print(secrets.token_hex(32))'

# Add to .env file
echo "SECRET_KEY=<generated-key>" >> .env

5. Data Isolation

Database Security:

  • All queries filtered by user_id
  • Parameterized queries prevent SQL injection
  • Foreign key constraints with CASCADE deletes
  • User-specific file storage directories

Example:

expense = conn.execute('''
    SELECT e.* FROM expenses e
    WHERE e.id = ? AND e.user_id = ?
''', (expense_id, user_id)).fetchone()

6. Encryption (Optional)

NEW: Enhanced Data Protection

The application now supports optional encryption for both database and file storage:

Features:

  • Database Encryption: SQLCipher-based 256-bit AES encryption for the SQLite database
  • File Encryption: Fernet (symmetric) encryption for all uploaded receipts and attachments
  • Backward Compatible: Works with existing unencrypted installations
  • Migration Support: Automated migration script for existing data

Benefits:

  • Protects sensitive financial data at rest
  • Encrypts all receipts and proof-of-reimbursement documents
  • Makes stolen database/files useless without encryption keys
  • Recommended for production deployments

Requirements:

  • Python 3.11 or lower (SQLCipher not compatible with Python 3.12+)
  • The Docker image is locked to Python 3.11 for compatibility

Setup:

  1. Generate encryption keys:
python app/utils/encryption.py
  1. Add keys to .env:
DB_ENCRYPTION_KEY=<your-db-key>
FILE_ENCRYPTION_KEY=<your-file-key>
  1. Restart the application - encryption is automatic once keys are set

CRITICAL SECURITY NOTES:

  • ⚠️ Backup encryption keys separately from data!
  • ⚠️ If keys are lost, encrypted data CANNOT be recovered!
  • ⚠️ Store keys in a secure secrets manager for production
  • ⚠️ Never commit encryption keys to version control

Docker Setup:

environment:
  - DB_ENCRYPTION_KEY=${DB_ENCRYPTION_KEY}
  - FILE_ENCRYPTION_KEY=${FILE_ENCRYPTION_KEY}

7. File Upload Security

Protections:

  • Whitelist validation: Only PDF, JPG, JPEG, PNG allowed
  • 16MB file size limit
  • User-specific storage directories
  • Ownership verification before file access
  • Optional file encryption (see Encryption section)

Configuration:

ALLOWED_EXTENSIONS = {'pdf', 'jpg', 'jpeg', 'png'}
MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 16MB

Installation & Setup

Prerequisites

pip install -r requirements.txt

Required Packages

  • Flask==3.0.0
  • Werkzeug==3.0.1
  • python-dotenv==1.0.0
  • pytz==2024.1
  • Flask-WTF==1.2.1 (CSRF protection)
  • Flask-Limiter==3.5.0 (Rate limiting)

Environment Configuration

  1. Copy the example environment file:

    cp .env.example .env
  2. Generate a secure secret key:

    python -c 'import secrets; print(secrets.token_hex(32))'
  3. Update .env file:

    FLASK_ENV=development
    SECRET_KEY=<your-generated-secret-key>
    PORT=5000

Database Initialization

cd app
python database.py

Production Deployment

1. Environment Variables

Required:

FLASK_ENV=production
SECRET_KEY=<strong-random-secret-key>

Optional:

PORT=5000

2. HTTPS/TLS Configuration

Option A: Using a Reverse Proxy (Recommended)

Example Nginx configuration:

server {
    listen 443 ssl;
    server_name yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$server_name$request_uri;
}

Option B: Using Flask-Talisman

from flask_talisman import Talisman
Talisman(app, force_https=True)

3. Production Checklist

  • Set FLASK_ENV=production
  • Generate and set strong SECRET_KEY
  • Enable HTTPS/TLS
  • Configure firewall rules
  • Set up reverse proxy (Nginx/Apache)
  • Enable automatic backups
  • Configure logging
  • Set up monitoring
  • Review file permissions
  • Disable debug mode (automatic when FLASK_ENV=production)

4. Running in Production

Using Gunicorn (Recommended):

pip install gunicorn
gunicorn -w 4 -b 127.0.0.1:5000 app:app

Using systemd service:

[Unit]
Description=HSA/FSA Tracker
After=network.target

[Service]
User=www-data
WorkingDirectory=/path/to/hsa-tracker-v2/app
Environment="FLASK_ENV=production"
Environment="SECRET_KEY=<your-secret-key>"
ExecStart=/usr/bin/gunicorn -w 4 -b 127.0.0.1:5000 app:app
Restart=always

[Install]
WantedBy=multi-user.target

Security Best Practices

For Users

  1. Use Strong Passwords:

    • Minimum 12 characters
    • Mix of uppercase, lowercase, numbers, and symbols
    • Unique password for this application
  2. Regular Backups:

    • Export your data regularly using the backup feature
    • Store backups in a secure location
    • Test restore process periodically
  3. Secure Your Receipts:

    • Only upload necessary documents
    • Remove sensitive metadata before upload
    • Regularly review stored files

For Administrators

  1. Keep Software Updated:

    • Regularly update Python packages
    • Monitor security advisories
    • Apply patches promptly
  2. Monitor Logs:

    • Review authentication logs
    • Watch for suspicious activity
    • Set up alerts for failed login attempts
  3. Database Security:

    • Regular backups
    • Restrict file system permissions
    • Consider encrypting database at rest
  4. Network Security:

    • Use firewall rules
    • Limit exposed ports
    • Enable fail2ban or similar

Current Limitations

Known Security Gaps (Future Enhancements)

  1. No Two-Factor Authentication (2FA)

    • Planned: TOTP-based 2FA
  2. No Audit Logging

    • Planned: Comprehensive audit trail
  3. Basic Password Policy

    • Current: 6 character minimum
    • Planned: Complexity requirements, strength meter
  4. No Email Verification

    • Planned: Email verification on registration

Reporting Security Issues

If you discover a security vulnerability, please:

  1. DO NOT open a public GitHub issue
  2. Email security concerns to: [[email protected]]
  3. Include:
    • Description of the vulnerability
    • Steps to reproduce
    • Potential impact
    • Suggested fix (if any)

We will respond within 48 hours and work with you to address the issue.

Version History

v2.3 (Current)

  • Added optional database encryption (SQLCipher)
  • Added optional file encryption (Fernet)
  • OIDC/SSO authentication support

v2.2

  • Added CSRF protection (Flask-WTF)
  • Implemented rate limiting (Flask-Limiter)
  • Enforced SECRET_KEY requirement
  • Added session security configuration
  • Fixed debug mode exposure

v2.1

  • Basic authentication
  • Password hashing
  • User data isolation
  • File upload security

Additional Resources


Last Updated: 2025-12-10 Maintained By: HSA Tracker Development Team

There aren’t any published security advisories