Database Security Is More Than Just SQL Injection

SQL injection is the vulnerability most developers associate with database security, and for good reason—it remains one of the most well-known attack classes, catalogued in the OWASP Top 10 and immortalized in the "little Bobby Tables" comic. But secure database access involves more than preventing injection. OWASP's Top 10 Proactive Control C3 identifies four distinct areas developers must address, and a fifth deserves equal attention.

  1. Secure queries
  2. Secure configuration
  3. Secure authentication
  4. Secure communication
  5. Secure connection (an addition worth making on its own)

Notably, these concerns apply to all database types. NoSQL databases, OQL, GraphQL, and stored procedures are no more inherently secure than relational SQL databases.

Secure Queries: Parameterization Is the Answer

Query injection remains one of the oldest vulnerability classes, and it still produces new instances every year. The core principle is simple: user-controlled data must never be able to change the meaning of a database query. That includes SQL statements as well as NoSQL, OQL, GraphQL, stored procedures, and any other query interface.

The danger arises when user input is concatenated or interpolated directly into a query template. Consider a login query where username and password are user-provided:

String query = "Select * from USERS where name = '" + request.getParam("username") + "' and password = '" + request.getParam("password") + "'" ;

An attacker can break out of the single-quoted string context where their data is placed, changing the meaning of the query itself. A value like:

Username: "admin"
Password: "FOO' or '1'='1"

Turns the templated query into:

String query = "Select * from USERS where name = 'admin' and password = 'FOO' or '1' = '1'";

This returns all users and can let an attacker authenticate as an administrator. Worse, depending on the database and privileges, injection can lead to reading arbitrary records, dropping tables, writing files, or executing system commands.

Input validation and sanitization—for example, stripping or escaping single quotes—are error-prone and insufficient. Some injections don't require breaking out of a single-quoted context at all, and sanitizers may miss dangerous characters or handle only the first occurrence.

The reliable mitigation is query parameterization. Most database libraries offer this feature, which separates the query template from the parameters and applies proper encodings automatically. In Java, parameterized queries look like:

String custname = request.getParameter("customerName");
String query = "SELECT account_balance FROM user_data WHERE user_name = ? ";  
PreparedStatement pstmt = connection.prepareStatement( query );
pstmt.setString( 1, custname);
ResultSet results = pstmt.executeQuery( );

Some parts of SQL queries cannot be parameterized. In those cases, if you must craft parts of the query with string concatenation, apply strict validation: type checking, mapping to predefined values, or using indirect values. The goal is to ensure user input cannot escape the intended query context. OWASP's Query Parameterization Cheat Sheet is a useful reference for how specific libraries implement this.

Secure Configuration: Hardening Beyond Defaults

While SQL injection remains the top database vulnerability, misconfigurations can enable other attacks or escalate an injection into remote command execution. Many database management systems are not hardened by default, and insecure defaults vary across DBMS products.

OWASP's Database Security Cheat Sheet lists the insecure defaults to address. Recommended hardening steps include:

  • Disabling command execution features when not needed
  • Disabling stored procedures when not needed
  • Disabling insecure authentication modes
  • Removing sample databases installed by default
  • Disabling browser services exposed by default
  • Disabling file system access features if not needed
  • Changing default ports
  • Disabling default unencrypted transport protocols
  • Disabling unauthenticated access

Secure Authentication: Accounts and Audits

Default database configurations may not require authentication at all. Proper authentication matters for two reasons: it prevents unauthenticated users with local access to the database port from tampering with data, and it provides an audit trail of who accessed the database and what actions they performed.

Authentication should only occur over secure channels, and credentials must be protected. Key practices from OWASP's cheat sheet include:

  • Setting strong and secure passwords
  • Using per-application or per-service accounts
  • Applying the principle of least privilege, granting only the minimum needed access
  • Performing regular account audits to verify accounts are still needed, have minimal privileges, and that passwords, keys, or tokens are rotated

Secure Communication: Encryption and Isolation

A database is only as secure as the services, APIs, and transport methods used to reach it. Where multiple communication options exist, use only encrypted connections against authenticated endpoints. The database connection cheat sheet recommends:

  • Isolating the backend database as much as possible, placing it on a separate DMZ isolated from application servers
  • Disabling network access when possible
  • Binding services to local ports when possible
  • Limiting access to service ports to specific hosts that need to access the database
  • Configuring the database to allow only encrypted connections

Secure Connection: Guarding Against Connection String Attacks

Beyond OWASP's four categories, a fifth area deserves attention. In some cases, high-privileged users can control the DBMS connection string through configuration files or administrative panels, either entirely or partially. Depending on the DBMS and language, connection string control can lead to parameter pollution, deserialization attacks, or JNDI datasource injection.

Apply the same defensive principles used elsewhere:

  • Validate that only expected characters are used
  • Encode input for the correct connection string context—host, authority, parameters, and so on
  • When possible, use indirection so final values come from a predefined set of known-good values

Addressing these five areas reduces the risk of database security issues. The OWASP cheat sheets linked throughout are worth bookmarking as practical references for writing more secure code.