Encoding in Java ESAPI - java

To prevent from SQL injections, OWASP encodes characters received.Below is the code implemented for org.owasp.esapi.codecs.OracleCodec.java class
//Default implementation that should be overridden in specific codecs. Encodes ' to '' Encodes ' to '' (according to doc)
public String encodeCharacter( char[] immune, Character c ) {
if ( c.charValue() == '\'' )
return "\'\'";
return ""+c;
}
How does above help for the prevention of SQL injection?Please explain.

Using the guidelines at OWASP, multiple test cases can be found here.
The snippet of code you're looking at here defends against someone trying to escape out of the query to run their own arbitrary command.
if ( c.charValue() == '\'' )
If the input value is equal to ASCII char value 0x27 (a single quote)
return "\'\'";
Escape the single quote.
Oracle escaping is here.
Lets say your query is "select * from users where id = \'" + request.getParameter("id")
By not escaping single-quotes, an input like this:
request.setParameter("id", "\' OR 1=1;"); would result in returning all the information in that table by changing the final, non-Java formatted query to select * from users where id = '' OR 1=1;
I highly recommend you download the WebGoat program, and follow its lessons. It will teach you how to use SQL injection, and many other basic web attacks. And the ESAPI swingset will help you learn how to mitigate them.

Here explains very well for oracle and others DBMS:
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
But rule n. 1 to prevent SQL injection is not to use query concatenation but instead prepared statements! With prepared statements there is no need to encode any parameter (set by sql api) and there are also DB performance optimizations.

Related

How to add multiline Strings in Java?

How to make long queries more readable?
For example I have this one:
String query = "SELECT CASE WHEN EXISTS (SELECT * FROM users WHERE username = 'username' AND user_password = crypt('password', user_password)) THEN 'match' ELSE 'differ' END";
And it's completely unreadable, are there any ways to beautify it?
Since Java 15, you can use text blocks:
String query = """
SELECT CASE
WHEN
EXISTS (
SELECT *
FROM users
WHERE
username = 'username'
AND user_password = crypt('password', user_password)
)
THEN 'match'
ELSE 'differ'
END
""";
In cases when you don't wont to blend SQL and JAVA you can put SQL queries in an .sql file. And get this text when needed.
public class QueryUtil {
static public String getQuery(String fileName) throws IOException {
Path path = Paths.get("src/test/resources//" + fileName + ".sql");
return Files.readAllLines(path).get(0);
}
}
If you can mix SQL and JAVA then starting from JDK15 you can use text blocks for this.
Also you can generates Java code from your database by using JOOQ, it gives many benefits.
Assuming that you can't move to a newer-than-8 version of Java (or even if you can), by far the best solution is to use an ORM. For Java it pretty much comes down to Hibernate, or jOOQ. jOOQ (and possibly Hibernate, I haven't used it so can't say, sorry) allows you to use a fluent programming interface, which is very much in keeping with existing Java code style and patterns.
Another specific advantage of using an ORM is that you can very easily change which DB engine you use without having to change the Java code that you've written beyond changing the SQL dialect in your setup functions. See https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/SQLDialect.html.
You can use JOOQ and get multiple other benefits like type safety, auto-complete, easy mapping and great support.
Have used it for several projects so far and also competition like Kotlin Exposed but always came back to JOOQ.
Move to Java 13+. There are Text Blocks for this.
Or use some ORM library.

Mockrunner(Java) query with Regex

I am using Mockrunner to mock Sql DB for my unit tests. Following is my query:-
"select * from table where userId in (" + userIds + ")"
Now my userIds is state dependent. I don't need my test cases dependent on the arrangement inside the list - userIds. So I don't need exact match but regex matching. I have already enabled regex matching by below code:-
StatementResultSetHandler statementHandler = connection.getStatementResultSetHandler();
usersResult = statementHandler.createResultSet("users");
statementHandler.setUseRegularExpressions(true);
//How to write this regex query?
statementHandler.prepareResultSet("select * from table where userId in .*", campaignsResult);
But as it is noted, I have no idea about the regex syntax supported by Mockrunner.
Edit: I unable to match queries like "Select * from tables" with "Select * from tab .*". So It has to do something with the way I using regex with Mockrunner
There are some helpful examples available here. For instance:
public void testCorrectSQL() throws Exception {
MockResultSet result = getStatementResultSetHandler().createResultSet();
getStatementResultSetHandler().prepareResultSet("select.*isbn,.*quantity.*", result);
List orderList = new ArrayList();
orderList.add("1234567890");
orderList.add("1111111111");
Bookstore.order(getJDBCMockObjectFactory().getMockConnection(), orderList);
verifySQLStatementExecuted("select.*isbn,.*quantity.*\\(isbn='1234567890'.*or.*isbn='1111111111'\\)");
}
From this, I surmise that it's using standard Java regex syntax. In which case, you probably want:
prepareResultSet("select \\* from table where userId in \\(.*\\)", campaignsResult);
...or perhaps more succinctly (and depending upon exactly how fine-grained your tests need to be):
prepareResultSet("select .* from table where userId in .*", campaignsResult);
The main caveat to be aware of when enabling the regex matching is that any literal special characters that you want in your query (such as *, (, and ) literals) need to be escaped in your regex before it will work properly.

appengine datastore query escaping single quote (')

I have used javax.jdo.Query like here JDO for Google App Engine: escaping quotes. Yet, my query string with single quote (') keep getting exploded.
Query query = pm.newQuery("select from " + Book.class.getName() + " where mArtist== '"+ artist + "' && mTitle=='" + title + "'");
Here is the exception
javax.jdo.JDOUserException: Portion of expression could not be parsed: 't Give Up'
org.datanucleus.store.query.QueryCompilerSyntaxException: Portion of expression could not be parsed: 't Give Up'
Here is this query.toString()
SELECT FROM com.example.Book WHERE mArtist== 'Famous Writer' && mTitle=='We Won''t Give Up'
Yeh, I have even escaped the single quote(') with double single quote per appengine docs
a str literal, as a single-quoted string. Single-quote characters in the string must be escaped as ''. For example: 'Joe''s Diner'
Building a query by string concatenation is almost always a risky thing to do, even when SQL Injection attacks aren't possible. (They aren't with GAE.)
See http://code.google.com/appengine/docs/java/datastore/jdo/queries.html#Introducing_Queries and note the bit on "parameter substitution".
The example code in the document only cover a single parameter substitution. Here is a bit more.
Query query = pm.newQuery(Book.class);
query.setFilter("mArtist == artist && mTitle == title");
query.declareParameters("String artist,String title");
List<Book> list = (List<Book>) query.execute("Famous Writer","We Won't Give Up");
Some SO questions worth reading :
How to dynamically build JDO Queries on multiple parameters
Google Datastore problem with query on *User* type

Java POST data to mySQL UTF-8 encoding issue

I have POST data that contains the Japanese string AKB48 ネ申テレビ シーズン3, defined in jQuery as data.
$("#some_div").load("someurl", { data : "AKB48 ネ申テレビ シーズン3"})
The post data is sent to Java Servlet:
String data = new String(this.request.getParameter("data").getBytes("ISO-8859-1"), "UTF-8");
My program saves it to MySQL, but after the data is saved to the database it becomes:
AKB48 u30CDu7533u30C6u30ECu30D3 u30B7u30FCu30BAu30F33
What should I do if I want to save it as it is in UTF-8? All my files are in UTF-8.
MySQL encoding is utf8 and here is the code
String sql = "INSERT INTO Inventory (uid, item_id, item_data, ctime) VALUES ("
+ inventory.getUid() + ",'"
+ inventory.getItemId() + "','"
+ StringEscapeUtils.escapeJava(inventory.getItemData()) + "',CURRENT_TIMESTAMP)";
Statement stmt = con.createStatement();
int cnt = stmt.executeUpdate(sql);
From your example above, I can verify that the Japanese string is getting saved to your MySQL database correctly, but as escaped Unicode.
I would check these items in order:
Are your tables and columns all set to have a character set and collation for utf8? I.e.,
CHARACTER SET utf8 COLLATE utf8_general_ci
Are explicitly setting the character set encoding before POST? request.setCharacterEncoding("UTF-8");
Are you setting the character encoding for your db connections? I.e., jdbc:mysql://localhost:3306/YOURDB?useUnicode=true&characterEncoding=UTF8
As the others have pointed out, you should not use that getBytes trick. It will surely mess up the POSTed values.
EDIT
Do not use StringEscapeUtils.escapeJava, since that will turn your string into escaped Unicode. That is what is transforming AKB48 ネ申テレビ シーズン3 into AKB48 u30CDu7533u30C6u30ECu30D3 u30B7u30FCu30BAu30F33.
Why you do not just extract value of parameter like this.request.getParameter("data")?
Your data is sent correctly using URL encoding where each unicode character is replaced by its code. Then you have to get the value of the parameter. When you are requesting bytes using ISO-8859-1 you are actually corrupting your data because the string is represented as a sequence if codes in textual form.
Java strings are stored in UTF-16. So, this code:
String data = new String(this.request.getParameter("data").getBytes("ISO-8859-1"), "UTF-8");
decodes a UTF-16 string (which has been re-encoded from UTF-8 in the HTTP protocol) into a binary array using the ISO-8859-1 charset, and re-encodes the binary array using the UTF-8 charset. This is almost certainly not what you want.
What happens when you use this?
String data = this.request.getParameter("data");
System.out.println(data);
If the second line generates bad data, then your problem is likely in jQuery. Determine that you are indeed getting unicode in your jQuery request:
System.out.println(this.request.getHeader("Content-Encoding"));
If it does not generate bad data, but the data doesn't get stored correctly in mySQL, your problem is at the database level. Make sure your column type supports unicode strings.
What's the point of the line
String data = new String(this.request.getParameter("data").getBytes("ISO-8859-1"), "UTF-8");
You're transforming chinese (or at least non-occidental) characters into bytes using the ISO-8859-1 encoding. Of course this can't work, since chinese characters are not supported by the ISO-8859-1 encoding. ANd then you're constructing a new String from bytes that are supposed to represent ISO-8859-1-encoded characters, using the UTF-8 encoding. This, once again, doesn't make any sense. UTF-8 and ISO-8859-1 are not the same thing, and only a small set of chars have the same encoding in both formats.
Just use
String data = this.request.getParameter("data");
and everything should be OK, provided that the column in the MySQL table uses an encoding that supports these characters.
EDIT:
now that you've shown us the code used to insert the data in database, I know where all this comes from (the preceding points are still valid, though). You're doing
StringEscapeUtils.escapeJava(inventory.getItemData())
What's the point? escapeJava is used to take a String and escape special characters in order to make it a valid Java String literal. It has nothing to do with SQL. Use a prepared statement:
String sql = "INSERT INTO Inventory (uid, item_id, item_data, ctime) VALUES (?, ?, ?, CURRENT_TIMESTAMP);
PreparedStatement stmt = con.prepareStatement();
stmt.setInteger(1, inventory.getUid()); // or setLong, depending on the type
stmt.setString(2, inventory.getItemId());
stmt.setString(inventory.getItemData());
int cnt = stmt.executeUpdate();
The PreparedStatement will take care of escaping special SQL characters correctly. They're the best tool agains SQL injection attack, and should always be used when a query has parameters, especially if the parameters come from the end user. See http://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html.

Using LIKE operator in Access works but not in Java

I'm making a java application for a toy store and using the MS-Access database.
I'm using the operator "LIKE" to search for products in database using the user's keyword.
E.g. in Access:
SELECT * FROM tblToy WHERE toyName LIKE '*puppy*' OR toyBrand LIKE '*puppy*'
this gives me the desired result in access.
But in java when i run this same query it returns null:
String query = "puppy";
sql = "SELECT * FROM tblToy WHERE toyName LIKE '*" + query+"*' "+
"OR toyBrand LIKE '*" + query + "*'";
rs = db.executeQuery(sql);
while(rs.next()){
String name = rs.getString("toyName");
return name;
}
return null;
Can anyone help me on this? I know it must be something simple which I'm missing out now but I just don't know what to do. Would appreciate your guys help.
I think with Java, you need to escape single quotes, so try using \' for all your single quotes, then try % instead of * as someone else mentioned, since % is the wildcard for SQL.
There are two possibilities for wildcards according to where you are running the query, * or %. In this case, you need %

Categories

Resources