Skip to content

Commit 4986733

Browse files
x7Gitphilipp-delmonegosklawinKaran Preet Singh Sasan
authored
#406 secured implementations for Union SQL Injection (#452)
* Add secured implementations for Union SQL Injection --------- Co-authored-by: philipp.delmonego <[email protected]> Co-authored-by: Sebastian Klawin <[email protected]> Co-authored-by: Karan Preet Singh Sasan <[email protected]>
1 parent a867b67 commit 4986733

File tree

4 files changed

+170
-11
lines changed

4 files changed

+170
-11
lines changed

src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/CarInformation.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
package org.sasanlabs.service.vulnerability.sqlInjection;
22

3+
import javax.persistence.*;
4+
35
/** @author [email protected] KSASAN */
6+
@Access(AccessType.FIELD)
7+
@Entity
8+
@Table(name = "cars")
9+
@NamedQuery(name = "findById", query = "select c from CarInformation c where c.id=:id")
410
public class CarInformation {
11+
12+
@Id
13+
@GeneratedValue(strategy = GenerationType.IDENTITY)
514
private int id;
15+
616
private String name;
17+
18+
@Column(name = "image")
719
private String imagePath;
820

921
public CarInformation() {}
@@ -38,4 +50,8 @@ public String getImagePath() {
3850
public void setImagePath(String imagePath) {
3951
this.imagePath = imagePath;
4052
}
53+
54+
public void setImage(String imagePath) {
55+
this.imagePath = imagePath;
56+
}
4157
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.sasanlabs.service.vulnerability.sqlInjection;
2+
3+
import java.util.Optional;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface CarInformationRepository extends JpaRepository<CarInformation, Integer> {
7+
8+
Optional<CarInformation> findById(Integer id);
9+
}

src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerability.java

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
import java.sql.ResultSet;
44
import java.sql.SQLException;
55
import java.util.Map;
6+
import java.util.Optional;
7+
import javax.persistence.EntityManager;
8+
import javax.persistence.TypedQuery;
9+
import javax.persistence.criteria.CriteriaBuilder;
10+
import javax.persistence.criteria.CriteriaQuery;
11+
import javax.persistence.criteria.Root;
612
import org.sasanlabs.internal.utility.LevelConstants;
713
import org.sasanlabs.internal.utility.Variant;
814
import org.sasanlabs.internal.utility.annotations.AttackVector;
@@ -12,7 +18,11 @@
1218
import org.springframework.beans.factory.annotation.Qualifier;
1319
import org.springframework.http.HttpStatus;
1420
import org.springframework.http.ResponseEntity;
21+
import org.springframework.jdbc.core.BeanPropertyRowMapper;
1522
import org.springframework.jdbc.core.JdbcTemplate;
23+
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
24+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
25+
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
1626
import org.springframework.web.bind.annotation.RequestParam;
1727

1828
/**
@@ -28,10 +38,19 @@
2838
public class UnionBasedSQLInjectionVulnerability {
2939

3040
private final JdbcTemplate applicationJdbcTemplate;
41+
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
42+
private final CarInformationRepository carInformationRepository;
43+
private final EntityManager entityManager;
3144

3245
public UnionBasedSQLInjectionVulnerability(
33-
@Qualifier("applicationJdbcTemplate") final JdbcTemplate applicationJdbcTemplate) {
46+
@Qualifier("applicationJdbcTemplate") final JdbcTemplate applicationJdbcTemplate,
47+
NamedParameterJdbcTemplate namedParameterJdbcTemplate,
48+
CarInformationRepository carInformationRepository,
49+
EntityManager entityManager) {
3450
this.applicationJdbcTemplate = applicationJdbcTemplate;
51+
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
52+
this.carInformationRepository = carInformationRepository;
53+
this.entityManager = entityManager;
3554
}
3655

3756
@AttackVector(
@@ -92,6 +111,83 @@ public ResponseEntity<CarInformation> getCarInformationLevel4(
92111
this::resultSetToResponse);
93112
}
94113

114+
@VulnerableAppRequestMapping(
115+
value = LevelConstants.LEVEL_5,
116+
variant = Variant.SECURE,
117+
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
118+
public ResponseEntity<CarInformation> getCarInformationLevel5(
119+
@RequestParam final Map<String, String> queryParams) {
120+
final String id = queryParams.get("id");
121+
SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("id", id);
122+
CarInformation s =
123+
namedParameterJdbcTemplate.queryForObject(
124+
"select * from cars where id=:id",
125+
namedParameters,
126+
new BeanPropertyRowMapper<>(CarInformation.class));
127+
return new ResponseEntity<>(s, HttpStatus.OK);
128+
}
129+
130+
@VulnerableAppRequestMapping(
131+
value = LevelConstants.LEVEL_6,
132+
variant = Variant.SECURE,
133+
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
134+
public ResponseEntity<CarInformation> getCarInformationLevel6(
135+
@RequestParam final Map<String, String> queryParams) {
136+
final String id = queryParams.get("id");
137+
String jql = "from CarInformation where id = :id";
138+
TypedQuery<CarInformation> q =
139+
entityManager
140+
.createQuery(jql, CarInformation.class)
141+
.setParameter("id", Integer.valueOf(id));
142+
return new ResponseEntity<>(q.getSingleResult(), HttpStatus.OK);
143+
}
144+
145+
@VulnerableAppRequestMapping(
146+
value = LevelConstants.LEVEL_7,
147+
variant = Variant.SECURE,
148+
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
149+
public ResponseEntity<CarInformation> getCarInformationLevel7(
150+
@RequestParam final Map<String, String> queryParams) {
151+
final String id = queryParams.get("id");
152+
153+
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
154+
CriteriaQuery<CarInformation> cq = cb.createQuery(CarInformation.class);
155+
Root<CarInformation> root = cq.from(CarInformation.class);
156+
157+
cq.select(root).where(cb.equal(root.get("id"), id));
158+
159+
TypedQuery<CarInformation> q = entityManager.createQuery(cq);
160+
return new ResponseEntity<>(q.getSingleResult(), HttpStatus.OK);
161+
}
162+
163+
@VulnerableAppRequestMapping(
164+
value = LevelConstants.LEVEL_8,
165+
variant = Variant.SECURE,
166+
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
167+
public ResponseEntity<CarInformation> getCarInformationLevel8(
168+
@RequestParam final Map<String, String> queryParams) {
169+
final String id = queryParams.get("id");
170+
TypedQuery<CarInformation> q =
171+
entityManager
172+
.createNamedQuery("findById", CarInformation.class)
173+
.setParameter("id", Integer.valueOf(id));
174+
return new ResponseEntity<>(q.getSingleResult(), HttpStatus.OK);
175+
}
176+
177+
@VulnerableAppRequestMapping(
178+
value = LevelConstants.LEVEL_9,
179+
variant = Variant.SECURE,
180+
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
181+
public ResponseEntity<CarInformation> getCarInformationLevel9(
182+
@RequestParam final Map<String, String> queryParams) {
183+
final String id = queryParams.get("id");
184+
Optional<CarInformation> carInformation =
185+
carInformationRepository.findById(Integer.valueOf(id));
186+
return carInformation
187+
.map(information -> new ResponseEntity<>(information, HttpStatus.OK))
188+
.orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
189+
}
190+
95191
private ResponseEntity<CarInformation> resultSetToResponse(final ResultSet rs)
96192
throws SQLException {
97193
final CarInformation carInformation = new CarInformation();

src/test/java/org/sasanlabs/service/vulnerability/sqlInjection/UnionBasedSQLInjectionVulnerabilityTest.java

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
11
package org.sasanlabs.service.vulnerability.sqlInjection;
22

3-
import static org.mockito.ArgumentMatchers.any;
4-
import static org.mockito.ArgumentMatchers.anyString;
5-
import static org.mockito.ArgumentMatchers.eq;
3+
import static org.mockito.ArgumentMatchers.*;
64
import static org.mockito.Mockito.doReturn;
75
import static org.mockito.Mockito.verify;
86

9-
import java.io.IOException;
107
import java.util.Collections;
118
import java.util.Map;
9+
import java.util.Objects;
10+
import javax.persistence.EntityManager;
1211
import org.junit.jupiter.api.BeforeEach;
1312
import org.junit.jupiter.api.Test;
13+
import org.mockito.ArgumentMatcher;
1414
import org.mockito.Mockito;
15+
import org.springframework.jdbc.core.BeanPropertyRowMapper;
1516
import org.springframework.jdbc.core.JdbcTemplate;
1617
import org.springframework.jdbc.core.PreparedStatementSetter;
1718
import org.springframework.jdbc.core.ResultSetExtractor;
19+
import org.springframework.jdbc.core.RowMapper;
20+
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
21+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
1822

1923
class UnionBasedSQLInjectionVulnerabilityTest {
2024

2125
private UnionBasedSQLInjectionVulnerability unionBasedSQLInjectionVulnerability;
2226
private JdbcTemplate template;
27+
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
28+
private CarInformationRepository carInformationRepository;
29+
private EntityManager entityManager;
2330

2431
@BeforeEach
25-
void setUp() throws IOException {
32+
void setUp() {
2633
template = Mockito.mock(JdbcTemplate.class);
34+
namedParameterJdbcTemplate = Mockito.mock(NamedParameterJdbcTemplate.class);
35+
carInformationRepository = Mockito.mock(CarInformationRepository.class);
36+
entityManager = Mockito.mock(EntityManager.class);
2737

2838
// mock database
2939
doReturn(null)
@@ -36,11 +46,16 @@ void setUp() throws IOException {
3646
(PreparedStatementSetter) any(),
3747
(ResultSetExtractor<? extends Object>) any());
3848

39-
unionBasedSQLInjectionVulnerability = new UnionBasedSQLInjectionVulnerability(template);
49+
unionBasedSQLInjectionVulnerability =
50+
new UnionBasedSQLInjectionVulnerability(
51+
template,
52+
namedParameterJdbcTemplate,
53+
carInformationRepository,
54+
entityManager);
4055
}
4156

4257
@Test
43-
void getCarInformationLevel1_ExpectParamInjected() throws IOException {
58+
void getCarInformationLevel1_ExpectParamInjected() {
4459
// Act
4560
final Map<String, String> params =
4661
Collections.singletonMap("id", "1 UNION SELECT * FROM cars;");
@@ -54,7 +69,7 @@ void getCarInformationLevel1_ExpectParamInjected() throws IOException {
5469
}
5570

5671
@Test
57-
void getCarInformationLevel2_ExpectParamInjected() throws IOException {
72+
void getCarInformationLevel2_ExpectParamInjected() {
5873
// Act
5974
final Map<String, String> params =
6075
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
@@ -68,7 +83,7 @@ void getCarInformationLevel2_ExpectParamInjected() throws IOException {
6883
}
6984

7085
@Test
71-
void getCarInformationLevel3_ExpectParamEscaped() throws IOException {
86+
void getCarInformationLevel3_ExpectParamEscaped() {
7287
// Act
7388
final Map<String, String> params =
7489
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
@@ -82,7 +97,7 @@ void getCarInformationLevel3_ExpectParamEscaped() throws IOException {
8297
}
8398

8499
@Test
85-
void getCarInformationLevel4_ExpecParamEscaped() throws IOException {
100+
void getCarInformationLevel4_ExpectParamEscaped() {
86101
// Act
87102
final Map<String, String> params =
88103
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
@@ -95,4 +110,27 @@ void getCarInformationLevel4_ExpecParamEscaped() throws IOException {
95110
(PreparedStatementSetter) any(),
96111
(ResultSetExtractor<? extends Object>) any());
97112
}
113+
114+
@Test
115+
void getCarInformationLevel5_ExpectParamEscaped() {
116+
// Act
117+
final Map<String, String> params =
118+
Collections.singletonMap("id", "1' UNION SELECT * FROM cars; --");
119+
final String id = "1' UNION SELECT * FROM cars; --";
120+
unionBasedSQLInjectionVulnerability.getCarInformationLevel5(params);
121+
// Assert
122+
ArgumentMatcher<MapSqlParameterSource> argumentMatcher =
123+
sqlParameterSource ->
124+
Objects.requireNonNull(sqlParameterSource.getValue("id").equals(id));
125+
verify(namedParameterJdbcTemplate)
126+
.queryForObject(
127+
eq("select * from cars where id=:id"),
128+
argThat(argumentMatcher),
129+
(RowMapper<Object>)
130+
argThat(
131+
val ->
132+
((BeanPropertyRowMapper) val)
133+
.getMappedClass()
134+
.equals(CarInformation.class)));
135+
}
98136
}

0 commit comments

Comments
 (0)