Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blind sql injection secure implementations #476

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.sasanlabs.service.vulnerability.sqlInjection;

import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.sasanlabs.internal.utility.LevelConstants;
import org.sasanlabs.internal.utility.Variant;
import org.sasanlabs.internal.utility.annotations.AttackVector;
Expand Down Expand Up @@ -29,6 +31,7 @@
value = "BlindSQLInjectionVulnerability")
public class BlindSQLInjectionVulnerability {

@PersistenceContext private EntityManager entityManager;
private JdbcTemplate applicationJdbcTemplate;

static final String CAR_IS_PRESENT_RESPONSE = "{ \"isCarPresent\": true}";
Expand Down Expand Up @@ -106,4 +109,50 @@ public ResponseEntity<String> getCarInformationLevel3(
ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE);
});
}

// Input Validation - Ensure that the input data is valid and of the expected type.
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_4,
variant = Variant.SECURE,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<String> getCarInformationLevel4(
@RequestParam Map<String, String> queryParams) {
String id = queryParams.get(Constants.ID);

// Validate numeric ID
if (!id.matches("\\d+")) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid ID format.");
}

BodyBuilder bodyBuilder = ResponseEntity.status(HttpStatus.OK);
bodyBuilder.body(ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE);
return applicationJdbcTemplate.query(
"select * from cars where id=" + id,
(rs) -> {
if (rs.next()) {
return bodyBuilder.body(CAR_IS_PRESENT_RESPONSE);
}
return bodyBuilder.body(
ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE);
});
}

// Implementation Level 5 - Hibernate
@VulnerableAppRequestMapping(
value = LevelConstants.LEVEL_5,
variant = Variant.SECURE,
htmlTemplate = "LEVEL_1/SQLInjection_Level1")
public ResponseEntity<String> getCarInformationLevel5(
@RequestParam Map<String, String> queryParams) {
int id = Integer.parseInt(queryParams.get(Constants.ID));

CarInformation car = entityManager.find(CarInformation.class, id);

if (car != null) {
return ResponseEntity.ok(CAR_IS_PRESENT_RESPONSE);
} else {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package org.sasanlabs.service.vulnerability.sqlInjection;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

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.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.jdbc.core.ResultSetExtractor;

public class BlindSQLInjectionVulnerabilityTest {

@Mock private JdbcTemplate jdbcTemplate;

@InjectMocks private BlindSQLInjectionVulnerability blindSQLInjectionVulnerability;

@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}

@Test
public void testGetCarInformationLevel1_CarPresent() throws SQLException {
// Arrange
String id = "1";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// The query is simulated to have returned a result (i.e. there is a car with ID "1")
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(true);

// 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)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(1);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel1(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("{ \"isCarPresent\": true}", response.getBody());
}

@Test
public void testGetCarInformationLevel1_CarNotPresent() throws SQLException {
// Arrange
String id = "2";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// The query is simulated to have returned a result (i.e. there is no a car with ID "2")
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(false);

// 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)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(1);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel1(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(
ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE, response.getBody());
}

@Test
public void testGetCarInformationLevel2_CarPresent() throws SQLException {
// Arrange
String id = "1";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// Mock the ResultSet behavior
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(true);

// Mock the query method of JdbcTemplate
when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(1);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel2(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("{ \"isCarPresent\": true}", response.getBody());
}

@Test
public void testGetCarInformationLevel2_CarNotPresent() throws SQLException {
// Arrange
String id = "2";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// Mock the ResultSet behavior
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(false);

// Mock the query method of JdbcTemplate
when(jdbcTemplate.query(anyString(), any(ResultSetExtractor.class)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(1);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel2(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(
ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE, response.getBody());
}

@Test
public void testGetCarInformationLevel3_CarPresent() throws SQLException {
// Arrange
String id = "1";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// Mock the ResultSet behavior
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(true);

// Mock the query method of JdbcTemplate
when(jdbcTemplate.query((PreparedStatementCreator) any(), any(), any(ResultSetExtractor.class)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(2);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel3(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("{ \"isCarPresent\": true}", response.getBody());
}

@Test
public void testGetCarInformationLevel3_CarNotPresent() throws SQLException {
// Arrange
String id = "2";
Map<String, String> queryParams = new HashMap<>();
queryParams.put("id", id);

// Mock the ResultSet behavior
ResultSet mockResultSet = mock(ResultSet.class);
when(mockResultSet.next()).thenReturn(false);

// Mock the query method of JdbcTemplate
when(jdbcTemplate.query((PreparedStatementCreator) any(), any(), any(ResultSetExtractor.class)))
.thenAnswer(
invocation -> {
ResultSetExtractor<ResponseEntity<String>> rse = invocation.getArgument(2);
return rse.extractData(mockResultSet);
});

// Act
ResponseEntity<String> response =
blindSQLInjectionVulnerability.getCarInformationLevel3(queryParams);

// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(
ErrorBasedSQLInjectionVulnerability.CAR_IS_NOT_PRESENT_RESPONSE, response.getBody());
}
}

Loading