The safety and integrity of an application are critically dependent on how untrusted data sources are handled in secure programming. Untrusted data sources may contain malicious code, inaccurate information, or other types of flaws that pose various security threats, including code injection, data tampering, and data leakage. By ensuring that the application is deployed securely, these risks can be avoided and the application’s potential access to sensitive data can be safeguarded. Because Android apps are part of a broad, varied, and open environment, handling untrusted data is even more crucial for Android development.
Here, with an emphasis on Android programming, we will go over various techniques and best practices to handle untrusted data sources. Examples will be provided in multiple languages, including C, C++, Java, and Kotlin, and special attention will be given to the Android application development environment.
Types of Untrusted Data Sources
Before diving into how to handle untrusted data sources, it is necessary to understand the types of data sources that can be considered untrusted. Let’s have a look at some common examples:
- External storage: Files stored on external storage, such as an SD card, can be accessed by any application with the appropriate permissions. Any data originating from external storage should be treated as untrusted.
- User input: Data that originates from a user or is entered by the user should be considered untrusted, as there is no guarantee of its integrity.
- Network connections: Data obtained from servers, APIs, or other remote services can have varying levels of trustworthiness. In many cases, this data should be treated as untrusted.
- Third-party libraries: Although they might increase an application’s capabilities, external libraries can also provide unforeseen security threats. When using third-party libraries, caution should be exercised, and their data should be regarded with suspicion.
Dealing with Untrusted Data Sources
The following are some techniques and best practices for securely handling untrusted data sources:
Input validation:
At the core of handling untrusted data is validating the input coming from various sources. Input validation checks the data against a set of predefined rules and constraints that help ensure the data matches expected requirements.
For example, consider a simple Java program that handles user input:
import java.util.Scanner;
public class InputValidation {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = scanner.nextInt();
if (age < 0 || age > 120) {
System.out.println("Invalid age!");
} else {
System.out.println("Your age is: " + age);
}
scanner.close();
}
}
In this example, the user’s input is checked to ensure it is within a reasonable range (0 to 120).
Encoding and escaping data:
Properly encoding and escaping data is another essential aspect of handling untrusted data. For instance, when displaying data from an untrusted source in an HTML context, escaping the data is necessary to prevent cross-site scripting (XSS) attacks. In Android, TextViews automatically escape HTML when set using the setText method, but you can escape HTML manually using the following in Java:
String untrustedData = "<script>alert('XSS')</script>";
String escapedData = Html.escapeHtml(untrustedData);
textView.setText(escapedData);
In Kotlin:
val untrustedData = "<script>alert('XSS')</script>"
val escapedData = HtmlCompat.escapeHtml(untrustedData, HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
textView.text = escapedData
Securely storing and transmitting data:
To prevent data leakage or tampering, it’s crucial to store ans transmit data securely. For instance, using encryption can protect the stored data in SharedPreferences. In Java, the following is an example of encrypting data using AndroidX’s EncryptedSharedPreferences library:
Context context = getContext();
EncryptedSharedPreferences encryptedSharedPreferences = (EncryptedSharedPreferences) EncryptedSharedPreferences.create(
context,
"secure_prefs",
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
);
// Save encrypted data
SharedPreferences.Editor editor = encryptedSharedPreferences.edit();
editor.putString("key", "untrustedData");
editor.apply();
// Read encrypted data
String untrustedData = encryptedSharedPreferences.getString("key", "");
In Kotlin:
val context = requireContext()
val encryptedSharedPreferences = EncryptedSharedPreferences.create(
context,
"secure_prefs",
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
// Save encrypted data
val editor = encryptedSharedPreferences.edit()
editor.putString("key", "untrustedData")
editor.apply()
// Read encrypted data
val untrustedData = encryptedSharedPreferences.getString("key", "")
Limiting third-party library usage:
Nowadays, there are lots of third-party libraries available that can help add functionalities easier, faster, and cheaper. But we should be aware that by adding any new libraries, we might also add vulnerabilities as well. To reduce the potential risks, we should use and select those libraries carefully and only when it’s really necessary.
Sandboxing and isolation:
If the untrusted data needs to be processed in a potentially harmful manner, consider using an isolated environment, such as a separate process, to mitigate the risk of damage to the primary application.
It is crucial to handle untrusted data sources securely to reduce the risks that come with code injection, data tampering, and data leakage. To ensure the application and its data’s confidentiality and integrity, several precautions can be taken, such as validating input, encoding and escaping data, storing and transmitting it properly, limiting the use of third-party libraries, and sandboxing or isolating it. By keeping these best practices in mind, application developers can better protect their applications against security threats originating from untrusted data sources.
Link to Book: Secure Android Development: Best Practices for Robust Apps