diff --git a/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java b/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java index c768a8593..7dae252a5 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java @@ -132,7 +132,8 @@ public ResponseEntity getCarInformationLevel2( BodyBuilder bodyBuilder = ResponseEntity.status(HttpStatus.OK); bodyBuilder.body(ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE); return applicationJdbcTemplate.query( - "select * from cars where id='" + id + "'", + (connection) -> connection.prepareStatement("select * from cars where id=?"), + (preparedStatement) -> preparedStatement.setString(1, id), (rs) -> { if (rs.next()) { return bodyBuilder.body(CAR_IS_PRESENT_RESPONSE); diff --git a/src/test/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerabilityTest.java b/src/test/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerabilityTest.java index 5883c6af6..46bdc5114 100644 --- a/src/test/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerabilityTest.java +++ b/src/test/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerabilityTest.java @@ -3,12 +3,15 @@ import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; +import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -16,6 +19,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.core.PreparedStatementSetter; import org.springframework.jdbc.core.ResultSetExtractor; public class BlindSQLInjectionVulnerabilityTest { @@ -91,6 +95,49 @@ public void testGetCarInformationLevel1_CarNotPresent() throws SQLException { response.getBody()); } + @Test + public void testGetCarInformationLevel2_BindsQuotedBlindInjectionPayload() throws SQLException { + String payload = "1' OR '1'='1"; + Map queryParams = new HashMap<>(); + queryParams.put("id", payload); + + ResultSet mockResultSet = mock(ResultSet.class); + when(mockResultSet.next()).thenReturn(false); + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), + (PreparedStatementSetter) any(), + any(ResultSetExtractor.class))) + .thenAnswer( + invocation -> { + ResultSetExtractor> extractor = + invocation.getArgument(2); + return extractor.extractData(mockResultSet); + }); + + ResponseEntity response = + blindSQLInjectionVulnerability.getCarInformationLevel2(queryParams); + + ArgumentCaptor creator = + ArgumentCaptor.forClass(PreparedStatementCreator.class); + ArgumentCaptor setter = + ArgumentCaptor.forClass(PreparedStatementSetter.class); + verify(jdbcTemplate) + .query(creator.capture(), setter.capture(), any(ResultSetExtractor.class)); + + Connection connection = mock(Connection.class); + PreparedStatement preparedStatement = mock(PreparedStatement.class); + when(connection.prepareStatement("select * from cars where id=?")) + .thenReturn(preparedStatement); + + assertEquals(preparedStatement, creator.getValue().createPreparedStatement(connection)); + setter.getValue().setValues(preparedStatement); + verify(preparedStatement).setString(1, payload); + verify(jdbcTemplate, never()).query(contains(payload), any(ResultSetExtractor.class)); + assertEquals( + ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE, + response.getBody()); + } + @Test public void testGetCarInformationLevel2_CarPresent() throws SQLException { // Arrange @@ -103,11 +150,14 @@ public void testGetCarInformationLevel2_CarPresent() throws SQLException { when(mockResultSet.next()).thenReturn(true); // Mock the query method of JdbcTemplate - when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class))) + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), + (PreparedStatementSetter) any(), + any(ResultSetExtractor.class))) .thenAnswer( invocation -> { ResultSetExtractor> rse = - invocation.getArgument(1); + invocation.getArgument(2); return rse.extractData(mockResultSet); }); @@ -132,11 +182,14 @@ public void testGetCarInformationLevel2_CarNotPresent() throws SQLException { when(mockResultSet.next()).thenReturn(false); // Mock the query method of JdbcTemplate - when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class))) + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), + (PreparedStatementSetter) any(), + any(ResultSetExtractor.class))) .thenAnswer( invocation -> { ResultSetExtractor> rse = - invocation.getArgument(1); + invocation.getArgument(2); return rse.extractData(mockResultSet); });