Sanitizing user input is a means to secure an application. The JDBC™ standard however provides a mechanism being superior regarding the purpose of protecting applications against SQL injection attacks. We shed some light on our current mechanism sending SQL statements to a database server:

Figure 879. SQL statements in Java applications get parsed at the database server Slide presentation
SQL statements in Java™ applications get parsed at the database server

Figure 880. Two questions Slide presentation
  1. What happens when executing thousands of SQL statements having identical structure?

  2. Is this architecture adequate with respect to security concerns?

Figure 881. Addressing performance Slide presentation
INSERT INTO Person VALUES ('Jim', '')
INSERT INTO Person VALUES ('Eve', '')
INSERT INTO Person VALUES ('Pete', '')

Wasting time parsing SQL over and over again!

Figure 882. Addressing performance mitigation Slide presentation
  ('Jim', ''),
  ('Eve', ''),
  ('Pete', '') ... ;

Dealing with large record counts even this option may become questionable.

Figure 883. Restating the SQL injection problem Slide presentation

The database server's interpreter may interpret an attacker's malicious code among with intended SQL.

  • User input is being interpreted by the database server's interpreter.

  • User input filtering my be incomplete / tedious.

Figure 884. Solution: Use java.sql.PreparedStatement Slide presentation
  • User input being excluded from parsing.

  • Allows for reuse per record.

Figure 885. PreparedStatement principle. Slide presentation
PreparedStatement principle.

Prepared statements are an example for parameterized SQL statements which do exist in various programming languages. When using java.sql.PreparedStatement instances we actually have three distinct phases:

Figure 886. Three phases using parameterized queries Slide presentation
  1. PreparedStatement instance creation: Parsing SQL statement possibly containing place holders.

  2. Set values of all placeholder values: Values SQL are not being parsed.

  3. Execute the statement.

Steps 2. and 3. may be repeated without requiring re-parsing SQL statements thus saving database server resources.

Our introductory toy application Figure 849, “JDBC™ backed data insert ” may be rewritten using PreparedStatement objects:

Figure 887. PreparedStatement example Slide presentation
final Connection conn = DriverManager.getConnection (...

final PreparedStatement pStmt = conn.prepareStatement(
  "INSERT INTO Person VALUES(?, ?)");❶

pStmt.setString(1, "Jim");❷
pStmt.setString(2, "");❸

final int updateCount = pStmt.executeUpdate();❹

System.out.println("Successfully inserted " + updateCount + " dataset(s)");

An instance of java.sql.PreparedStatement is being created. Notice the two question marks representing two place holders for string values to be inserted in the next step.

Fill in the two placeholder values being defined at ❶.


Since half the world of programming folks will index a list of n elements starting from 0 to n-1, JDBC™ apparently counts from 1 to n. Working with JDBC™ would have been too easy otherwise!

Execute the beast! Notice the empty parameter list. No SQL is required since we already prepared it in ❶.

Figure 888. Injection attempt example Slide presentation
Jim', '');DROP TABLE Person;INSERT INTO Person VALUES('Joe

Attacker's injection text simply becomes part of the database server's content.

Problem solved!

Figure 889. Limitation: No dynamic table support! Slide presentation
  • SELECT birthday from Persons
  • PreparedSatatement statement =
      connection.prepareStatement("SELECT ?  from ?" );
    statement.setString(1, "birthday") ;
    statement.setString(2, "Persons") ;
    ResultSet rs = statement.executeQuery() ;

In a nutshell: Only attribute value literals may be parameterized.

Providing an attributes name as parameter.

Providing the table name to be queried as parameter.

Setting the desired attributes name intending:

SELECT birthday FROM ...

Setting the table name to be queried intending:

SELECT birthday FROM Persons

Fails: Only attribute value literals are allowed.

exercise No. 10

Prepared Statements to keep the barbarians at the gate


Use PreparedStatement objects to sanitize your flawed Interactive inserts, connection properties, error handling and unit tests implementation being susceptible to SQL injection attacks.

When you are done repeat your injection attempt from Attack from the dark side . You may require larger string lengths in your SQL schema for accommodating the injection string.