- java
- security
- Java basic
- quality
- SEI CERT
Performing a comparison using equals after changing the casing of strings is locale dependent. This comparison may lead to unexpected results.
When performing changes to the casing of a string, a locale needs to be provided to map lowercase and uppercase characters. If no locale is provided, the JVM will use its default locale. In practice this means that characters may change in an unexpected way when changing their case, depending on the locale used to create the string. When comparing the resulting strings for equality, they might not be considered equal even though they would be expected to be equal.
For example, in the Turkish locale the character "\u0130" indicates the "latin capital letter i with dot above". When comparing using the default locale, it will not be considered equal to the character 'i', however, it can be interpreted by code as such. This can lead to validation routine bypassing, enabling other types of attacks.
To resolve the issue, either provide a locale to the case changing operation or remove the case changing operation and use equalsIgnoreCase
instead.
public static void processTag(String tag) { if (tag.toUpperCase().equals("SCRIPT")) { return; } // Process tag }After (Using explicit locale)
public static void processTag(String tag) { if (tag.toUpperCase(Locale.ROOT).equals("SCRIPT")) { return; } // Process tag }After (Using
equalsIgnoreCase
)
public static void processTag(String tag) { if (tag.equalsIgnoreCase("SCRIPT")) { return; } // Process tag }References
id: scw:java:equals-after-case-conversion version: 10 metadata: name: 'Portability Flaw: Avoid locale dependent comparisons: equals after case conversion' shortDescription: This comparison is sensitive to the system's locale. Ignore the case or add a locale. level: warning language: java newCodeOnly: false cweCategory: 474 enabled: true comment: "" descriptionFile: descriptions/Portability_Flaw__Avoid_locale_dependent_comparisons__equals_after_case_conversion.html tags: security;Java basic;quality;SEI CERT search: methodcall: name: equals type: java.lang.String "on": methodcall: anyOf: - name: matches: (toUpperCase|toLowerCase) type: java.lang.String without: args: any: {} availableFixes: - name: Use equalsIgnoreCase actions: - rewrite: to: '{{{ qualifier.qualifier }}}.equalsIgnoreCase({{{ arguments.0 }}})' - name: Add ROOT locale actions: - rewrite: to: '{{{ qualifier.qualifier }}}.{{{ qualifier.methodName }}}(java.util.Locale.ROOT).{{{ methodName }}}({{{ arguments.0 }}})'