I just stumbled upon some SQL code of a colleague (we have a "dont fix it, if it aint broke policy"), for a login process.
The name variable is delivered by an input field from a JSP.
//BAD CODING ALERT: DONT USE THIS CRAPPY CODE, YOU NAUGHTY COPY PASTERS!
Query q = em.createQuery("select object(u) from User as u where u.name = '" + name + "'");
With no sanitation at all on the name variable except of server side validating on some Illegal characters: <>"'%;() (mind that that is single and double quotes)
Can this be exploited? And if yes, how so?
If it wasnt for the single and double quotes, one could do something like: blah' OR 'x'='x
You should NEVER EVER create query by string concatenation. use query.setParameter("paramName",paramValue);
so it would be something like that
Query q = em.createQuery("select object(u) from User as u where u.name =:name");
q.setParameter("name", "O'Reilly")
no SQLInjections possible because of escaping values;
Answering my own question... it is safe, however not practical as allready stated by myself.
Before downvoting this, READ the question. Or give an exploit example otherwise.
Related
ps = (PreparedStatement) connection.prepareStatement(
"SELECT nm.id, nid.key, nm.name, nm.languageCode FROM odds.name as nm JOIN (odds.name_id as nid)\r\n"
+ "ON (nm.id = nid.id) where nm.name like '%' and nid.key not like \"vhc%\" and nid.key not like \"vdr%\" and nid.key not like \"vto%\" and nid.key not like \"vbl%\"\r\n"
+ "and nid.key not like \"vf%\" and nid.key not like \"vfl%\" and nid.key not like \"vsm%\" and nid.key not like \"rgs%\"\r\n"
+ "and nid.key not like \"srrgs%\" and nm.typeId=8 and nm.sourceId=-1 and nm.languageCode = 'en'");
for(Entry <String, Tag> e : allTags.entrySet()) {
ResultSet rs = ps.executeQuery();
while(rs.next()) {
if(rs.getString("name").equals(e.getValue().getTranslation(Language.EN))) {
e.getValue().setAlternativeKey(rs.getString("name"));
break;
}
}
}
);
Do you have any Ideas how I can do this a way faster. I'll try to find a string in the database and add an extra information to my object. But I have to do this for 1265 objects, so the program runs about 80 seconds.
Thanks in advance!
First of all, when tackling performance problems, get yourself a profiling tool that tells you where you're spending the time, how often a given method is called and so on.
But I think the case is clear enough to give some more specific hints.
You're executing your PreparedStatement over and over again, once for every entry in allTags.entrySet(), always giving you the same results, and inside in software you filter out the lines you're interested in. So you're doing the same query 1265 times, correct?
And it's puzzling me what you're doing inside the while(rs.next()) loop. Effectively, your code does (after introducing some local variables, moving constant values out of loops, ...):
for(Entry <String, Tag> e : allTags.entrySet()) {
Tag tag = e.getValue();
String translation = tag.getTranslation(Language.EN);
ResultSet rs = ps.executeQuery();
while(rs.next()) {
if(rs.getString("name").equals(translation)) {
tag.setAlternativeKey(translation);
break;
}
}
}
So, the only role of the query result seems to be to decide whether the alternative key should be set (if the translation of your Tag shows up as name in the ResultSet) - the value is already fixed by the result of the method call getTranslation(Language.EN), independent of any database result.
I'd suggest to do one execution of your query, collecting the name values in a HashSet names, and after that do the allTags loop setting the translation if the translation is contained in your names set. That should give the same result as your code, and probably much faster.
Open the DB-client of your choice (e.g. HeidiSQL) and do an
explain [the select statement that is originally executed]
That way MySQL explains to you what it's doing when trying to create the result and where time gets lost.
From there you can go on e.g. creating indizes or changing your query to make use of existing ones.
BTW:
nm.name like '%'
looks strange. Is that a variant of
is not null
The latter might be faster. If the texts in the other like-statements are always the same, a better performance might be achieved by checking these conditions when inserting the data, add columns of type int or boolean and save the result of this check as integer/boolean in addition to the text itself. Checking against a fixed numeric value is way faster than text searches.
I'm trying to print a list (of only 1 item) but my JPQL statement isn't working due to quotations. I've tried every combination possible it seems but none will work. If anyone has any suggestions or different approaches I'd appreciate it. Note: I found a somewhat similar question on the site before I posted this but the answers aren't working for my case. Thanks
String submittedName=request.getParameter("name");
user=entityManager.find(user.getClass(),submittedName);
Query myQuery=entityManager.createQuery
("SELECT u.password FROM UserData u WHERE u.name=''"+submittedName+"");
List results=myQuery.getResultList();
String convertedResults=results.get(0).toString();
out.println(results);
To summarize what Dennis and Rob are trying to say:
String submittedName=request.getParameter("name");
user=entityManager.find(user.getClass(),submittedName);
Query myQuery=entityManager.createQuery("SELECT u.password FROM UserData u WHERE u.name=:name");
myQuery.setParameter("name", submittedName);
List results=myQuery.getResultList();
String convertedResults=results.get(0).toString();
out.println(results);
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 %
Hello guys I am having some problems with exact matches while doing a NamedQuery.
I am currently using something like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from Entry e where e.name =:"+ Entry.NAME )
...
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName());
It works for most cases, however I noticed that in case the user pass the file name with an space at the end, the namedQuery ignores that character. For example:
Query query = em.createNamedQuery(MyClass.GET_ENTRY_BY_NAME);
query.setParameter(Entry.NAME, myEntry.getName()+ " ");
Will return the same result as the query before. Bypassing my 'valid entry' validation. In other words I'd like the query to return no entry at all and treat the error later on.
One workaround I could think of, is to put single quotes surrounding my parameter in the namedQuery, like this:
#NamedQuery(name = MyClass.GET_ENTRY_BY_NAME, query = "select e from entry e where e.name =':"+ Entry.NAME "'")
However it will trash my code in case the String contains single quotes in it...
Any ideas guys?
I guess this happens because your database field is declared as CHAR(...), and therefore stored values are padded with whitespaces which are not taken into account by = operation.
So, you may either declare your database field as VARCHAR(...) or use a built-in trim function:
query = "select e from Entry e where trim(trailing from e.name) =:"+ Entry.NAME
I did some research in JPA and found out that it does some automatic trimming for CHARs, I am not sure if this behaves the same with Strings, but since it is happening to me... I believe so. The only way to bypass it is by setting some attribute within the session DatabaseLogin object (see http://www.eclipse.org/eclipselink/api/1.1/org/eclipse/persistence/sessions/DatabaseLogin.html#setShouldTrimStrings) .
Well I didn't want to be messing up with the session properties so I decided to make some sort of check and throwing the same exception as the NoResultException catch does in my code.
I basically took the result from the database and compared the field with the String I used:
query.setParameter(Entry.NAME, myEntry.getName());
...
if(!StringUtils.equals(result.getName(), myEntry.getName()){
do a cool throw just like NoResultException Catch
}
I also had to include the Trim function axtavt! This is just to make sure that if the database has a column with trailing spaces and it matches the parameter given by the user, it will be included as a valid answer. For example:
Database entry: Name = "Flavio " - Trimmed with Function = "Flavio".
Parameter passed: Name = "Flavio " - Trimmed by JPA automatic function = "Flavio".
If it isnt trimmed at all it will just Compare "Flavio " with "Flavio", returning NoResult when it was supposed to return that Entry.
Nasty workaround, but as long as there is no other way to stop the auto-trimming we will have to just make use of this sort of things.
Thanks for all the other answers!!
I'm having problems with ldap search filters.
I want to search through all the children of a root node. I want the users where the username of the email contains the query string.
for example, if I have
foo_l.c_bar#foobar.com
foobar#foo_l.c_bar
and the search query is "l.c" I want only foo_l.c_bar#foobar.com
the following code, surprisingly, returns either the first and the second.
String query = "...";
DirContext dc = ...;
NamingEnumeration<SearchResult> ne = dc.search(root,
"(email=*{0}*#*)",
new Object[] { query }, null);
what's wrong in the "*...*#*" query filter?
I cannot give you a full answer, but if you try a ldapsearch from command line with the filter "(email=*l.c*#*)", you should get the right records ... so I would say the problem is in the Java method and not in the filter.
Hope it could help you.
I assume you forgot to paste the code that formatted your query and its {0} parameter ?
edit: wow, forget me, I didn't even know about the method that takes the filterArgs array.
As a side note, the standard attribute for e-mail address in inetOrgPerson is "mail" not "email" (but it might be different on your case of course)