I use Spring + Hibernate.
In one part I have native sql like:
SELECT *
FROM (...) sel
WHERE %s
%s i receive from UI. It looks like "id = ?1 AND name = ?2..." + list of params.
It is generated by query builder;
And now i have a case when UI can send something like:
CLAUSE: id = 'id; TRUNCATE TABLE schema.foo;'
How to check that clause is not a query?
Where can i find some libraries?
I would take an other direction : rather than trying to detect if a query is malicious, make sure that the query cannot do anything malicous, with grants at database level :
if you have a public table, with users generating queries for this table, create a database user that can only SELECT on this sole table, and use a specific jdbc connection, that connect to the database using the former read-only user, to run these 'unsafe' queries.
I want to list all table names from database. My application has to be independent from DBMS. Different DBMS has different command to list tables, e.g:
PstgreSQL:
SELECT * FROM pg_catalog.pg_tables
MySQL:
show tables
Oracle:
SELECT DISTINCT OBJECT_NAME
FROM DBA_OBJECTS
WHERE OBJECT_TYPE = 'TABLE'
I think that I should use hibernate because writing different SQL query for all DBMS is uncomfortable.
There are examples in network how to list tables in hibernate, but all examples which I found list only mapped entitites. I want to list all table names regardless of hibernate entities.
This post explains how to do it using JDBC driver, which is IMHO a better approach then using hibernate for this. I'll post the code here also, for reference
Connection conn = DriverManager.getConnection("", "", "");
DatabaseMetaData md = conn.getMetaData();
ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
System.out.println(rs.getString(3)); // 3rd column is table name
}
The way Hibernate makes HQL/JPQL queries and expressions cross-platform is by using dialects. There's a dialect for each of the supported database.
To the best of my knowledge, listing tables is not a part of these dialects therefore what you want is most probably not possible OOTB.
But you can write your own dialects for your target databases. So you'd have a cross-database *QL in your application and database specifics would be cleanly abstracted into dialects.
As I read in a lot of articles, when I use JPA/Hibernate query it is good to set parameters in my queries so SQL injection is avoided. Like:
select user from User user where user.name = :name and user.surname = :surname
My problem is that in some cases I need to use native query when I create my query.
I will use my entity manager and createNativeQuery. But in this case the parameters will be positional. Like:
select * from users where user_name = ? and user_surname = ?
Then in my query I will use the method setParameter(1, "name") etc. So is this case "sql injection proof" like when in the parameterized query?
if you do not use string operations for building your query like
"SELECT foo FROM bar Where id="+myParameter+" more sql ..."
, then you will not have any vulnerabilities.
Currently (community correct me if I am wrong) no vulnerabilities exist within the latest PDO database abstraction layer.
However testing your queries for known and unknowns while sanitizing and filtering input will help eliminate the possibility of an injection in the event of a zero day exploit.
I currently use a combination of filtering input, charset expectations, stored procedures and strict requirements on their arguments prior to any and all dynamically created queries
May I know how can I get the sql from a JPA query? or let's say, convert the JPA query to a SQL string? Thank you very much!
For Eclipselink: you can extract the SQL the following way:
query.unwrap(EJBQueryImpl.class).getDatabaseQuery().getSQLString()
It works only after the query has been executed.
If you only want to know how your JPQL or Criteria Query gets translated to the SQL dialect of your database you can enable fine grained logging in the persistence xml and then look into your log files.
The property name and value depends on your JPA implementation. Here is an example of the relevant part of persistence.xml for EclipseLink:
<properties>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
JPA Specification
While there is not standard JPA functionality to achieve this goal, you can still extract the SQL query from a JPQL or Criteria API Query using the JPA provider-specific API.
Hibernate Types
Starting with the 2.9.11 version, the Hibernate Types open-source project offers the SQLExtractor utility that allows you to get the SQL query from any JPQL or Criteria API query, no matter you are using Hibernate 5.4, 5.3, 5.2, 5.1, 5.0, 4.3, 4.2, or 4.1.
Get the SQL statement from a JPQL Query
Let's assume we have the following JPQL query:
Query jpql = entityManager.createQuery("""
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
""", Tuple.class
);
With Hibernate Types, extracting the Hibernate-generated SQL query is as simple as that:
String sql = SQLExtractor.from(jpql);
And, if we log the extracted SQL query:
LOGGER.info("""
The JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
We get the following output:
- The JPQL query: [
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
]
generates the following SQL query: [
SELECT
extract(YEAR FROM sqlextract0_.created_on) AS col_0_0_,
count(sqlextract0_.id) AS col_1_0_
FROM
post p
GROUP BY
extract(YEAR FROM p.created_on)
]
Notice that we unwrapped the JPA Query to the Hibernate org.hibernate.query.Query interface which provided the getQueryString method we can use to log the associated JPQL query string.
Get the SQL statement from a JPA Criteria API Query
The SQLExtractor is not limited to JPQL queries. You can use it with Criteria API queries as well, as illustrated by the following example:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PostComment> criteria = builder.createQuery(PostComment.class);
Root<PostComment> postComment = criteria.from(PostComment.class);
Join<PostComment, Post> post = postComment.join("post");
criteria.where(
builder.like(post.get("title"), "%Java%")
);
criteria.orderBy(
builder.asc(postComment.get("id"))
);
Query criteriaQuery = entityManager.createQuery(criteria);
String sql = SQLExtractor.from(criteriaQuery);
assertNotNull(sql);
LOGGER.info("""
The Criteria API, compiled to this JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
When running the above test case, we get the following SQL query:
- The Criteria API, compiled to this JPQL query: [
select
pc
from
PostComment as pc
inner join
pc.post as p
where
p.title like :param0
order by
pc.id asc
]
generates the following SQL query: [
SELECT
pc.id AS id1_1_,
pc.post_id AS post_id3_1_,
pc.review AS review2_1_
FROM
post_comment pc
INNER JOIN
post p ON pc.post_id=p.id
WHERE
p.title LIKE ?
ORDER BY
pc.id ASC
]
The Criteria API is first compiled to a JPQL query, as illustrated by the getQueryString() method call.
The intermediary JPQL query is further translated to an SQL query, which is properly resolved by the SQLExtractor utility.
Following Karol's answer - It is possible to retrieve the SQL before executing the statement in EclipseLink :
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();
String bound = databaseQuery.getTranslatedSQLString(session, r);
String sqlString = databaseQuery.getSQLString();
To retrieve the SQL String During/After execution it is probably best to do so using persistence properties rather than in-code :
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.logging.level" value="FINE"/>
Beside enabling the logging like #Matt Handy mentioned it is also possible to get the SQL String for a specific query with eclipselink at runtime as described here.
Using Hibernate as a provider you can enable the following properties:
hibernate.show_sql
Write all SQL statements to console. This is an alternative to setting the log category org.hibernate.SQL to debug. (e.g. true | false)
hibernate.format_sql
Pretty print the SQL in the log and console. (e.g. true | false)
Or, as stated above you can enable logging to the debug level for the logger
org.hibernate.SQL
Log all SQL DML statements as they are executed
You are probably interested if there's a way to 'extract' JPQL string (either with placeholders for params, or final JPQL after params are filled-in) out of javax.persistence.Query (one of it's possible subclasses to be more precise),- in this case it's not possible according to JPA specification contract. However, this hypothetically might be possible by JPA implementation (e.g., NamedQueryImpl could have #toJPQLString(), which you could access via casting), but I doubt about that.
And even if it's possible I don't think it's a good code performing such manipulations. I would suggest finding another design solutions (and for that you could specify what kind of actual problem do you have). E.g., if you are building your queries dynamically, JPA Criteria API could be used for that, and along with 'building' JPA query, you could maintain your internal data structure reflecting the logic of your query.
This blog contains instructions: http://narcanti.keyboardsamurais.de/hibernate-hql-to-sql-translation.html
You could use p6spy. At the following link there are instructions for its operation:
https://p6spy.readthedocs.io/en/latest/install.html
I'm a bit of a NHibernate newbie and Im taking on some code written by another developer. I want to find out how NHibernate converts lambda based criteria into SQL.
I know in Linq to SQL using Lambda expressions on queries means that the whole thing is turned into an expression tree and then into SQL (where possible) by the Linq to SQL provider. This can be seen by doing DataContext.Log = Console.Out.
But what about an NHibernate criteria expression where Linq to NHibernate isnt being used?
The following namespaces are imported...
using NHibernate;
using NHibernate.Criterion;
using NHibernate.LambdaExtensions;
.. and the criteria code looks like this...
return Session.CreateCriteria<MyObjectType>()
.Add<MyObjectType>(x => x.Id == id)
.UniqueResult<MyObjectType>();
Will this be turned into an SQL statement e.g.
Select distinct * from table where id = [param]
... or will the whole dataset be pulled into memory giving a List and then have the lambda expressions applied against the objects. e.g.
return List<MyObject>.Where(x => x.id = id) [or something similar].
I', not sure if my importing NHibernate.LambdaExtensions provides a sort of translation into SQL.
It is turned to an HQL statement first (enable logging and look at the console for the statements) and then to an SQL and sent to the database.
It does not select the whole table to memory and filters there.