Yesterday searching through some repositories on Github I found some interesting stuff: one Java project (I won't mention the name of the repository but I've already notified the owner of it) contained a bad handling of HQL queries which could lead to SQL/HQL injections. The code was the following: (note that username and password come from the user)
Query query = session.createQuery("from Client where username = '" + username + "'");
List clients = query.list();
Client client = (Client) clients.get(0);
if (!validPassword(client.getPassword(), password)) {
return false;
}
//client is authenticated....
I think it is obvious that this query is injectable. I don't really know how this vulnerable query could be exploited because even if we inject the username, the
password is still checked. The database used was MySql (if it helps).
So my question is: how could this be exploited?
Even though HQL is more restrictive than SQL for injections, it can still be exploited.
Some example injections are explained at https://blog.h3xstream.com/2014/02/hql-for-pentesters.html
A similar question to this one has been asked already before at https://security.stackexchange.com/questions/24265/hql-injection-example
The answer to this question explains how characters of a password (hash) could be scanned. e.g. if for an Oracle database the value of username is:
admin' AND SUBSTR(password, 0, 1) = 'A
Then if
the first character of the password (hash) is not 'A' -> the clients List is empty and the clients.get(0) method call throws an IndexOutOfBoundsException
the first character of the password (hash) is 'A', but the provided password is false -> the user is not authenticated
the first character of the password (hash) is 'A' and the provided password is correct -> the user is authenticated
A hacker can repeat the query for each x and z in
SUBSTR(password, x, x + 1) = z
in the query above until the outcome is always case 2. where the user is not authenticated. This way he can find out the password hash for the user admin and may be able to crack his password.
Other exploits are possible, I am not going to list all of them...
Yes so...once you had start hibernate session, You can fetch data using query. Now you have written query for Client table.
For ex,
username = "ABC"
1) Your query from Client where username = 'ABC' will fetch data from Client whoes username is exact ABC.
If it found multiple same Username, it also return all.
2) It is going to store in list. 0 or more record will store in list.
3) Then whatever records came, it fetch only first record using
Client client = (Client) clients.get(0);
4) it check with client object record password with your expected password that may be suppose to save in some variable via method calling.
5) if it won't match then it return with false boolean flag otherwise code will go ahead with authenticated client execution.
Hope you got your answer.
Related
Sonarqube is giving me this error:
[BLOCKER] Change this code to not construct SQL queries directly from user-controlled data
Here is my code:
String countSQL;
countSQL = (String.format("SELECT count(*) as total FROM ltid_owner.enty %s",additionalWhereClauses));
jdbcTemplateTMI.queryForObject(countSQL, Integer.class);
In the above code additionalWhereClauses could be something like this shown below which I am building on the fly when the user clicks on the grid to perform filtering on different columns:
additionalWhereClauses = where UPPER(enty_num) like '003%'
Can you please let me know how to resolve this issue?
Your code combines strings into SQL statements. If any of these strings contains user provided input, an attacker can sneak in code to trigger an SQL injection attack and possibly run arbitrary code on your computer (obligatory Bobby Tables reference).
Simple example:
String sql = "SELECT * FROM users WHERE name = '" + name + "' AND password = '" + password + "'";
If I enter ' OR 1=1 -- for the name (and "..." for the password, but that doesn't really matter anymore) the code becomes a valid SQL statement:
SELECT *
FROM users
WHERE name = '' OR 1=1 -- ' AND password = '...'
but the user name / password check is completely disabled.
To avoid this, use prepared statements. They build the SQL command in a way that SQL injection is impossible.
Maybe this never happens in your code as you don't accept user input, but Sonar doesn't know this (and human reviewers won't either). I'd always use prepared statements. Just because your code only passed column headers from a frontend, doesn't mean an attacker cannot manually call your web service endpoints and pass whatever they want, it your code runs as an HTTP endpoint.
I have a requirement. The technology is quite old doesn't support spring at all . It is pure java application with jdbc connection.
Requirement is :
Suppose
select * from employee where empid = <<empid>> and designation = 'Doctor'
I am trying to replace <> with actual int value in java . How I can do it ?
String query = "select * from employee where empid = <<empid>> and designation = 'Doctor'";
if(query.contains("<<empid>>"))
/// Here I want to replace <<empid>> with actual int value in java
Any leads will be helpful
The code you didn't paste, that actually executes the SQL is either [A] a massive security leak that needs serious rewrites, or [B] is using PreparedStatement.
Here's the problem: SQL injection. Creating the SQL string by mixing a template or a bunch of string constants together with a bunch of user input is a security leak. For example, if you try to make SELECT * FROM users WHERE email = 'foo#bar.com' by e.g. String sql = "SELECT * FROM users WHERE email = '" + email + "'";, the problem is, what if the user puts in the web form, in the 'email' field: whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --? Then the SQL becomes:
SELECT * FROM users WHERE email = 'whatever#foo.com'; DROP TABLE users CASCADE; EXEC 'FORMAT C: /y /force'; --';
That is legal SQL and you really, really, really don't want your DB engine to execute it.
Each DB engine has its own ideas on what's actually legal, and may do crazy things such as treating curly quotes as real quotes, etc. So, there is no feasible blacklist or whitelist technology you can think of that will properly cover all the bases: You need to ask your DB engine to do this for you, you can't fix this hole yourself.
Java supports this, via java.sql.PreparedStatement. You instead always pass a fully constant SQL string to the engine, and then fill in the blanks, so to speak:
PreparedStatement ps = con.prepareStatement("SELECT * FROM users WHERE email = ?");
ps.setString(1, "foo#whatever.com");
ps.query();
That's how you do it (and add try-with-resources just like you should already be doing here; statements and resultsets are resources you must always close). Even if you call .setString(1, "foo#whatever.com'; DROP TABLE users CASCADE; --"), then it'll simply look for a row in the database that has that mouthful in the email field. It will not delete the entire users table. Security hole eliminated (and this is the only feasible way to eliminate it).
So, check out that code. Is it using preparedstatement? In that case, well, one way or another that code needs to be calling:
ps.setInt(1, 999);
Where ps is the PreparedStatement object created with connection.prepareStatement(...) where ... is either an SQL constant or at least your input string where the <<empid>> was replaced with a question mark and never with any string input from an untrusted source. The 1 in ps.setInt(1, 999) is the position of the question mark (1 = the first question becomes 999), and the 999 is your actual number. It may look like:
if (input instanceof String) {
ps.setString(idx++, (String) input);
} else if (input instanceof Integer) {
ps.setInt(idx++, ((Integer) input).intValue());
} ...
etcetera. If you don't see that, find the setInt invoke and figure out how to get there. If you don't see any setInt, then what you want is not possible without making some updates to this code.
If you don't even see PreparedStatement anywhere in the code, oh dear! Take that server offline right now, research if a security leak has occurred, if this server stored european data you have 72 hours to notify all users if it has or you can't reasonably figure out e.g. by inspecting logs that it hasn't, or you're in breach of the GDPR. Then rewrite that part using PreparedStatement to solve the problem.
As part of a Secure Code course I am given a vulnerable Java system, where queries are built up using string concatintion, and so on. Following is the respective code line that I have to SQL inject to retrieve log-in data:
String comment;
int articleID;
//...
stmt.executeUpdate("INSERT INTO comment (text, article_id) VALUES ('" + comment + "', " + articleId + ")");
comment can be set to any text, it is just read plain-text from a textbox. Therefore, I thought about setting the textbox text to an SELECT statement, reading the complete login data (table user has columns login and password):
' || (SELECT login || password FROM user) || '
which in overall should result in the query
INSERT INTO comment (text, article_id) VALUES ('' || (SELECT login || password FROM user) || '', 4)
yet, this results in
org.hsqldb.HsqlException: cardinality violation
Question:
I assume this is because (SELECT login || password FROM user) is not a single string, but a result set, and may therefore not be concatenated using ||.
Is it possible to convert the complete result set to one string in a way it can be used in this SQL injection scenario (in standard SQL / SQL that works on HSQLDB)?
You are correct, as there is obviously more than one user and multiple rows are returned from the SELECT.
You can add LIMIT 1 to the SELECT to get the first row. You can also create a string array from the inner SELECT. See the guide.
In HSQLDB each database user has separate access rights to the tables. In a real deployment the user that inserts comments will not even see the existence of the table that contains the password, let alone select from it.
I'm new to connecting Java to SQL Server but hopefully I manage to connect them successfully through helps of various tutorials. But there are these methods and syntax that I couldn't explain for myself.
1.
Connection conn=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=login_DB;integratedSecurity=true");
Regarding the code above, what does integratedSecurity=true do?
2.
String user = rss.getString(1);
String pass = rss.getString(2);
Does the parameter inside getString(1) and getString(2) pertains to the column in the Database? And also, how does the ResultSet affects the getString()?
3.
while(rss.next()){
String user = rss.getString(1);
String pass = rss.getString(2);
if(usernameTF.getText().trim().equals(user)&&passwordTF.getText().trim().equals( pass)){
count = 1;
}//if success
}//while
Lastly, at least for now, does the while(rss.next()) method simply means that while there is a row in my table?
I know my code is a bad practice. But I am really trying my best to make it better.
Integrated Security = true/SSPI : the current Windows account credentials are used for authentication.
Integrated Security = False : User ID and Password are specified in the connection String.
rs.getString(1) - get 1 return column from your select statement.
Select x,y,z from table; rs.getString(1) gives x column result for particular row.
Your query returning n number row ,each time rs.next() check is there row available after current row.
Difference between Integrated Security = True and Integrated Security = SSPI
Yes the number refers to the column number, or you can pass a String as the column name to pull data.
Yes, whilst there is data in your ResultSet, for each iteration it will move the cursor to the next row of data available. Where you can access columns specifically using the syntax from part 2 of your question.
Hope this is useful.
According to Microsoft they are the same thing.
When false, User ID and Password are specified in the connection. When true, the current Windows account credentials are used for authentication.
Recognized values are true, false, yes, no, and sspi (strongly recommended), which is equivalent to true.
There however is a difference between them according to the comment below:
True ignores User Id and Password if provided and uses those of the running process, SSPI it will use them if provided which is why MS prefers this.
They are equivalent in that they use the same security mechanism to authenticate but that is it.
refer this link...!
I am trying to build a simple login form using Swing in Java. I created a Sample form with two fields.
usernamefield of type TextField
passfield of type PasswordField
Now I have a database and in that a login table which has following structure.
username | password
----------------------
abcd | xyz
Also I created a connection to database. and I am able to access table data by using ResultSet.
I made an object of database connection called conn.
I know that password is stored in the form of char array.
so when I try to match password by using following code it does not work.
if(usernamefield.getText() == conn.username && passfield.getPassword().toString == conn.password) {
system.out.println("Correct");
}else {
system.out.println("Incorrect");
}
Above code always go to else block.
I also noticed that passfield.getPassword() prints the correct password while passfield.getPassword().toString prints some random characters like [C#76dab03c
How to resolve it?
Use equals instead of == and it should work. Never use == on strings, it hardly ever produces the result you expect.
I think the more serious issue with your code is that you're storing passwords in plain text. That is a huge security risk. You should look into password hashing algorithms, for instance bcrypt.
You must compare string with .equals(), not ==, but you're doing this wrong anyway. The password should be hashed at the database, and you should be passing what the user entered to the database and having it do the matching, via a WHERE clause using the appropriate hash function. In other words, ask the database to fetch the user row with this username and password.