TDA357 L09 JDBC, Security
TDA357 L09 JDBC, Security
Queries
Database
HTTP
server
server
Result tables
Web client
Python or Java?
try:
with psycopg2.connect(
host="localhost",
user="postgres",
password="postgres") as conn: Does important stuff
conn.autocommit = True
# actual code goes here (see lecture on transactions)
except psycopg2.Error as e:
print(str(e))
Your first JDBC program
• Assuming conn is the Connection object we opened earlier
• Queries are written in Java strings
• Use try-with-resource to automatically close Statements
String query = "SELECT idnr,name FROM BasicInformation";
try (Statement s = conn.createStatement();){
ResultSet rs = s.executeQuery(query); Run the query
while(rs.next()){
next() moves to the next row, returns
String id = rs.getString(1); false if there are no more rows
String name = rs.getString(2);
System.out.println(id + " " + name); fetches column 2 (name)
} of the current result row
} loop through whole result
The next() method in ResultSet
• Each ResultSet has an internal cursor pointing at the current row in the result
• Initially the cursor is "above" the table, pointing at no row
• If there is a row below the current one, next() will move to it and return true
• Otherwise it closes the ResultSet and returns false
• If next() returns false or has not been called, calls to get* will throw exceptions
For this result, next() is called 3 times
while(rs.next()){
System.out.println(rs.getString(1)+" "+rs.getString(2));
}
Result in rs
Call 1: cursor "above" table, move to first row and return true idnr name
Call 2: cursor at first row, move to second and return true 1111111111 S1
Call 3: cursor at second row, close and return false 2222222222 S2
(this terminates the loop!)
Single row query
• Replace the while-loop with an if-else for queries that should give a single row
• The else-clause deals with the case when no row is found
String query =
"SELECT idnr,name FROM BasicInformation WHERE idnr='2222222222'";
try (Statement s = conn.createStatement();){
ResultSet rs = s.executeQuery(query);
if(rs.next()) Always a single call to next()
System.out.println(rs.getString(2));
else
System.out.println("error, no such student!");
We could use if(rs.next()) again to check that there are no more rows
Updates (includes deletes and inserts!)
• The executeUpdate method in Statement is for UPDATE/INSERT/DELETE
• Also for creating/dropping tables etc, but that's rarely done from applications
• Does not give a ResultSet, instead gives an int (the number of affected rows)
• What happens if the student inputs this course code: "x' OR 'a'='a"?
• The query will be:
DELETE FROM Registered WHERE student='1337' AND course='x' OR 'a'='a'
• Ooops, that query just deleted all our registrations...
WHERE-clause is always true
SQL injection attacks
• The trick on the last slide is called SQL injection
(because we "inject" code into user inputs)
• In the youth of the WWW, this could In the worst cases, you can even run
be used to hack almost any website
arbitrary statements (that is why ; is
• The counter is to sanitize input data, not allowed at all in JDBC queries)
making sure reserved characters (like
single quotes) are
properly escaped
• Still, lots of programmers
are too lazy to do this...
try(PreparedStatement ps = conn.prepareStatement(
"DELETE FROM Registered WHERE student=? AND course=?");){
String sid = "111111111";
String code = <request user input>;
Two parameters (1 and 2)
ps.setString(1,sid);
ps.setString(2,code);
ps.executeUpdate();
Turns the Java string into an SQL string,
} escaping as needed and adding enclosing
single quotes, placing it in parameter 2
Use prepared statements
• You should use prepared statements for all queries and statements that
contain any kind of user input
• Good rule of thumbs: Always use prepareStatement() instead of
createStatement() unless you have a compelling reason not to
(which you will never have in this course)
Debugging JDBC code
• Getting syntax errors? Query running but not getting the result you expected?
• Add some debug printing! (Or use a proper debugger)
• Run the printed query in psql to get a better idea of what's wrong
• Always remove your debugging code before submitting!
try(PreparedStatement ps = conn.prepareStatement(
"DELETE FROM Registered WHERE student=? AND course=?");){
ps.setString(1,sid);
ps.setString(2,code);
System.out.println("query is: " + ps);
int r = ps.executeUpdate();
}
Prints the actual query being executed, including set parameters
Sanitized string
try(PreparedStatement ps = conn.prepareStatement(
"DELETE FROM Waiting WHERE position=? AND course=?");){
int pos = 1;
String code = "x' OR 'a'='a";
Safe:
cur.execute
cur execute("SELECT
execute "SELECT * FROM Registered WHERE student=%s AND course=%s",
course=%s" (id
id,course
id course))
course
Uses the % operator to insert text into the string
Sends a single parameter to execute
cur.execute
cur execute("SELECT
execute "SELECT * FROM Registered WHERE student='%s' AND course='%s'" % (id
id,course
id course))
course