Before you begin
Since ORM architecture isn't obvious, this document will explain some important things you need to know in order to analyze a Hibernate application in a security context. This document assumes some SQL and database knowledge.
A note about SQL injection
Since it is the hot topic, I will address it now but discuss in detail later.
- Hibernate does not grant immunity to SQL Injection, one can misuse the api as they please.
- There is nothing special about HQL (Hibernates subset of SQL) that makes it any more or less susceptible.
- Functions such as createQuery(String query) and createSQLQuery(String query) create a Query object that will be executed when the call to commit() is made. If the query string is tainted you have sql injection. The details of these functions are covered later.
The problem Hibernate addresses
In object oriented systems, we represent entities as objects, and use a database to persist those objects. Generally these objects are considered non-scalar values (non-primitive types). But many databases can only store and manipulate scalar values organized in tables. The crux of the problem is translating those objects to forms which can be stored in the database, and which can later be retrieved easily, while preserving the properties of the objects and their relationships; these objects are then said to be persistent. Hibernate attempts to address this problem with Object/Relational Mapping (O/R M) by mapping attributes of objects we wish to persist to columns of a database.
How it works
- Usually Hibernate applications use JavaBeans style POJOs to represent objects we want to persist in a database.
- These objects should have an identifier property (i.e private class variable) used to represent it's primary key value in the database.
- This identifier will be mapped in a hibernate mapping file, usually with the default extension .hbm.xml, you will see this mapping in the <id> element. This file will also map all other object properties we wish to preserve to columns in a database table, along with their data types and other stuff.
- Once objects are mapped, Hibernate provides the mechanism for you to store and access them via org.hibernate.Session and org.hibernate.Transaction objects.
- The Session object has methods to save() objects to a session, load() objects from a database and createQuery()s to be executed against the database.
- The Transaction object often wraps a database transaction, allowing one to begin() transactions, commit() changes, and rollback() to a previous state.
- Other classes worth mentioning: SessionFactory, TransactionFactory, and Query.
- Hibernate's main configuration file, extension .cfg.xml, provides basic setup for things like datasource, dialect, mapping files, etc.
- Transient - The instance is not associated with a Session, has no persistent representation in the database and no identifier assigned. An object that has just been instantiated with the new operator is said to be transient.
- Persistent - Is associated with a Session, has a representation in the database and has been assigned an identifier. Hibernate synchronizes changes on a persistent object with its representation in the database when it completes a unit of work.
- Detatched - was once in a persistent state, but its session has been closed. The reference is still valid and the object may be modified and even reattached to a new session later.
Hitting the database
The Session object represents the main interface or conversation between Java and Hibernate. A Session is used for a single request, or unit of work. To make an object persistent, it must first be associated with a Session.
But where does the session come from? Hibernate's Configuration object instantiates a SessionFactory (Configuration.buildSessionFactory()) which is an expensive, immutable, thread safe object intended to be shared by all application threads. Threads that service client requests must obtain a Session from the factory by calling SessionFactory.getCurrentSession() or SessionFactory.openSession().
Anyways, a Session is NOT thread safe and there are associated concurrency issues discussed in this section of the Hibernate Guidelines page. Once an object is associated with a Session we can begin a transaction. All database communication must occur within the scope of a transaction. A transaction starts with a call to Transaction.begin() or Session.beginTransaction() and ends with a call to Transaction.commit().
To actually build queries, store and retrieve data we mostly use methods in the Session class. For example, load() will instantiate a class object, and load the state from the database into the instance. Session.createQuery() will return a Query object which has many methods with which to operate on this query string. Query.setParameter(), setFloat(), and others act similar to prepared statements. You can also simply call Query.executeUpdate() to execute the query.