System.getenv() used in spring boot is shown as a security vulnerability in sonarQube

Viewed 4791

I have method in my spring boot application which takes the data from system environment variable, the method works as intended but sonarQube says "Make sure that environment variables are used safely here", I tried to find an alternative to fix this issue but I am unable to find a solution, here is the method:

How can I handle this security issue, I cannot use anything other than getting the values from environment variables.

public Map<String, Object> getConfigurations() {
    Map<String, Object> result = new HashMap<>();
    HttpResponse response = null;
    try {
         String xVaultToken = System.getenv("XVaultToken");
         String cityAppConfig = System.getenv("CityApp_Config");

        @SuppressWarnings("deprecation")
        HttpClient client = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier())
                .setSslcontext(
                        new SSLContextBuilder().loadTrustMaterial(null, (x509Certificates, s) -> true).build())
                .build();
        Map<String, Object> headerDatas = new HashMap<>();
        headerDatas.put("Content-Type", "application/json");
        headerDatas.put("X-Vault-Token", xVaultToken);
        HttpGet get = new HttpGet(cityAppConfig);
        Set<String> keys = headerDatas.keySet();
        for (String key : keys) {
            get.setHeader(key, headerDatas.get(key).toString());
        }
        response = client.execute(get);
        try(BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))){
            String responseData = rd.readLine();
            result.put(Constants.RESPONSE, responseData);
        }
        int statusCode = response.getStatusLine().getStatusCode();
        result.put(Constants.STATUS, statusCode);

    } catch (Exception e) {
        logger.info("error is local settings getConfigurations" + e);
    }
    return result;
}

}

4 Answers

Disclaimer !!!

First of all, as I mentioned in my comments, if someone requires you to read an ENV-Variable but also says that you can't mark the SonarQube warning as false-positive: Tell them (politely) that they'll have to live with that SonarQube warning.

However, if that is for any reason not an option, I will show you 2 ways that may not trigger the warning in SonarQube which are still much less verbose than calling cmd.exe for that purpose.

Example 1

Call the function via java.util.function.Function

private static String getenv(String variable) {
    return ((Function<String, String>) System::getenv).apply(variable);
}

Example 2

Call the function via reflection

    private static String getenv(String variable) {
        try {
            return (String) System.class.getMethod("getenv", String.class).invoke(null, variable);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

All these "security hotspot" warnings are just "TODO" notifications and should be solved in three steps:

  1. Make sure that the value is really used securely.
    • In this particular case: you are invoking GET request to externally-supplied URL and then use the value from response. What happens when someone changes the environment variable value by some clandestine means and point it to their own web server? Is the response used for anything sensitive? Sometimes even the fact that the URL is invoked can be used for nefarious purposes (tracking). etc etc
  2. Add @SuppressWarnings({"squid:S5304"}) annotation, with proper description in a comment.
  3. Make sure that everything is properly reviewed, including the reasoning from step 1. Remember: Two heads are better than one (especially in security).

Its LOW-level issue can be suppressed using @SuppressWarnings({"squid:S5304"}). Add this statement on class level.

After searching a lot I figured using environment variables to store important information is a bad idea, but if you no other option like me, here is the workaround:

Instead of using System.getenv("XVaultToken"), use a method like this

private String cmdUrl = "cmd.exe /c echo %wfManagement_Config%";
String cityAppConfig =  getEnvironmentVariable(cmdUrl)

private String getEnvironmentVariable(String cmd){
    String environmentVar = "";
    Process p;
    try {
        p = Runtime.getRuntime().exec(cmd);
        p.waitFor(); 
        BufferedReader reader=new BufferedReader(new InputStreamReader(
         p.getInputStream())); 
        String line; 
        while((line = reader.readLine()) != null) { 
            environmentVar = line;
        }
        return environmentVar;
    } catch (Exception e) {
        logger.info("Exception-->"+e);
    }
    return environmentVar;
    
}

The method runs a command and fetches the environment variable for you, for some reasons sonarQube ignores this and doesn't give a security issue.

Related