Need the #1 custom application developer in Brisbane?Click here →

Database Security

9 min read

Database security is foundational. A compromised database is your worst-case scenario. An attacker with database access has your users' passwords, payment information, messages, and everything else you store. Security must be multi-layered, not relying on any single defense.

SQL Injection: The Foundational Vulnerability

SQL injection is still the most common database vulnerability. An attacker injects SQL into user input that gets executed as a query. SELECT * FROM users WHERE email = 'user' OR '1'='1' returns all users. This is completely preventable.

The defense is parameterised queries. Never concatenate user input into SQL. Always use placeholders. SELECT * FROM users WHERE email = ? with email provided as a parameter is impossible to inject. The database treats the parameter as data, never as code.

Every ORM handles parameterisation automatically. Using an ORM essentially prevents SQL injection by default. If you write raw SQL, use parameterised queries religiously.

Encryption at Rest

Database files on disk should be encrypted. If an attacker gains physical access to the server, encrypted data is unreadable. Managed database services (RDS, Supabase, etc.) include encryption at rest by default. Self-hosted databases require explicit configuration.

Full-disk encryption or database-level encryption both work. The goal is that a stolen hard drive yields no data.

Encryption in Transit

Connections to the database must use TLS (HTTPS for databases). Data in transit between your application and the database is encrypted. Managed services handle this by default. Self-hosted databases need TLS configuration.

Credential Management

Database passwords must never be in code. Never. Don't commit them to git. Don't hardcode them in configuration files. Use environment variables or a secrets manager.

Environment variables: DATABASE_PASSWORD=secret in .env, read by the application. The .env file is in .gitignore so it's never committed. This works for development.

Secrets managers (AWS Secrets Manager, HashiCorp Vault, Supabase's Secrets management) securely store and rotate secrets. The application requests the secret, which is retrieved and injected. This is better than environment variables for production.

Principle of Least Privilege

The application's database user should have minimal permissions. If the application only SELECTs, INSERTs, UPDATEs, and DELETEs from specific tables, the user should have only those permissions on those tables. NOT permissions to drop tables or create users or modify system tables.

If your database is compromised through an application vulnerability, the attacker can't do more than the application user can do. A read-only replica user can't modify data. A user limited to a specific schema can't access other schemas.

Database Firewall

The database should not be publicly accessible. Only your application servers should be able to connect. This is typically handled by network configuration: the database runs in a private subnet, only accessible to the application in the same VPC.

Managed databases are configured this way by default. Self-hosted databases in cloud providers can be configured the same way with security groups and VPCs.

Backups: Your Safety Net

Backups must exist, be tested, and be encrypted. Know your backup retention (can you restore from 30 days ago? 1 year?). Know your recovery time (how long until you're back online?).

Automated backups are standard. Take backups frequently. Test restores quarterly to ensure backups aren't corrupted. Backups should be in a separate region or account to protect against regional outages or account compromise.

PII and Sensitive Data

Personal Identifiable Information (names, emails, phone numbers) and sensitive data (credit card numbers, SSNs, health information) require additional protection. Store credit card numbers in a separate, tightly-secured database or use a payment processor's tokenization. Use field-level encryption for the most sensitive fields.

Even with database encryption, a stolen backup containing millions of credit card numbers is catastrophic. Field-level encryption means even backups contain encrypted data.

Audit Logging

Log who accesses what data, when. PostgreSQL's audit logging can track all queries. This is required for compliance (HIPAA, SOC 2, etc.) and invaluable for detecting breaches.

Logs themselves are sensitive—they contain queries which might include user data. Log to a separate, secured system.

Access Control

Database access should be limited to people who need it. Most developers don't need production database access. Database admins have full access. Application users have only the access required for their role.

Managed databases provide role-based access control. Supabase, RDS, and others let you define who can access the database and what they can do.

Monitoring for Anomalies

Monitor for unusual activity: unexpected large queries, unusual access patterns, failed authentication attempts. Alerting on anomalies can catch compromises early.

Warning
A compromised database is a critical security incident. A single breach can expose millions of user records. Database security is not optional. Implement multiple layers of defense: parameterised queries, encryption, access control, backups, monitoring.
Developer Insight
When evaluating a managed database service, check their security certifications (SOC 2, ISO 27001), encryption capabilities, backup policy, and audit logging. These factors should drive your choice.