Increasingly, programmers view string data as a portable means of storing and communicating data, including numeric values. A real world example involved storing the binary values of encrypted passwords as strings in a database.
While inefficient, it is generally feasible to convert numeric values to strings and then reverse the process. However, the binary numeric value may not be representable in any character set, because not all bit patterns represent valid characters. Consequently, programmers must never convert directly from a binary numeric value to a string.
This noncompliant code example attempts to convert a BigInteger value to a String and then restore it back again. The toByteArray() method used returns a byte array containing the two's-complement representation of this BigInteger. The byte array is in big-endian byte-order: the most significant byte is in the zeroth element. The program uses the String(byte[] bytes) constructor to create the string from the byte array. The behavior of this constructor when the given bytes are not valid in the default character set is unspecified, which is likely to be the case. Specifying the character set as a string also has unspecified behavior, although the Java API [API 2014] document claims that the String(byte[], Charset) method always replaces malformed-input and unmappable-character sequences with this character set's default replacement string. In any case, converting the String back to a BigInteger is unlikely to reproduce the original value.
BigInteger x = new BigInteger("530500452766");
byte[] byteArray = x.toByteArray();
String s = new String(byteArray);
byteArray = s.getBytes();
x = new BigInteger(byteArray);
|
This compliant solution first produces a String representation of the BigInteger object and then converts the String object to a byte array. This process is then reversed. Because the textual representation in the String object is generated by the BigInteger class, it contains valid character data in the default character set.
BigInteger x = new BigInteger("530500452766");
String s = x.toString(); // valid character data
byte[] byteArray = s.getBytes();
String ns = new String(byteArray);
x = new BigInteger(ns);
|
While Java does not provide a Charset that guarantees lossless encoding of byte data, there are many other solutions for safely converting an arbitrary byte array into a string and back. Java 8 provides the java.util.Base64 class which provides encoders and decoders for the Base64 encoding scheme. This compliant solution uses Base64 to safely convert the number to a string and back without corruption of data.
BigInteger x = new BigInteger("530500452766");
byte[] byteArray = x.toByteArray();
String s = Base64.getEncoder().encodeToString( byteArray);
byteArray = Base64.getDecoder().decode(s);
x = new BigInteger(byteArray);
|
Storing numeric data as a string is likely to result in a loss of data integrity.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
STR03-J | low | unlikely | medium | P2 | L3 |
CWE-838. Inappropriate Encoding for Output Context |
[API 2006] |