description |
---|
Guidelines for creating a secure Android based SDK |
To achieve this, the SDK should clearly define the activities that can be invoked by the FIU app, for example, an activity to capture login information and another activity to capture the debit card details. The FIU app should then include these activities in its manifest file under a separate process as shown in the snippet below:
<application
...
<activity android:name=".MainActivity">
...
</activity>
<activity
android:name="com.aa.sdk.Login"
android:process=":aasdk"
/>
</application>
Notes:
- For inter-activity (process) communication, “Intent” should be used to pass data to the SDK activity by the FIU app.
- FIU app can start the activity by invoking the “startActivity()” method when the activity is not expected to return any data to the calling app.
- FIU app can start the activity by invoking the “startActivityForResult()” method when the activity is expected to return any data to the calling app.
2. The SDK should use a custom/virtual keyboard and should not rely on system keyboards to capture sensitive information
The custom keyboard can be a number only or a regular keyboard based on what information needs to be captured. This will ensure any keylogging attacks can be successfully thwarted. We see similar methods being used in banking apps like SBI YONO and UPI apps like GPay and BHIM to capture login information and **UPI **PIN.
3. The activities exposed by the SDK should disable capturing of screenshots taken either manually or programmatically.
Again this is to protect sensitive information to be captured by any outside process.
To prevent screen capturing, android provides enough security to block either screenshot or recording for that particular activity by setting the “FLAG_SECURE” attribute in the activity window. The FLAG_SECURE attribute will also exclude the activity view from google assistant, read more about it here.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE);
setContentView(R.layout.activity_main);
}
4. Make activities exposed by the SDK private so that they can’t be launched by any other application other than the FIU app that embeds it.
Hackers can try to reverse engineer the **SDK **code to find any vulnerabilities in the code or to modify its functionality or search for sensitive data hardcoded in the code.
One way to raise the bar manyfold is by obfuscating the code of SDK. Find more details about it here.
Another option is using NDK one can write sensitive portions of the code in C/C++ and compile it natively into .so files, which are much less likely to be decompiled than APKs. Reverse engineering would require the attacker to be proficient in processor architecture, assembler language, JNI Conventions, and Compiler ABI giving even a proficient attacker a few sleepless nights.
For obfuscating any string resources or an asset file, use a library like StringCare.
While storing sensitive information in variables in code like the PIN entered by the user, do not use String data type (when coding in java) instead, use a char/byte array and clear the array once it's not required anymore.
Make sure your public resources names are also unique to prevent resource merge conflicts**.**
This will help identify the source of all the calls to the AA network more reliably and also pin the source of the leak if any. Imagine a case where an FIU shares the AA SDK with another app developer who ends up misusing the AA network. In this case, we can easily find the source of the leak by looking at the API keys used to access the AA network.
- Use explicit intent to restrict receivers(If implicit intent is used, launch app chooser)
- You can also safely restrict the broadcast to a single application by using
Intent.setPackage()
- Use LocalBroadcast Manager instead of
Context.SendBroadcast
so that you don’t have to worry about leaking private data.
- Store private data within internal storage. By default, files that you create on internal storage are accessible only to your app. Android implements this protection, and it's sufficient for most applications.
- Store only non-sensitive data in cache files
- Use SharedPreferences in private mode(MODE_PRIVATE)
- Don't store sensitive information using external storage.
- Don't store sensitive information using external storage. Files created on external storage, such as SD cards, are globally readable and writable. Because external storage can be removed by the user and also modified by any application, don't store sensitive information using external storage.
An android application can have multiple activities and each activity can potentially run in a different process. Assume an FIU app has 3 activities fiu-01
, fiu-02
and fiu-03
and an AA SDK having two activities aa-01
and aa-02
. What needs to be checked is that "aa-xx" activities have an exclusive process of their own. Following APIs should be helpful to check this programmatically in the AA SDK.
- Get all activities for an application and the name of the process that hosts that activity
- Get all processes (PID and process-name) for an application
- Get current process id.
Using information from 1 and 2, we can build a dictionary of [pid to List] . Using information provided by 3, we can find the process id for the current aa activity. Using this PID of aa activity, we can look up the dictionary to find the list of activity-names running in that process and ensure that non-aa activities are not running in this process.
public class AA_Activity extends AppCompatActivity {
// ...
public static void printAllRunningActivities(Context context) {
try {
PackageInfo pi = context.getPackageManager().getPackageInfo(
context.getPackageName(), PackageManager.GET_ACTIVITIES);
ArrayList<ActivityInfo> activities = new ArrayList<>(Arrays.asList(pi.activities));
for(ActivityInfo a : activities){
System.out.println("activity name" + a.name);
System.out.println("activity process name" + a.processName);
}
} catch (PackageManager.NameNotFoundException e) {
// handle errors
}
}
}
Refer to the API Doc.
public static void printAllAppProcesses(){
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
for (ActivityManager.RunningAppProcessInfo process : processes) {
System.out.println("Process id" + process.pid);
System.out.println("Process name " + process.processName);
}
}
Refer to API Doc.
public static void printCurrentProcessId(){
System.out.println("Current Process id"+ android.os.Process.myPid());
}
Refer to the API Doc.
- Android process and application lifecycle: https://developer.android.com/guide/components/activities/process-lifecycle
- Android activity lifecycle: https://developer.android.com/reference/android/app/Activity