Appscan source edition - SQL Injection - java

I am using Appscan source edition for Java Secure Coding. It is reporting an SQL injection in my application. The issue is that we are generating the query dynamically in code so I cannot use a prepared statement. Instead I have to us e Esapi.encoder().encodeForSql(new OracleCodec(), query). AppScan does not consider this to mitigate the SQL injection issue.
final String s = "SELECT name FROM users WHERE id = " +
Esapi.encoder().encodeForSql(new OracleCodec(), userId);
statement = connection.prepareStatement(s);
This code additionally does not work for ESAPI.encoder()
How can I resolve this issue?

what you should do is
final String s = "SELECT name FROM users WHERE id = ?"
statement = connection.prepareStatement(s);
statement.setString(1, userId);

The documentation for encodeForSQL recommends a PreparedStatement which you can still use which dynamically generated queries:
Encode input for use in a SQL query, according to the selected codec
(appropriate codecs include the MySQLCodec and OracleCodec). This
method is not recommended. The use of the PreparedStatement interface
is the preferred approach. However, if for some reason this is
impossible, then this method is provided as a weaker alternative. The
best approach is to make sure any single-quotes are double-quoted.
Another possible approach is to use the {escape} syntax described in
the JDBC specification in section 1.5.6. However, this syntax does not
work with all drivers, and requires modification of all queries.
Let's check what the encoder is doing to see why your code have an injection vulnerability. The encoder calls encodeCharacter in the oracle codec which simply replaces single quotes with two single quotes:
public String encodeCharacter( char[] immune, Character c ) {
if ( c.charValue() == '\'' )
return "\'\'";
return ""+c;
}
This only makes sense if the value is inside single quotes, which string values would be. If id is actually an integer and you wanted to concatenate it with the query, then you would convert it to an int type first instead of using this encoder.

Related

SQL injection protection in Expression

I am trying to make my queries SQL injection proof. I am using couchbase expression to build the query with user input
private GroupByPath getSearchStatement(SearchParams searchParams) {
String bucketName = asyncBucket.name();
Expression expression = x("sample_id").eq(s(searchParams.getSampleId()));
String selectStatement = bucketName + ".*";
return select(selectStatement)
.from(bucketName)
.where(expression);
}
Is this code SQL injection safe? Or I have to do anything extra.
The code looks good enough to prevent sql injection. Parameterized queries should be another way to do it and more flexible for prepared queries.
A simple example would be
N1qlQuery.parameterized("select * from myBucket where sample_id = $1", JsonArray.from(searchParams.getSampleId()));
It can be either positional/named parameters.

IBM Appscan Security Vulnerability SQL injection

I have App scan through which i scan my projects but at statements like
preparedStatement = conn.prepareStatement(sql);
there is SQL.Injection Vulnerability , i am using esapi api for setting the value in prepared statement e.g.
preparedStatement.setString(1 , OracleEncoder.encode(code) );
OracleEncoder is doing This
ESAPI.encoder().encodeForSQL( ORACLE_CODEC,param);
Any idea how can i fix this Vulnerability?
Assuming you are doing static analysis, appscan does not have a mark up for your ESAPI API, you should create a SQLi validator mark up for your encodeForSQL method in appscan. That way the next time you scan, the scan engine will pick up the new mark up and understand the SQLi threat is neutralized by the esapi call.
You don't need to encode bind parameters to preparedStatement,
// preparedStatement.setString(1 , OracleEncoder.encode(code) );
preparedStatement.setString(1 , code );
The relevant part of the PreparedStatement.setString() JavaDoc says,
The driver converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends it to the database.
If you are using ESAPI library function and prepared statement in your code,then you can mark this issues Not an issue.
Prepared statement is one of the mitigation technique to a avoid SQL injection .
preparedStatement = conn.prepareStatement(sql);

how to replace a string value in java

i replace a particular string in a statement like the following
SQL = SQL.replaceAll("CUSTOMER_NUMBER", customer);
this conversion goes as integer but i want to replace this as a string like the following
AND CIMtrek_accountlist_customer_number = '0002538'
but at present it replaces like the following
AND CIMtrek_accountlist_customer_number = 0002538
how to do this in java.
Just get it to output the ' as well as the customer variable
SQL = SQL.replaceAll("CUSTOMER_NUMBER", "'" + customer + "'");
However as #jlordo mentioned in a comment, you should look at using prepared statements which will allow you to inject values into a prepared sql statement.
Though you should be using PreparedStatement if you are running SQL, However if placeholder "CUSTOMER_NUMBER" is under your control, It is better to use String.format. See and example here

using java variable in sql statement

I'm trying to build a web page to better learn Java and SQL. My question is, is there a way in Java to make a generic SQL select statement? For example:
SELECT var1 FROM var2 WHERE var3=var4
or something of the sort.
My idea is to fill the vars with user selected items from the web page. I know this can be done in PHP using the Post method, but I'm not using PHP. Also, I've read about the Prepared Statement in Java, but seems only to work when the used after the comparison operator; ex:
SELECT * FROM table Where attr = ? &
Also, I do know i can do the hard coded version of "SELECT " + var1 + "FROM " + var2 + "WHERE attr = " + var3 + " " but that doesn't seem very generic and prone to a lot of errors.
Incase: I'm trying to build this test page using HTML & JSP.
What you are doing with the ? is parameterizing the query. The query can only be parameterized for values not names of tables or columns.
Every time you run a query. The database has to create a query plan. If you are running the same query again and again, you can reduce this overhead by creating a PreparedStatement.
The first execution of PreparedStatement will generate the query plan. The subsequent executions will reuse the same plan.
Same query here means, it is identical in all respects except values used in where clause, expressions etc.
If you change the Column or Table name or modify the structure of the query, then it is a different query and will require a different query plan. A PreparedStement is not useful in this case and you should stick to the hardcoded version you talked about. Because of this reason you will get an error if you try to parameterize Table or Column names in PreparedStement.
Having said that. It is not advisable to take such a generic approach for queries. If your queries are that simple, you can benefit from ORM tools. You would not have to maintain even a line of SQL. For complex queries you have an option of using ORM specific query language or JPQL or Native SQL. Look for JPA + Hibernate
Your specific usage is not permitted by JDBC. You need to hard code the table name when creating the prepared statement. If you really do want to do that I suggest you use String concatenation to create the SQL statements and then create a PreparedStatement with parameters to handle the where part. In case you are wondering why bother with PreparedStatements in the specific solution, it's to avoid SQL injection.
You can use PreparedStatement to achive your objective.
For example -
String query = "SELECT * FROM table Where attr = ?";
PreparedStatement pt = con.prepareStatement(query);
pt.setString(1, attribete);
pt.executeUpdate();
There is no such direct provision in any of SQL packaged classes or others to replace table, column names along with query parameter values, in a query string, using a single method.
You require to depend on both PreparedStatement and any of String methods replace(...) and replaceFirst(...) to achieve your requirement.
String sql = "Select $1, $2 from $3 where $4=? and $5=?";
sql = sql.replaceFirst( "$1", "col1_name" );
sql = sql.replaceFirst( "$2", "col2_name" );
sql = sql.replaceFirst( "$3", "table_name" );
sql = sql.replaceFirst( "$4", "col4_name" );
sql = sql.replaceFirst( "$5", "col5_name" );
// .. and so on
PreparedStatement pst = con.prepareStatement( sql );
// use relevant set methods to set the query parametrs.
pst.setXXX( 1, value_for_first_query_parameter ); // from a variable or literal
pst.setXXX( 2, value_for_second_query_parameter); // from a variable or literal
// ... and so on
If you are using JDBC, can try this
PreparedStatement statement = connection.prepareStatement("SELECT ? FROM ? WHERE ?=? ");
then
statement.setString(1, "column_name");
statement.setString(2, "table_name");
statement.setString(3, "column_name");
statement.setBigDecimal(4, 123);
If you are using other ORM like Hibernate or JPA, I believe there are also ways to do.

Standard library to escape strings (without prepared statements)

I'm searching for a Java standard library to escape strings before using them in a SQL statement. This is mainly to prevent errors and to prevent SQL injection, too.
Unfortunately, I will not be able to use prepared statements as is is suggested in a lot of other threads.
Is there any standard library I can use?
I've seen StringEscapeUtils at Apache Commons but I really don't know if this is state of the art.
Thank you very much in advance!
This is a non-trivial problem and a critical one because of SQL injection security issues. I would instead consider using SQL ? type arguments instead of escaping. For example, to search for a particular string:
Instead of doing:
SELECT * FROM accounts
WHERE name = 'escapedstring1' AND password = 'escapedstring2'
I'd use:
SELECT * FROM accounts WHERE name = ? AND password = ?
You will then need to pass in the injected strings (without any escaping needed) as arguments to your SQL methods. Here's how to do it using JDBC. Not sure if that would apply to you.
Something like:
String statement = "SELECT * FROM accounts WHERE name = ? AND password = ?";
try {
PreparedStatement stmt = databaseConnection.prepareStatement(updateString);
// notice that it is 1 based, not 0 (ick)
stmt.setString(1, name);
stmt.setString(2, password);
ResultSet results = stmt.executeQuery();
Here's how ORMLite, my ORM library, does it as an example using a select argument.
Hope this helps.
You can use Apache Commons, it's the very mature project.

Categories

Resources