I'm looking to inspect SQL statements in Java/jdbc code to ensure that the SQL to be executed is of acceptable quality. Neither PMD not Findbugs appears to have JDBC or sql rules. I could use p6spy to log the SQL and look at that way, but this is manual.
I'm wondering if the strategy of of using PMD/Findbugs/etc to create a rule that any string passed to PreparedStatement where there is an "=" or "in" has only parametrized vars on the compare side.
Has anyone done this? Or done this by other means?
This is a tricky problem. Comparison operators like = and IN() are some cases, but there's also: != <> < <= > >= LIKE.
How do you spot cases of interpolating application variables as literals in expressions?
String sql = "SELECT *, " + someJavaVar + " AS constant_column FROM mytable";
You could search for SQL containing string delimiters, but SQL injection doesn't come only from interpolating string literals.
How would you spot cases of interpolating application variables as things other than data values?
String sql = "SELECT * FROM mytable ORDER BY " + columnname;
I don't know any automatic way to detect SQL injection flaws. Code review is a more effective way to spot them. In every SQL statement that contains interpolated application variables, you have to confirm that the application variables are "safe" and that your app has explicitly validated them or transformed them so they don't contain dangerous payload.
Do you have the ability to completely test the application with a debugger connected to it?
Set a breakpoint in your JDBC driver's implementation of Connection.createStatement(), and run the app... (or if using a driver for which you don't have source code, write a fake driver that just delegates calls to the real one, and log all instances of createStatement())
Related
From https://en.wikipedia.org/wiki/Code_injection#Preventing_problems
To prevent code injection problems, utilize secure input and output handling, such as:
Using APIs that, if used properly, are secure against all input characters. Parameterized queries (also known as "Compiled queries", "prepared statements", "bound variables") allows for moving user data out of string to be interpreted. Additionally Criteria API[7] and similar APIs move away from the concept of command strings to be created and interpreted.
I was wondering how and why "parameterized queries (also known as "Compiled queries", "prepared statements", "bound variables") allows for moving user data out of string to be interpreted" and prevent or mitigate code injection problems?
Can you also provide some examples in explanation?
Thanks.
Compiled queries use special syntax that the database understands. They usually add placeholders for parameters such as in:
select * from applicant where name = ?
select * from applicant where name = :name
The exact syntax depends on the specific technology: JDBC, ODBC, etc.
Now, once those queries are sent to the database (without the specific parameter values), the database "saves" them. Later on (usually in the same database session), you can run them many times, by just providing the parameter values each time.
SQL Injection Safety
They are also safe against SQL injection. For example, if in the previous query instead of a simple value such as Mary you used the value x'; delete from applicant; -- the database will work safely. It would run something like:
select * from applicant where name = 'x; delete from applicant; --'
This query won't probably find anything and will be safe.
If instead you didn't use compiled query, but just decided to concatenate the SQL as a string you would do something like:
String sql = "select * from applicant where name = '" + param1 + "'";
And would end up with the UNSAFE query:
select * from applicant where name = 'x'; delete from applicant; --
This one would run two queries. The second one will delete all the information from your table. Probably not what you want.
I have a SQL statement String in Java which contains, among other things, the segment:
" AND \"Reference_No\" > ? "
I understand that this is a parameterized query, where the statement is precompiled and the parameters then added, in order to prevent injection attacks.
However, every example I've seen of this used, I have always seen accompanying code where the parameter values are then hard-coded in using some kind of setter method with code that runs something like:
setValue(1, "value1");
The program I am trying to understand does not appear to have this accompanying code, and I am trying to understand at what point a value is added to this SQL statement.
The application which uses this is a webUI servlet that sends and receives job transactions. More specifically, I am looking at the page that lists pending transactions.
I have a method which contains the following:
List<Job> query = getJdbcTemplate().query(sql.toString(),
new Object[]{minRef},
rowMapper);
sql contains the SQL statement segment in question.
Is the value-adding dealt with by the JdbcTemplate class? If so, how does it determine the values?
public function receiveDomainNames($keyword)
{
try
{
$stmt = $this->_dbh->prepare("SELECT d.someField FROM domain d WHERE d.someField LIKE :keyword");
$someField = '%'.$keyword.'%';
Do we need to escape $keyword on this case?
On php manual we can read:
If an application exclusively uses prepared statements, the developer can
be sure that no SQL injection will
occur (however, if other portions of
the query are being built up with
unescaped input, SQL injection is
still possible).
Is this the case on your opinion, are, on this case, build up unescaped input (no prior treatment has been made to our $keyword parameter) ?
Thanks in advance,
MEM
Given the above SQL statement, I see no rational possibility of a SQL injection.
What the warning about "other parts" would be a SQL query like:
$binds = array(":id"=>$_GET['id']);
$myPDO->prepare("SELECT {$_GET['columns']} FROM {$_GET{['table']} WHERE id = :id");
$statement = $myPDO->execute($binds);
The example is a worst case/explicit example of what they mean, that naively someone might think since they're escaping the where argument, that everything is safe.
With your example above, there is no un-escaped input so you're safe.
If an application exclusively uses prepared statements, the developer
can be sure that no SQL injection will occur (however, if other
portions of the query are being built up with unescaped input, SQL
injection is still possible).
I'd figure variables you create shouldn't have to be escaped because you know what they're doing.
Only escape content gotten from the user, such as $_COOKIE, $_POST, $_GET and other parameters such as the URL.
The classic way to query an SQL database case-insensitively from Java is as follows:
String name = ...; // get the user's input (case is unknown)
String sql = "select * from Person where lower(name) = ?";
Object jdbcBindVariable = name.toLowerCase();
// ... using JDBC, bind that variable and run the SQL query
The problem is that lower-casing is a locale-specific operation. For example, lower-casing the letter "I" gives different results in English and Turkish. In the above code, there are two lower-casing operations:
The String#toLowerCase() method
The lower() database function
How can I make sure that Java and the database are using the same locale and thereby performing a valid comparison?
I'm aware that the String class has a toLowerCase(Locale) method, but how do I know what Locale the database is using? Can I check this programatically, or do I have to hard-code the locale to the one with which I think the database (in this case Oracle 10g) is configured?
The simple answer is let the database do it.
That way the way the bind variable is put into lower case will be consistent with the way the column value is put into lowercase.
String sql = "select * from Person where lower(name) = lower(?)";
... but how do I know what Locale the database is using? Can I check this programmatically ...
There doesn't appear to be a portable (database independent) way to do this, but you can apparently use the following query to get the charset used by an Orable database:
select value from nls_database_parameters where parameter = 'NLS_CHARACTERSET';
This page gives more details.
As for actually doing the comparison, you would be best off (*) letting the database take care of the lower-casing, as #Gary suggests. The JDBC driver will take care of converting Java (UTF-16) Strings into whatever the database is using.
(* In fact, I don't think you have much choice, unless you are prepared to wear the cost of storing mixed-case and lower-case copies of all queriable strings in the database.)
I'm unsure how someone would break my SQL if I simply replace all incoming single quotes with double quotes. Can someone enlighten me for both Oracle and SQL Server examples? Thanks.
string sql1 = "select * from users where user_id = '" + "O'Reily".Replace("'", "''").Replace("\", "") + "'";
==> "select * from users where user_id = 'O''Reily'
string sql2 = "select * from users where user_id = '" + "O'''Reily".Replace("'", "''").Replace("\", "") + "'";
==> "select * from users where user_id = 'O''''''Reily"
UPDATE: the slash '\' is a restricted character in the application and will be stripped out before it is used in the query. A double dash can just as easily be added to this list of restricted characters.
Parameterize your variables. Seriously. All modern environments have facilities to do so and you don't have to worry about escape sequences like \' which will turn into \'' with your scheme (in Oracle) which becomes an escaped quote and a regular (terminating) quote.
There are plenty of other tricks to pull this off which I'm not enumerating as they aren't helpful.
Again: Parameterize your variables. Seriously. If you won't learn how to use the parameterization you will become another hacked statistic.
EDIT: Read the links in Paul's answer and here is another: http://unixwiz.net/techtips/sql-injection.html
No matter how clever you think your sanitation of strings is, you are doing it wrong. Especially if you have to handle multiple back ends.
Composing queries out of strings is one of the few things I will flat out fire people for... the risk such a programmer poses to the company is greater than just about anything else they bring to the table (especially after we make it very clear we won't accept such code on day one and provide an entity framework that makes such things unnecessary).
To prevent SQL injection, what you really should do is use bound positional or named parameters instead of constructing your SQL as a string with the user input inlined. How this is done depends on how your application accesses the database. For example, here is what it would look like in Java using JDBC:
Bad:
String updateString = "UPDATE COFFEES SET SALES = 75 " +
"WHERE COF_NAME LIKE 'Colombian'";
stmt.executeUpdate(updateString);
Good:
PreparedStatement updateSales = con.prepareStatement(
"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate():
I borrowed the example from here:
http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html
Your proposed solution is vulnerable to the inclusion of the \' string, which would end your quoted section and allow the injection of other commands.
You want to use SQL prepared statements wherever possible, which should be everywhere. Basically, you write your sql with specific placeholders for your data, and then pass that data via a separate, non-interpreted channel to the sql server.
A few links:
http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html
http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html
http://mattbango.com/notebook/web-development/prepared-statements-in-php-and-mysqli/
There are some tricks involving the attacker taking advantage of the application truncating input :
http://www.rampant-books.com/t_super_sql_154_ideas_prevent_injection.htm