java.sql.PreparedStatement
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:
-
What happens when executing thousands of SQL statements having identical structure?
-
Is this architecture adequate with respect to security concerns?
INSERT INTO Person VALUES ('Jim', 'jim@q.org')
INSERT INTO Person VALUES ('Eve', 'eve@y.org')
INSERT INTO Person VALUES ('Pete', 'p@rr.com')
...
Wasting time parsing SQL over and over again!
INSERT INTO Person VALUES
('Jim', 'jim@q.org'),
('Eve', 'eve@y.org'),
('Pete', 'p@rr.com') ... ;
Dealing with large record counts even this option may become questionable.
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.
-
User input being excluded from parsing.
-
Allows for reuse per record.
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:
-
PreparedStatement
instance creation: Parsing SQL statement possibly containing place holders. -
Set values of all placeholder values: SQL values are not being parsed.
-
Execute the statement.
Steps 2. and 3. may be repeated without re-parsing the underlying SQL statement thereby saving database server resources.
Our introductory toy application Figure 865, “JDBC™
backed data insert ” may be rewritten using
PreparedStatement
objects:
PreparedStatement
example final Connection conn = DriverManager.getConnection (...
final PreparedStatement pStmt = conn.prepareStatement(
"INSERT INTO Person VALUES(?, ?)");❶
pStmt.setString(1, "Jim");❷
pStmt.setString(2, "jim@foo.org");❸
final int updateCount = pStmt.executeUpdate();❹
System.out.println("Successfully inserted " + updateCount + " dataset(s)");
An instance of
|
|
Fill in the two placeholder values being defined at ❶. |
|
Execute the beast! Notice the empty parameter list. No SQL is required since we already prepared it in ❶. |
Jim', 'jim@c.com');DROP TABLE Person;INSERT INTO Person VALUES('Joe
Attacker's injection text simply becomes part of the database server's content.
Problem solved!
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. |
No. 10
Prepared Statements to keep the barbarians at the gate
Q: |
Use 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. |
A: |
See:
|