Skip to main content

Security

DBBat implements multiple security layers to protect both the proxy infrastructure and the target databases.

Authentication

Password Hashing

User passwords are hashed using Argon2id, the winner of the Password Hashing Competition:

  • Memory-hard algorithm resistant to GPU/ASIC attacks
  • Configurable memory, time, and parallelism parameters
  • Includes salt to prevent rainbow table attacks

Password Requirements

  • Mandatory change: Users must change their initial password before accessing the API
  • Minimum length: 8 characters (configurable)
  • Login attempts before password change return 403 password_change_required

Authentication Rate Limiting

Failed login attempts trigger exponential backoff per username:

Failed AttemptsLockout Duration
1-2None
3-45 seconds
5-630 seconds
7-92 minutes
10+5 minutes

This prevents brute-force attacks while allowing legitimate users to recover from typos.

Token Types

TypePrefixLifetimeUse Case
Web Sessionweb_1 hourInteractive frontend use
API Keydbb_Configurable (or permanent)Programmatic access

API Key Restrictions

API keys have intentional limitations:

  • Cannot create other API keys
  • Cannot revoke API keys
  • These operations require web session or basic auth

This prevents a compromised API key from being used to create persistent backdoor access.

Encryption

Database Credentials

Target database passwords are encrypted at rest using AES-256-GCM:

  • 256-bit encryption keys
  • Authenticated encryption (integrity + confidentiality)
  • Random nonce per encryption operation
  • AAD binding: Ciphertext is bound to the database ID, preventing credential transplant attacks

Key Management

Encryption keys are provided via environment:

VariableDescription
DBB_KEYBase64-encoded 32-byte key
DBB_KEYFILEPath to file containing the key

Keys are:

  • Never logged or exposed via API
  • Never transmitted over the network
  • Required at startup (DBBat won't start without a valid key)

Role-Based Access Control

Roles

RoleDescription
adminFull access to all resources and operations
viewerRead-only access to observability data (queries, connections, audit)
connectorCan only connect to databases with active grants

Users can have multiple roles. Permissions are additive.

Resource Visibility by Role

ResourceAdminViewerConnector
All usersFullList onlyOwn only
All databasesFull detailsName/descriptionGranted only
All grantsFullFullOwn only
All queriesFullFullNone
All connectionsFullFullOwn only
Audit logFullFullNone

Access Grants

Grants control which users can connect to which databases through the proxy.

Grant Constraints

ConstraintDescription
starts_atGrant is not valid before this time
expires_atGrant automatically expires after this time
max_query_countsMaximum queries allowed (quota)
max_bytes_transferredMaximum data transfer allowed (quota)
access_levelread or write

Recommendation: Always set all constraints. Time-limited grants with quotas minimize blast radius if credentials are compromised.

Grant Lifecycle

  1. Admin creates grant with constraints
  2. Grant becomes active at starts_at
  3. User can connect and execute queries
  4. Quotas are enforced per-query
  5. Grant expires at expires_at or when revoked
  6. Revoked grants record revoked_at and revoked_by for audit

Read-Only Mode

When a grant has access_level: read, DBBat enforces read-only access through defense in depth.

Layer 1: Query Inspection

Queries are inspected and blocked if they match write patterns:

  • DML: INSERT, UPDATE, DELETE, MERGE
  • DDL: CREATE, ALTER, DROP, TRUNCATE
  • DCL: GRANT, REVOKE
  • Other: COPY FROM, CALL (procedures)

Layer 2: PostgreSQL Session Setting

At connection establishment, DBBat sets:

SET SESSION default_transaction_read_only = on;

PostgreSQL itself then blocks any write operation, regardless of SQL syntax.

Layer 3: Bypass Prevention

Attempts to disable read-only mode are blocked:

  • SET default_transaction_read_only = off
  • RESET default_transaction_read_only
  • SET SESSION AUTHORIZATION (privilege escalation)
  • SET ROLE (privilege escalation)

Limitations

Read-only mode is defense in depth for trusted users, not a security boundary against malicious actors:

  • Regex-based inspection may miss edge cases
  • New PostgreSQL syntax could bypass detection
  • Functions with SECURITY DEFINER might execute writes

For untrusted access: Create a dedicated PostgreSQL user with GRANT SELECT only.

Audit Trail

What's Logged

Event TypeData Captured
ConnectionsUser, database, source IP, timestamps, query count
QueriesSQL text, parameters, execution time, rows affected, errors
Query ResultsAll result rows (for replay/audit)
Access ChangesGrant creation, revocation, user changes

Audit Log Integrity

  • Audit logs are append-only (no UPDATE/DELETE via API)
  • Protected from modification via proxy (internal table protection)
  • Includes performed_by for accountability

API Rate Limiting

All authenticated endpoints are rate-limited:

  • Per-user request limits
  • Response headers indicate remaining quota
  • 429 Too Many Requests when exceeded

Rate limit exempt users can be configured for automation/CI.

Network Security

Upstream Connections

DBBat supports PostgreSQL SSL modes for upstream connections:

ModeDescription
disableNo SSL
preferTry SSL, fall back to plain (default)
requireRequire SSL, don't verify certificate
verify-caRequire SSL, verify CA
verify-fullRequire SSL, verify CA and hostname

Recommendation: Use require or stronger for production.

Client Connections

DBBat accepts plain PostgreSQL protocol connections. For encryption:

  • Deploy behind a TLS-terminating load balancer, or
  • Use network-level encryption (VPN, private network)

Security Checklist

Deployment

  • Set strong encryption key (DBB_KEY or DBB_KEYFILE)
  • Use separate database for DBBat storage
  • Enable TLS for upstream connections (ssl_mode: require)
  • Deploy in private network or behind VPN
  • Change default admin password immediately

Operations

  • Use time-limited grants (hours/days, not years)
  • Set query and byte quotas on all grants
  • Prefer read access level unless writes are required
  • Review audit logs regularly
  • Rotate API keys periodically
  • Monitor for blocked query attempts

For Target Databases

  • Use dedicated PostgreSQL user for DBBat upstream connections
  • Grant minimum required privileges to that user
  • For read-only grants, use PostgreSQL user with only SELECT privileges
  • Enable PostgreSQL logging as additional audit layer