'SonnarQube's issue: change code to not construct the URL from user-controlled data

I facing a SonarQube bug and am not able to figure out whats the issue. SonnarQube's issue is, change this code to not construct the URL from user-controlled data.

@Value("${...}")
String apiKey;

@Value("${...}")
String apiUrl;

public Response apiResponse(String location) {

   HttpHeaders headers = new HttpHeaders();
   headers.add("x-apikey", apiKey);

   HttpEntity<Object> entity = new HttpEntity<>(headers);

   String url = apiUrl + location; // SonarQube issue: tainted value is propagated

   Response response = null;

   try {

      ResponseEntity<Response> responseEntity = restTemplate.exchange(url, HttpMethod.GET, entity, Response.class); // SonarQube issue: Tainted value is used to perform a security- sensitive operation.

      response = responseEntity.getBody();

   } catch(Exception){

       // doesn't throw anything

   }

   return response;

}

@Cacheable(...)
Response cacheResponse(String location, String tokenKey) {

  return apiResponse(location); // SonarQube issue: tainted value is propagated
}

This fixed the issue, but why is that so? and how can I apply this in the above code?

 String url = apiUrl + location; // SonarQube issue: tainted 

Instead, I just tried hardcoding the value of location and fixed the issue.

String url = apiUrl + "location";

So weird...



Solution 1:[1]

I added validation for the Location variable and this solved the issue

if(!location.matches(...)) {
   throw error.....
}

String url = apiUrl + location;

Solution 2:[2]

What SonarQube is trying to tell you is that you are exposing your logic to input from the clients. A better solution would be to refactor your code to not depend on a specific header from the client to perform some action. Its hard to suggest sample code without seeing a little more of the codebase.

Solution 3:[3]

You are using input from the client/user (namly in the variable location) to construct an URL. So if the client/user supplies an malicious value to location he could form an invalid URL.

In the second example String url = apiUrl + "location"; you are not using user input, as "location" is a hard coded String.

I don't know what you try to achieve with the code. But maybe it's better to hold a list of possible URLs and the user supplies and enum value that maps to an URL.

Solution 4:[4]

String url = "https://someurl/%s";
url = String.format(url,location);
sendRequest(url);

Maybe this approach won't give error.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ima.technophyle
Solution 2 Dharman
Solution 3 TomStroemer
Solution 4