This site is the archived OWASP Foundation Wiki and is no longer accepting Account Requests.
To view the new OWASP Foundation website, please visit https://owasp.org

Hibernate

From OWASP
Revision as of 17:23, 5 June 2008 by Tehmina (talk | contribs) (Security Implications)

Jump to: navigation, search

Status

Headline text

In progress

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.

Overview

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.

See original article.

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.

See this configuration example

Jargon

  • 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.

Ok, why don't we just see what it looks like. Example1

         Session sess = factory.openSession();
         Transaction tx;
         try {
              tx = sess.beginTransaction();
              Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
              q.setString(0, "Izi");
              tx.commit();
         }
         catch (Exception e) {
             if (tx!=null) tx.rollback();
             throw e;
         }
         finally {
             sess.close();
         }

Another simple example using HQL and named parameters...this time we have a helper class to obtain a Session

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction(); //All database communication occurs within the scope of a transaction

        Person aPerson = (Person) session
                .createQuery("select p from Person p left join fetch p.events where p.id = :pid")
                .setParameter("pid", personId); 

        session.getTransaction().commit();


Security Implications

These issues are discussed in context on this page and are also listed in this section of Hibernate Guidelines.

  • No communication with the database should occur outside of a database transaction. Doing so will probably result in synchronization issues. Transactions should also not encompass user think time. Details are of how it's done is discussed in the Defining Transaction Bounds section of this page.
  • createQuery() can easily be passed a tainted SQL or HQL string, dialect is irrelevant. The proper way to construct a sql string hibernate style is to use Query and SQLQuery's setParameter(), setString(), setXXX() methods for named parameter and placeholder binding. Just like prepared statements. Details are discussed in the Creating Queries section of this page.
  • Persisting tainted objects is stored xss. Since stored XSS is generally hard to find with static tools, it is best to sanitize all data going in rather than waiting for it to show up on a jsp somewhere. Details of these functions are discussed in the Persisting Tainted Data section of this page.
  • An application should rollback and discard Session instance on error. So if the Session throws an exception, the catch block should have rollback() and finally should call Session.close(). This applies to any SQLException. Pretty cut and dry, see Example1 above.
  • You may not mix and match JDBC-style parameters ("?") and named parameters (:namedparam) in the same query.
     Person aPerson = (Person) session
                .createQuery("select :somenamedparameter from ? where x = :someothernamedparameter");
  • Transaction.setTimeout(int) should be called to ensure that misbehaving transactions do not tie up resources in definitely.
     Session sess = factory.openSession();
     try {
          //set transaction timeout to 3 seconds
          sess.getTransaction().setTimeout(3);
          sess.getTransaction().begin();
          // do some work
         ...

Defining Transaction Bounds

Creating, manipulating and executing queries

Persisting tainted data