Skip to content

Commit d22bbb5

Browse files
dreab8Sanne
authored andcommitted
HHH-14225 CVE-2020-25638 Potential for SQL injection on use_sql_comments logging enabled
1 parent d48e19d commit d22bbb5

File tree

12 files changed

+217
-9
lines changed

12 files changed

+217
-9
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Map;
2525
import java.util.Properties;
2626
import java.util.Set;
27+
import java.util.regex.Pattern;
2728

2829
import org.hibernate.HibernateException;
2930
import org.hibernate.LockMode;
@@ -140,6 +141,9 @@ public abstract class Dialect implements ConversionContext {
140141
*/
141142
public static final String CLOSED_QUOTE = "`\"]";
142143

144+
private static final Pattern ESCAPE_CLOSING_COMMENT_PATTERN = Pattern.compile( "\\*/" );
145+
private static final Pattern ESCAPE_OPENING_COMMENT_PATTERN = Pattern.compile( "/\\*" );
146+
143147
private final TypeNames typeNames = new TypeNames();
144148
private final TypeNames hibernateTypeNames = new TypeNames();
145149

@@ -3002,6 +3006,14 @@ public String addSqlHintOrComment(
30023006
}
30033007

30043008
protected String prependComment(String sql, String comment) {
3005-
return "/* " + comment + " */ " + sql;
3009+
return "/* " + escapeComment( comment ) + " */ " + sql;
3010+
}
3011+
3012+
public static String escapeComment(String comment) {
3013+
if ( StringHelper.isNotEmpty( comment ) ) {
3014+
final String escaped = ESCAPE_CLOSING_COMMENT_PATTERN.matcher( comment ).replaceAll( "*\\\\/" );
3015+
return ESCAPE_OPENING_COMMENT_PATTERN.matcher( escaped ).replaceAll( "/\\\\*" );
3016+
}
3017+
return comment;
30063018
}
30073019
}

hibernate-core/src/main/java/org/hibernate/loader/plan/exec/query/internal/SelectStatementBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ public String toStatementString() {
187187
StringBuilder buf = new StringBuilder( guesstimatedBufferSize );
188188

189189
if ( StringHelper.isNotEmpty( comment ) ) {
190-
buf.append( "/* " ).append( comment ).append( " */ " );
190+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
191191
}
192192

193193
buf.append( "select " )

hibernate-core/src/main/java/org/hibernate/sql/Delete.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import java.util.LinkedHashMap;
1010
import java.util.Map;
1111

12+
import org.hibernate.dialect.Dialect;
13+
1214
/**
1315
* An SQL <tt>DELETE</tt> statement
1416
*
@@ -36,7 +38,7 @@ public Delete setTableName(String tableName) {
3638
public String toStatementString() {
3739
StringBuilder buf = new StringBuilder( tableName.length() + 10 );
3840
if ( comment!=null ) {
39-
buf.append( "/* " ).append(comment).append( " */ " );
41+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
4042
}
4143
buf.append( "delete from " ).append(tableName);
4244
if ( where != null || !primaryKeyColumns.isEmpty() || versionColumnName != null ) {

hibernate-core/src/main/java/org/hibernate/sql/Insert.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public Insert setTableName(String tableName) {
9090
public String toStatementString() {
9191
StringBuilder buf = new StringBuilder( columns.size()*15 + tableName.length() + 10 );
9292
if ( comment != null ) {
93-
buf.append( "/* " ).append( comment ).append( " */ " );
93+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
9494
}
9595
buf.append("insert into ")
9696
.append(tableName);

hibernate-core/src/main/java/org/hibernate/sql/InsertSelect.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public String toStatementString() {
6565

6666
StringBuilder buf = new StringBuilder( (columnNames.size() * 15) + tableName.length() + 10 );
6767
if ( comment!=null ) {
68-
buf.append( "/* " ).append( comment ).append( " */ " );
68+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
6969
}
7070
buf.append( "insert into " ).append( tableName );
7171
if ( !columnNames.isEmpty() ) {

hibernate-core/src/main/java/org/hibernate/sql/QuerySelect.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public void addOrderBy(String orderByString) {
126126
public String toQueryString() {
127127
StringBuilder buf = new StringBuilder( 50 );
128128
if ( comment != null ) {
129-
buf.append( "/* " ).append( comment ).append( " */ " );
129+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
130130
}
131131
buf.append( "select " );
132132
if ( distinct ) {

hibernate-core/src/main/java/org/hibernate/sql/Select.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public Select(Dialect dialect) {
4040
public String toStatementString() {
4141
StringBuilder buf = new StringBuilder(guesstimatedBufferSize);
4242
if ( StringHelper.isNotEmpty(comment) ) {
43-
buf.append("/* ").append(comment).append(" */ ");
43+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
4444
}
4545

4646
buf.append("select ").append(selectClause)

hibernate-core/src/main/java/org/hibernate/sql/SimpleSelect.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ public String toStatementString() {
148148
);
149149

150150
if ( comment != null ) {
151-
buf.append( "/* " ).append( comment ).append( " */ " );
151+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
152152
}
153153

154154
buf.append( "select " );

hibernate-core/src/main/java/org/hibernate/sql/Update.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public Update setWhere(String where) {
166166
public String toStatementString() {
167167
StringBuilder buf = new StringBuilder( (columns.size() * 15) + tableName.length() + 10 );
168168
if ( comment!=null ) {
169-
buf.append( "/* " ).append( comment ).append( " */ " );
169+
buf.append( "/* " ).append( Dialect.escapeComment( comment ) ).append( " */ " );
170170
}
171171
buf.append( "update " ).append( tableName ).append( " set " );
172172
boolean assignmentsAppended = false;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.comments;
8+
9+
import javax.persistence.Entity;
10+
import javax.persistence.Id;
11+
12+
/**
13+
* @author Andrea Boriero
14+
*/
15+
@Entity
16+
public class TestEntity {
17+
@Id
18+
private String id;
19+
20+
private String value;
21+
22+
public TestEntity() {
23+
24+
}
25+
26+
public TestEntity(String id, String value) {
27+
this.id = id;
28+
this.value = value;
29+
}
30+
31+
public String getId() {
32+
return id;
33+
}
34+
35+
public void setId(String id) {
36+
this.id = id;
37+
}
38+
39+
public String getValue() {
40+
return value;
41+
}
42+
43+
public void setValue(String value) {
44+
this.value = value;
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.comments;
8+
9+
import javax.persistence.Entity;
10+
import javax.persistence.Id;
11+
12+
/**
13+
* @author Andrea Boriero
14+
*/
15+
@Entity
16+
public class TestEntity2 {
17+
@Id
18+
private String id;
19+
20+
private String value;
21+
22+
public String getId() {
23+
return id;
24+
}
25+
26+
public void setId(String id) {
27+
this.id = id;
28+
}
29+
30+
public String getValue() {
31+
return value;
32+
}
33+
34+
public void setValue(String value) {
35+
this.value = value;
36+
}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.comments;
8+
9+
import java.util.List;
10+
import java.util.Map;
11+
import javax.persistence.EntityManager;
12+
import javax.persistence.TypedQuery;
13+
import javax.persistence.criteria.CompoundSelection;
14+
import javax.persistence.criteria.CriteriaBuilder;
15+
import javax.persistence.criteria.CriteriaQuery;
16+
import javax.persistence.criteria.Path;
17+
import javax.persistence.criteria.Root;
18+
19+
import org.hibernate.cfg.AvailableSettings;
20+
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
21+
22+
import org.junit.Before;
23+
import org.junit.Test;
24+
25+
import static org.hamcrest.CoreMatchers.is;
26+
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
27+
import static org.junit.Assert.assertThat;
28+
29+
/**
30+
* @author Andrea Boriero
31+
*/
32+
public class UseSqlCommentTest extends BaseEntityManagerFunctionalTestCase {
33+
34+
@Override
35+
protected Class<?>[] getAnnotatedClasses() {
36+
return new Class[] { TestEntity.class, TestEntity2.class };
37+
}
38+
39+
@Override
40+
protected void addMappings(Map settings) {
41+
settings.put( AvailableSettings.USE_SQL_COMMENTS, "true" );
42+
settings.put( AvailableSettings.FORMAT_SQL, "false" );
43+
}
44+
45+
@Before
46+
public void setUp() {
47+
doInJPA( this::entityManagerFactory, entityManager -> {
48+
TestEntity testEntity = new TestEntity();
49+
testEntity.setId( "test1" );
50+
testEntity.setValue( "value1" );
51+
entityManager.persist( testEntity );
52+
53+
TestEntity2 testEntity2 = new TestEntity2();
54+
testEntity2.setId( "test2" );
55+
testEntity2.setValue( "value2" );
56+
entityManager.persist( testEntity2 );
57+
} );
58+
}
59+
60+
@Test
61+
public void testIt() {
62+
String appendLiteral = "*/select id as col_0_0_,value as col_1_0_ from testEntity2 where 1=1 or id=?--/*";
63+
doInJPA( this::entityManagerFactory, entityManager -> {
64+
65+
List<TestEntity> result = findUsingQuery( "test1", appendLiteral, entityManager );
66+
67+
TestEntity test1 = result.get( 0 );
68+
assertThat( test1.getValue(), is( appendLiteral ) );
69+
} );
70+
71+
doInJPA( this::entityManagerFactory, entityManager -> {
72+
73+
List<TestEntity> result = findUsingCriteria( "test1", appendLiteral, entityManager );
74+
75+
TestEntity test1 = result.get( 0 );
76+
assertThat( test1.getValue(), is( appendLiteral ) );
77+
} );
78+
}
79+
80+
public List<TestEntity> findUsingCriteria(String id, String appendLiteral, EntityManager entityManager) {
81+
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
82+
CriteriaQuery<TestEntity> criteria = builder.createQuery( TestEntity.class );
83+
Root<TestEntity> root = criteria.from( TestEntity.class );
84+
85+
Path<Object> idPath = root.get( "id" );
86+
CompoundSelection<TestEntity> selection = builder.construct(
87+
TestEntity.class,
88+
idPath,
89+
builder.literal( appendLiteral )
90+
);
91+
criteria.select( selection );
92+
93+
criteria.where( builder.equal( idPath, builder.parameter( String.class, "where_id" ) ) );
94+
95+
TypedQuery<TestEntity> query = entityManager.createQuery( criteria );
96+
query.setParameter( "where_id", id );
97+
return query.getResultList();
98+
}
99+
100+
public List<TestEntity> findUsingQuery(String id, String appendLiteral, EntityManager entityManager) {
101+
TypedQuery<TestEntity> query =
102+
entityManager.createQuery(
103+
"select new org.hibernate.test.comments.TestEntity(id, '"
104+
+ appendLiteral.replace( "'", "''" )
105+
+ "') from TestEntity where id=:where_id",
106+
TestEntity.class
107+
);
108+
query.setParameter( "where_id", id );
109+
return query.getResultList();
110+
}
111+
}

0 commit comments

Comments
 (0)