Database Hardening Fundamentals
Database Hardening Fundamentals
Default database installations include numerous features, sample databases, and permissive configurations designed to simplify initial setup and demonstration. These defaults become security liabilities in production environments. Database hardening involves systematically removing unnecessary components, restricting permissions, and configuring security features to minimize attack surface while maintaining required functionality.
The hardening process begins with removing all unnecessary components. Sample databases, while useful for learning, provide attackers with known schemas and data to exploit. Default stored procedures, especially those with system-level privileges, offer ready-made attack vectors. Extended stored procedures that interact with the operating system pose particular risks. Even seemingly benign features like xp_cmdshell in SQL Server or UTL_FILE in Oracle can become devastating attack tools if left enabled.
Network configuration represents another critical hardening aspect. Databases should never be directly accessible from the internet, with application servers serving as the sole connection point. Binding databases to localhost or private network interfaces prevents external access even if firewall rules are misconfigured. For distributed systems requiring remote database access, VPNs or encrypted tunnels should protect connections, with IP whitelisting providing additional access control.
-- PostgreSQL hardening configuration example
-- File: postgresql.conf
# Network Security
listen_addresses = '10.0.1.5' # Private network only, not '*'
port = 5432
max_connections = 100 # Limit based on actual needs
# SSL Configuration
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'
# Authentication
password_encryption = scram-sha-256 # Not md5
authentication_timeout = 30s
# Logging for Security Auditing
logging_collector = on
log_directory = 'pg_log'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = 1d
log_rotation_size = 100MB
# Security-relevant logging
log_connections = on
log_disconnections = on
log_duration = off # Can impact performance
log_statement = 'ddl' # Log schema changes
log_min_duration_statement = 1000 # Log slow queries (potential DoS)
# Statement logging for security
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '
log_checkpoints = on
log_lock_waits = on
# Resource Limits (Prevent DoS)
shared_buffers = 256MB
work_mem = 4MB
maintenance_work_mem = 64MB
max_wal_size = 1GB
min_wal_size = 80MB
# Security Features
row_security = on # Enable row-level security
default_transaction_isolation = 'read committed'
# Disable dangerous functions
shared_preload_libraries = 'pg_stat_statements' # But not 'plpythonu' etc.