Skip to content

Commit 4aacba8

Browse files
authored
Merge pull request #6468 from atorralba/atorralba/promote-cleartext-sharedprefs
Java: Promote Cleartext storage of sensitive information using SharedPreferences from experimental
2 parents 77763d7 + 394c4a9 commit 4aacba8

13 files changed

+239
-287
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/** Provides classes and predicates to reason about cleartext storage in Android's SharedPreferences. */
2+
3+
import java
4+
import semmle.code.java.dataflow.DataFlow
5+
import semmle.code.java.frameworks.android.SharedPreferences
6+
import semmle.code.java.security.CleartextStorageQuery
7+
8+
private class SharedPrefsCleartextStorageSink extends CleartextStorageSink {
9+
SharedPrefsCleartextStorageSink() {
10+
exists(MethodAccess m |
11+
m.getMethod() instanceof PutSharedPreferenceMethod and
12+
this.asExpr() = m.getArgument(1)
13+
)
14+
}
15+
}
16+
17+
/**
18+
* The call to get a `SharedPreferences.Editor` object, which can set shared preferences and be
19+
* stored to the device.
20+
*/
21+
class SharedPreferencesEditorMethodAccess extends Storable, MethodAccess {
22+
SharedPreferencesEditorMethodAccess() {
23+
this.getMethod() instanceof GetSharedPreferencesEditorMethod and
24+
not DataFlow::localExprFlow(any(MethodAccess ma |
25+
ma.getMethod() instanceof CreateEncryptedSharedPreferencesMethod
26+
), this.getQualifier())
27+
}
28+
29+
/** Gets an input, for example `password` in `editor.putString("password", password);`. */
30+
override Expr getAnInput() {
31+
exists(SharedPreferencesFlowConfig conf, DataFlow::Node editor |
32+
sharedPreferencesInput(editor, result) and
33+
conf.hasFlow(DataFlow::exprNode(this), editor)
34+
)
35+
}
36+
37+
/** Gets a store, for example `editor.commit();`. */
38+
override Expr getAStore() {
39+
exists(SharedPreferencesFlowConfig conf, DataFlow::Node editor |
40+
sharedPreferencesStore(editor, result) and
41+
conf.hasFlow(DataFlow::exprNode(this), editor)
42+
)
43+
}
44+
}
45+
46+
/**
47+
* Holds if `input` is the second argument of a setter method
48+
* called on `editor`, which is an instance of `SharedPreferences$Editor`.
49+
*/
50+
private predicate sharedPreferencesInput(DataFlow::Node editor, Expr input) {
51+
exists(MethodAccess m |
52+
m.getMethod() instanceof PutSharedPreferenceMethod and
53+
input = m.getArgument(1) and
54+
editor.asExpr() = m.getQualifier()
55+
)
56+
}
57+
58+
/**
59+
* Holds if `m` is a store method called on `editor`,
60+
* which is an instance of `SharedPreferences$Editor`.
61+
*/
62+
private predicate sharedPreferencesStore(DataFlow::Node editor, MethodAccess m) {
63+
m.getMethod() instanceof StoreSharedPreferenceMethod and
64+
editor.asExpr() = m.getQualifier()
65+
}
66+
67+
/** Flow from `SharedPreferences.Editor` to either a setter or a store method. */
68+
private class SharedPreferencesFlowConfig extends DataFlow::Configuration {
69+
SharedPreferencesFlowConfig() { this = "SharedPreferencesFlowConfig" }
70+
71+
override predicate isSource(DataFlow::Node src) {
72+
src.asExpr() instanceof SharedPreferencesEditorMethodAccess
73+
}
74+
75+
override predicate isSink(DataFlow::Node sink) {
76+
sharedPreferencesInput(sink, _) or
77+
sharedPreferencesStore(sink, _)
78+
}
79+
}

java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.java renamed to java/ql/src/Security/CWE/CWE-312/CleartextStorageSharedPrefs.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
public void testSetSharedPrefs(Context context, String name, String password)
22
{
33
{
4-
// BAD - save sensitive information in cleartext
4+
// BAD - sensitive information saved in cleartext.
55
SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
66
Editor editor = sharedPrefs.edit();
77
editor.putString("name", name);
@@ -10,7 +10,7 @@ public void testSetSharedPrefs(Context context, String name, String password)
1010
}
1111

1212
{
13-
// GOOD - save sensitive information in encrypted format
13+
// GOOD - save sensitive information encrypted with a custom method.
1414
SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
1515
Editor editor = sharedPrefs.edit();
1616
editor.putString("name", encrypt(name));
@@ -19,7 +19,7 @@ public void testSetSharedPrefs(Context context, String name, String password)
1919
}
2020

2121
{
22-
// GOOD - save sensitive information using the built-in `EncryptedSharedPreferences` class in androidx.
22+
// GOOD - sensitive information saved using the built-in `EncryptedSharedPreferences` class in androidx.
2323
MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
2424
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
2525
.build();
@@ -37,3 +37,12 @@ public void testSetSharedPrefs(Context context, String name, String password)
3737
editor.commit();
3838
}
3939
}
40+
41+
private static String encrypt(String cleartext) throws Exception {
42+
// Use an encryption or hashing algorithm in real world. The demo below just returns its
43+
// hash.
44+
MessageDigest digest = MessageDigest.getInstance("SHA-256");
45+
byte[] hash = digest.digest(cleartext.getBytes(StandardCharsets.UTF_8));
46+
String encoded = Base64.getEncoder().encodeToString(hash);
47+
return encoded;
48+
}

java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.qhelp renamed to java/ql/src/Security/CWE/CWE-312/CleartextStorageSharedPrefs.qhelp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<qhelp>
33
<overview>
44
<p>
5-
<code>SharedPreferences</code> is an Android API that stores application preferences using simple sets of data values. Almost every Android application uses this API. It allows to easily save, alter, and retrieve the values stored in the user's profile. However, sensitive information should not be saved in cleartext. Otherwise it can be accessed by any process or user on rooted devices, or can be disclosed through chained vulnerabilities e.g. unexpected access to its private storage through exposed components.
5+
<code>SharedPreferences</code> is an Android API that stores application preferences using simple sets of data values. It allows you to easily save, alter, and retrieve the values stored in a user's profile. However, sensitive information should not be saved in cleartext. Otherwise it can be accessed by any process or user in rooted devices, or can be disclosed through chained vulnerabilities, like unexpected access to the private storage through exposed components.
66
</p>
77
</overview>
88

@@ -24,10 +24,6 @@
2424
</example>
2525

2626
<references>
27-
<li>
28-
CWE:
29-
<a href="https://cwe.mitre.org/data/definitions/312.html">CWE-312: Cleartext Storage of Sensitive Information</a>
30-
</li>
3127
<li>
3228
Android Developers:
3329
<a href="https://developer.android.com/topic/security/data">Work with data more securely</a>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @name Cleartext storage of sensitive information using `SharedPreferences` on Android
3+
* @description Cleartext Storage of Sensitive Information using
4+
* SharedPreferences on Android allows access for users with root
5+
* privileges or unexpected exposure from chained vulnerabilities.
6+
* @kind problem
7+
* @problem.severity warning
8+
* @precision medium
9+
* @id java/android/cleartext-storage-shared-prefs
10+
* @tags security
11+
* external/cwe/cwe-312
12+
*/
13+
14+
import java
15+
import semmle.code.java.security.CleartextStorageSharedPrefsQuery
16+
17+
from SensitiveSource data, SharedPreferencesEditorMethodAccess s, Expr input, Expr store
18+
where
19+
input = s.getAnInput() and
20+
store = s.getAStore() and
21+
data.flowsTo(input)
22+
select store, "'SharedPreferences' class $@ containing $@ is stored $@. Data was added $@.", s,
23+
s.toString(), data, "sensitive data", store, "here", input, "here"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: newQuery
3+
---
4+
* The query "Cleartext storage of sensitive information using `SharedPreferences` on Android" (`java/android/cleartext-storage-shared-prefs`) has been promoted from experimental to the main query pack. Its results will now appear by default. This query was originally [submitted as an experimental query by @luchua-bc](https://github.com/github/codeql/pull/4675).

java/ql/src/experimental/Security/CWE/CWE-312/CleartextStorageSharedPrefs.ql

Lines changed: 0 additions & 167 deletions
This file was deleted.

java/ql/test/experimental/query-tests/security/CWE-312/CleartextStorageSharedPrefs.expected

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)