From 646b383f959eff18d58081b1a574f0d777d353da Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 30 Apr 2020 16:26:56 -0700 Subject: [PATCH] HHH-14077 : CVE-2019-14900 SQL injection issue in Hibernate ORM --- .../expression/LiteralExpression.java | 12 +- .../CriteriaLiteralWithSingleQuoteTest.java | 133 ++++++++++++++++++ 2 files changed, 139 insertions(+), 6 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/expression/LiteralExpression.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/expression/LiteralExpression.java index af42b2f0091c..fa66140b6478 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/expression/LiteralExpression.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/expression/LiteralExpression.java @@ -78,15 +78,15 @@ private String bindLiteral(RenderingContext renderingContext) { @SuppressWarnings({ "unchecked" }) public String renderProjection(RenderingContext renderingContext) { + if ( ValueHandlerFactory.isCharacter( literal ) ) { + // In case literal is a Character, pass literal.toString() as the argument. + return renderingContext.getDialect().inlineLiteral( literal.toString() ); + } + // some drivers/servers do not like parameters in the select clause final ValueHandlerFactory.ValueHandler handler = ValueHandlerFactory.determineAppropriateHandler( literal.getClass() ); - if ( ValueHandlerFactory.isCharacter( literal ) ) { - return '\'' + handler.render( literal ) + '\''; - } - else { - return handler.render( literal ); - } + return handler.render( literal ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java new file mode 100644 index 000000000000..b51040b87664 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/criteria/literal/CriteriaLiteralWithSingleQuoteTest.java @@ -0,0 +1,133 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.test.criteria.literal; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +public class CriteriaLiteralWithSingleQuoteTest extends BaseEntityManagerFunctionalTestCase { + + @Test + public void literalSingleQuoteTest() throws Exception { + + doInJPA( + this::entityManagerFactory, + entityManager -> { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(); + query.select( cb.literal( '\'' ) ).from( Student.class ); + Object object = entityManager.createQuery( query ).getSingleResult(); + assertEquals( "'", object ); + } + ); + } + + @Test + public void literalProjectionTest() throws Exception { + + doInJPA( + this::entityManagerFactory, + entityManager -> { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(); + query.multiselect( cb.literal( "' || aValue || '" ) ).from( Student.class ); + Object object = entityManager.createQuery( query ).getSingleResult(); + assertEquals( "' || aValue || '", object ); + } + ); + } + + @Test + public void testLiteralProjectionAndGroupBy() throws Exception { + doInJPA( + this::entityManagerFactory, + entityManager -> { + + final String literal = "' || aValue || '"; + + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery query = cb.createQuery(); + query.multiselect( cb.literal( literal ) ) + .from( Student.class ); + query.groupBy( cb.literal( literal ) ); + + Object object = entityManager.createQuery( query ).getSingleResult(); + assertEquals( literal, object ); + } + ); + } + + @Before + public void setupData() { + doInJPA( + this::entityManagerFactory, + entityManager -> { + Student student = new Student(); + student.setAValue( "A Value" ); + entityManager.persist( student ); + } + ); + } + + @After + public void cleanupData() { + doInJPA( + this::entityManagerFactory, + entityManager -> { + entityManager.createQuery( "delete from Student" ); + } + ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Student.class }; + } + + @Entity(name = "Student") + @Table(name = "Students") + public static class Student { + + @Id + @GeneratedValue + private Long id; + + @Column + private String aValue; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + this.id = id; + } + + public String getAValue() { + return aValue; + } + + public void setAValue(String value) { + this.aValue = value; + } + } +}