CodeQL 文档

使用 SharedPreferences 在 Android 上对敏感信息进行明文存储

ID: java/android/cleartext-storage-shared-prefs
Kind: problem
Security severity: 7.5
Severity: warning
Precision: medium
Tags:
   - security
   - external/cwe/cwe-312
Query suites:
   - java-security-extended.qls
   - java-security-and-quality.qls

点击以在 CodeQL 存储库中查看查询

SharedPreferences 是一个 Android API,它使用简单的数据值集存储应用程序首选项。它使您可以轻松保存、更改和检索存储在用户个人资料中的值。但是,不应以明文形式保存敏感信息。否则,任何进程或植根设备中的用户都可以访问它,或者可以通过链接的漏洞(如通过公开组件意外访问私有存储)来公开它。

建议

使用 EncryptedSharedPreferences API 或其他加密算法来存储敏感信息。

示例

在第一个示例中,敏感用户信息以明文形式存储。

在第二个和第三个示例中,代码在将敏感信息保存到设备之前对其进行加密。

public void testSetSharedPrefs(Context context, String name, String password)
{
	{
		// BAD - sensitive information saved in cleartext.
		SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
		Editor editor = sharedPrefs.edit();
		editor.putString("name", name);
		editor.putString("password", password);
		editor.commit();
	}

	{
		// GOOD - save sensitive information encrypted with a custom method.
		SharedPreferences sharedPrefs = context.getSharedPreferences("user_prefs", Context.MODE_PRIVATE);
		Editor editor = sharedPrefs.edit();
		editor.putString("name", encrypt(name));
		editor.putString("password", encrypt(password));
		editor.commit();
	}

	{
		// GOOD - sensitive information saved using the built-in `EncryptedSharedPreferences` class in androidx.
		MasterKey masterKey = new MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
			.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
			.build();

		SharedPreferences sharedPreferences = EncryptedSharedPreferences.create(
			context,
			"secret_shared_prefs",
			masterKey,
			EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
			EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM);

		SharedPreferences.Editor editor = sharedPreferences.edit();
		editor.putString("name", name);
		editor.putString("password", password);
		editor.commit();
	}
}

private static String encrypt(String cleartext) throws Exception {
	// Use an encryption or hashing algorithm in real world. The demo below just returns its
	// hash.
	MessageDigest digest = MessageDigest.getInstance("SHA-256");
	byte[] hash = digest.digest(cleartext.getBytes(StandardCharsets.UTF_8));
	String encoded = Base64.getEncoder().encodeToString(hash);
	return encoded;
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私