Both environment variables and system properties provide user-defined mappings between keys and their corresponding values and can be used to communicate those values from the environment to a process. According to the Java API \ [[API 2006|AA. References#API 06]\] {{API 2014] Wiki Markup java.lang.System
}} class documentation:
Environment variables have a more global effect because they are visible to all descendants of the process which defines them, not just the immediate Java subprocess. They can have subtly different semantics, such as case insensitivity, on different operating systems. For these reasons, environment variables are more likely to have unintended side effects. It is best to use system properties where possible. Environment variables should be used when a global effect is desired, or when an external system interface requires an environment variable (such as
PATH
).
...
The default values of system properties are set by the Java Virtual Machine (JVM) upon startup and can be considered trusted. However, they may be overridden by properties from untrusted sources, such as a configuration file. System properties from untrusted sources must be sanitized and validated before use.
_The Java Tutorial_ \[ [Campione 1996|AA. References#Campione 96] \] states: Wiki Markup
To maximize portability, never refer to an environment variable when the same value is available in a system property. For example, if the operating system provides a user name, it will always be available in the system property
user.name
.
...
This noncompliant code example tries to get the user name, using an environment variable.:
Code Block | ||
---|---|---|
| ||
String username = System.getenv("USER");
|
First, this is a portability issue. The Java Tutorial Campione 1996 further suggests:
The way environment variables are used also varies. For example, Windows provides the user name in an environment variable called
USERNAME
, while UNIX implementations might provide the user name inUSER
,LOGNAME
, or both.
Second, an attacker can execute this program with the USER
environment variable set to any value he or she chooses. The following code example does just that on a POSIX platform:
Code Block | ||
---|---|---|
| ||
public static void main(String args[]) { if (args.length != 1) { System.err.println("Please supply a user name as the argument"); return; } String user = args[0]; ProcessBuilder pb = new ProcessBuilder(); pb.command("/usr/bin/printenv"); Map<String,String> environment = pb.environment(); environment.put("USER", user); pb.redirectErrorStream(true); try { Process process = pb.start(); InputStream in = process.getInputStream(); int c; while ((c = in.read()) != -1) { System.out.print((char) c); } int exitVal = process.waitFor(); } catch (IOException x) { // forwardForward to handler } catch (InterruptedException x) { // forwardForward to handler } } |
This program runs the POSIX /usr/bin/printenv
command, which prints out all environment variables and their values. It takes a single argument string and sets the USER
environment variable to that string. The subsequent output of the printenv
program will indicate that the USER
environment variable is set to the string requested.
...
This compliant solution obtains the user name using the user.name
system property. The Java Virtual Machine (JVM), upon initialization, sets this system property to the correct user name, even when the USER
environment variable has been set to an incorrect value or is missing.
Code Block | ||
---|---|---|
| ||
String username = System.getProperty("user.name");
|
...
Untrusted environment variables can provide data for injection and other attacks if not properly sanitized.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
ENV02-J |
Low |
Likely |
Low | P9 | L2 |
Bibliography
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="ee2073f8-7136-4c1c-917d-ecfe7b322dad"><ac:plain-text-body><![CDATA[ | [[API 2006 | AA. References#API 06]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="5c2c82bf-97b9-4e1c-bc9b-2ec9ce6b79d0"><ac:plain-text-body><![CDATA[ | [[Campione 1996 | AA. References#Campione 96]] |
| ]]></ac:plain-text-body></ac:structured-macro> |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.ENV02.ENV | Do not use the non-portable 'System.getenv()' method | ||||||
PVS-Studio |
| V6110 |
Android Implementation Details
On Android, the environment variable user.name
is not used and is left blank. However, environment variables exist and are used on Android, so the rule is applicable.
Bibliography
...