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..736346be2 100644 --- a/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java +++ b/src/main/java/org/sasanlabs/service/vulnerability/sqlInjection/BlindSQLInjectionVulnerability.java @@ -90,7 +90,10 @@ public ResponseEntity getCarInformationLevel1( String id = queryParams.get(Constants.ID); BodyBuilder bodyBuilder = ResponseEntity.status(HttpStatus.OK); return applicationJdbcTemplate.query( - "select * from cars where id=" + id, + (conn) -> conn.prepareStatement("select * from cars where id=?"), + (prepareStatement) -> { + prepareStatement.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..257da82c1 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 { @@ -42,11 +46,12 @@ public void testGetCarInformationLevel1_CarPresent() throws SQLException { // return rse.extractData(mockResultSet); indicates that the ResultSetExtractor extracts the // data from the mockResultSet (which mocks the query result) - when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class))) + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), any(), any(ResultSetExtractor.class))) .thenAnswer( invocation -> { ResultSetExtractor> rse = - invocation.getArgument(1); + invocation.getArgument(2); return rse.extractData(mockResultSet); }); @@ -72,11 +77,12 @@ public void testGetCarInformationLevel1_CarNotPresent() throws SQLException { // return rse.extractData(mockResultSet); indicates that the ResultSetExtractor extracts the // data from the mockResultSet (which mocks the query result) - when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class))) + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), any(), any(ResultSetExtractor.class))) .thenAnswer( invocation -> { ResultSetExtractor> rse = - invocation.getArgument(1); + invocation.getArgument(2); return rse.extractData(mockResultSet); }); @@ -91,6 +97,40 @@ public void testGetCarInformationLevel1_CarNotPresent() throws SQLException { response.getBody()); } + @Test + public void testGetCarInformationLevel1_BindsBooleanPayloadAsData() throws SQLException { + Map queryParams = new HashMap<>(); + queryParams.put("id", "100 OR 2=2"); + + when(jdbcTemplate.query( + (PreparedStatementCreator) any(), any(), any(ResultSetExtractor.class))) + .thenReturn( + ResponseEntity.ok( + ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE)); + + blindSQLInjectionVulnerability.getCarInformationLevel1(queryParams); + + ArgumentCaptor creatorCaptor = + ArgumentCaptor.forClass(PreparedStatementCreator.class); + ArgumentCaptor setterCaptor = + ArgumentCaptor.forClass(PreparedStatementSetter.class); + verify(jdbcTemplate) + .query( + creatorCaptor.capture(), + setterCaptor.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, creatorCaptor.getValue().createPreparedStatement(connection)); + setterCaptor.getValue().setValues(preparedStatement); + verify(preparedStatement).setString(1, "100 OR 2=2"); + } + @Test public void testGetCarInformationLevel2_CarPresent() throws SQLException { // Arrange