Building CosmosDB Query strings with escaping - java

I want to build a cosmosdb sql query, because I'm using a rest interface, which accepts SQL querys (don't ask why, I can't change that :( )...
Now I want to build that query with some parameters, which affects the WHERE clause.
I think it is a good idea to escape these parameters, to prevent sql injection.
But I just found these way to build a query:
var param = new SqlParameter();
param.add("#test", "here some string to inject");
var query = new SqlQuerySpec("SELECT #test FROM table", param);
Now I could do sql calls to the cosmos's without sql injection. But I don't want this. I just want to get the query string.
But I need the full query from "query". But there seems to be just the method query.getQueryText(). But this just returns the string "SELECT #test FROM table".
Do know a workaround for me? Or maybe just a good package I can use to to my own string escapes.
T

I found the information that this escalation stuff doesn't happen on client site. It happens in the dbms. So I need a rest interface, where I can pass the parameters.
Azure Cosmos DB SQL Like, prepared statements

Related

Android: SQL Parameter Evaluator for Realm

I need to translate SQL statement to Realm (to get record stored in Realm based on SQL statement). I just need to handle SELECT statement with SQL parameters and translate it to Realm. For example:
SELECT * FROM tblCustomer WHERE (Name = 'John Doe' OR Name = 'Joe Black') AND (Postcode = '10013')
I need to evaluate anything after WHERE statement so I can filter and return appropriate records. So, from example above, it is translated to Realm like this
realm.where(tblCustomer.class)
.beginGroup()
.equalTo("Name", "John Doe")
.or()
.equalTo("Name", "Joe Black")
.endGroup()
.beginGroup()
.equalTo("Postcode", "10013")
.endGroup();
I have tried to use Dijsktra's algorithm (Evaluate.java) to evaluate the WHERE parameters, but I am having problem with translating spaces.
I am just wondering, does anyone have algorithms ready to evaluate SQL parameters? If yes, I'll just use your algorithm instead of creating one myself.
Thanks.

Couchbase uses wrong indexes with N1QL parameterized queries

I have problems with understanding of way couchbase query plan works.
I use SpringData with Couchbase 4.1 and I provide custom implementation of Couchbase Repository. Inside my custom implememtnation of Couchbase Repository I have below method:
String queryAsString = "SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS FROM MyDatabase WHERE segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1";
JsonObject params = JsonObject.create()
.put(CLASS_VARIABLE, MyClass.class.getCanonicalName())
.put(ID_VARIABLE, segmentId);
N1qlQuery query = N1qlQuery.parameterized(queryAsString, params);
List<MyClass> resultList = couchbaseTemplate.findByN1QL(query, SegmentMembers.class);
return resultList.isEmpty() ? null : resultList.get(0);
In a result, Spring Data produces following json object represented query to Couchbase:
{
"$class":"path/MyClass",
"statement":"SELECT MyDatabase.*, META().id as _ID, META().cas as _CAS from MyDatabase where segmentId = $id AND _class = $class ORDER BY executionTime DESC LIMIT 1",
"id":"6592c16a-c8ae-4a74-bc17-7e18bf73b3f8"
}
And the problem is with performance when I execute it via Java and N1QL Rest Api or via cbq consol. For execute this query in cbq I simply replace parameters reference with exact values.
After adding EXPLAIN clause before select statement I mentioned different execution plans. Execution this query as parameterized query via Java Spring Data or N1QL Rest Api I've mentioned that query doesn't use index that I created exactly for this case. Index definiton can be found below:
CREATE INDEX `testMembers` ON MyDatabase `m`(`_class`,`segmentId`,`executionTime`) WHERE (`_class` = "path/MyClass") USING GSI;
So, when I execute query via cbq consol, Couchbase uses my idnex and query performance is very good. But, when I execute this query via N1QL rest api or Java i see that query doesn't use my index. Below you can find part of execution plan that proves this fact:
"~children": [
{
"#operator": "PrimaryScan",
"index": "#primary",
"keyspace": "CSM",
"namespace": "default",
"using": "gsi"
},
So, the question is that the right and legal behavior of couchbase query optimizer? And does it mean that query plan does not take into account real values of parameters? And have I manually put values into query string or exist eny other way to use N1Ql parameterized query with correct index selection?
EDIT
According to shashi raj answer I add N1qlParams.build().adhoc(false) parameter to parameterized N1QL query. This doesn't solve my problem, because I still have performance problem with this query. Moreover, when I print query I see that it is the same as I described earlier. So, my query still wrong analyzed and cause performance decline.
first of all you need to know how N1QL parameterized queries works query should be passed as:
String query= select * from bucketName where _class=$_class and segmentId=$segmentId LIMIT $limit ;
Now the query should be passed as:
N1QL.parameterized(query,jsonObject,N1qlParams.build().adhoc(false));
where jsonObject will have all the placeholder values.
JsonObject jsonObject=JsonObject.create().put("_class","com.entity,user").put("segmentId","12345").put("limit",100);
N1qlParams.build().adhoc(false) is optional since if you want your query to be optimized it will make use of it. It makes use of LRU where it keeps track of previously query entered and it keeps record of it so that next time it doesn't need to parse query and fetch it from previous what we call as prepared statement.
The only problem is couchbase only keeps record of last 5000 queried.
The problem in your case is caused by the fact that you have an index with 'where' clause WHERE ( _class = "path/MyClass"), and at the same time, you passing the _class as a parameter in your query.
Thus, the query optimizer analyzing the parametrized query has no idea that this query might use an index created for _class = "path/MyClass", cause it's _class = $class in a select's where. Pretty simple, right?
So, don't pass any fields mentioned in your index's 'where' as select parameters. Instead, hardcode _class = "path/MyClass" in your select in the same way you did for create index. And everything should be fine.
Here's the ticket in the couchbase issue tracking system about that.
https://issues.couchbase.com/browse/MB-22185?jql=text%20~%20%22parameters%20does%20not%20use%20index%22

pass a array in querybuilder in statement

I am using a query builder to create a query statement in hibernate. i need to pass a arrayList for in statement. How can this be done.
Dummy code :
List<String> xyz = new ArrayList<String>("sam","tam","vam");
StringBuilder queryBuilder = new StringBuilder("select abc from tem where xyz in :xyzList");
Query query = entityManager.createNativeQuery(queryBuilder.toString());
query.setParameter("xyzList", xyz);
query.getResultList();
this is not working. it throws exceptions. Can somebody point me how to do this.
Use setParameterList("xyzList", new String []{"a","b","c"});
So if you have the list with you, you can do list.toArray() in place of new String []{"a","b","c"}
You have seemed to be mistaken an entityManager.createNativeQuery with entityManager.createNamedQuery or entityManager.createQuery
The syntax of your query is JPQL, but you compile it as a native query syntax
What should work for you is to move from createNativeQuery simply to createQuery, or align it the other way around so write a proper native query if that is your goal.
Note just that if you're intent was to go for a native query you should stay away from the named parameters. In your case it would work since you're using hibernate as persistence provider, but otherwise, named parameters in native queries are not supported according to JPA specification

Does Hibernate's createCriteria() sanitize input?

Came across some code today that uses Hibernate to perform a query. The query uses a value submitted from a form. It made me curious as to whether or not this sort of code "sanitizes" its input.
public List<School> search(String query) {
Session session = this.getCurrentSession();
query = "%" + query + "%";
Criteria criteria = session.createCriteria(getPersistentClass());
criteria.createAlias("country", "a");
Criterion nameCriterion = Restrictions.ilike("name", query);
Criterion cityCriterion = Restrictions.ilike("city", query);
Criterion countryCriterion = Restrictions.ilike("a.name", query);
Criterion criterion = Restrictions.or(Restrictions.or(nameCriterion, cityCriterion), countryCriterion);
criteria.add(criterion);
return criteria.list();
}
Is this safe?
Hibernate Criteria Queries are quiet safe in terms of Sql Injection since they pass strings as parameter while performing any fetch. Even, Hql is quiet safe unless you build the query via string literal.
For more details, you should take a look at queries getting fired at the database level by switching on hibernate sql logging.
If you think to SQL injection attacks, then yes, Hibernate Criteria API is safe.
It will generate the underlying query by first compiling it from the specified query fields and only after apply the query parameters (It should use a classical PreparedStatement). This way the JDBC driver will know which part of the query are fields and which part are parameters. Then the driver will take care to sanitize the parameters.
Tough you should take care with the SQL restrictions applied on the Criteria, if you need to place parameters there. For example
String vulnerable = //parameter from user interface
criteria.add(
Restrictions.sqlRestriction("some sql like + vulnerable") //vulnerable
criteria.add(
Restrictions.sqlRestriction("some sql like ?",
vulnerable, Hibernate.STRING)) //safe
In this case the vulnerable parameter could "leak" in to the query fields part and be bypassed by JDBC driver checking as in a normal vulnerable SQL query.
Hibernate is useful to sanitizing inputs but sanitizing inputs is not considered the best practice for preventing SQL injection attacks. As your code develops over time, you will need to remember to change your Hibernate sanitation as your database and client-side application change; this leaves a lot of room for error and any one mistake can compromise your database.
To prevent SQL injection attacks, it is better to use prepared statements. In a prepared statement, your client-side application will make a non-SQL request and let your server generate your SQL statement.
For example, if a user wants all users in the city "Dallas" then your client-side application should make a request similar to username equals "Dallas" and then your server can generate:
SELECT * FROM users WHERE name='Dallas'

Is it possible to soft code sql statements?

I was told that it is possible to soft code SQL queries instead of hard coding them. Just like we parse JSON responses in Java, we can do that through an external file like below:
abc:[
{
sql:"selecct count(*) from some_database",
count:"100"
}]
Is it possible? How I can do that? Links or articles would be appreciated. I am using Hibernate. How can I run a SQL query through external file in Hibernate?
If you're using Java, try using MyBatis.
SQL statements are placed in a resource XML file and code references the queries by name. This allows you to edit the XML when details of the schema change, possibly without modifying the code that consumes them.
Yes.
for instance in a resource bundle:
ResourceBundle bundle = ResourceBundle.getBundle();
PreparedStatement psmt = connection.prepareStatement(bundle.getString("users.query"));
....
Or any other string for that matter.
Store the SQL statements in variables, or return them from a function if you want to dynamically add variables to the SQL statements themselves.
Wherever you normally put an SQL query as a string, just put the variable, or function call instead.

Categories

Resources