Guidelines for creating a secure SDK for Account Aggregator Clients
Sahamati would like to thank Team Repute (Raviteja Sriram, Deepak Dhar, Puneet Gupta and other team members) and our security experts (Saurabh Panjwani, Sumit Gwalani, SasiKumar Ganesan) for volunteering with us on developing the guidelines.
Account Aggregators can provide their client-facing apps via a website client, mobile app or SDK (software development kit). SDKs give a consistent mobile experience customized to the users of the particular app, this will in turn improve app retention. SDKs will play an important role in increasing the adoption and usage of Account Aggregator clients.
AA SDKs are expected to be embedded in thousands of mobile apps. It becomes vital to ensure the security part of the SDK is addressed. This document lists general guidelines for creating a secure SDK for the Android app.
These guidelines have to be implemented in the account aggregator (AA) ecosystem by AAs that offer SDKs as AA Clients, which can be embedded into third-party apps (such as Financial Information User/FIU apps).
The AA SDK should be able to capture information in a secure manner without exposing the information captured to the embedding FIU app.
Please follow the guidelines provided in this document to make sure you are leveraging all the security features built into the Android platform.
Guidelines
1. Run the SDK out of process to ensure SDK does not share memory space with the FIU app.
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. 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>
Note
- 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 “startActivity()” method when the activity is not expected to return any data back to the calling app.
- FIU app can start the activity by invoking “startActivityForResult()” method when the activity is expected to return any data back 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 to capture numerical information like PIN, last 6 digits of debit card and debit card expiry date, etc. 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 BHIM, Paytm, PhonePe to capture login information and UPI PIN.
3. The activities exposed by the SDK should disable the 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.
5. Make sure your release artifact doesn’t contain any logs that output-sensitive information. We cannot stress enough how important this step is.
6. 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. It is important to prevent reverse engineering of the SDK code.
One way to raise the bar many folds is by obfuscating the code of SDK. You can find more details about obfuscating your code 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.
7. Keep resources private because all public resources are accessible outside your library. Make sure your public resources names are also unique to prevent resource merge conflicts. For more details check here.
8. AA’s should be able to distinguish traffic from FIU1 vs FIU2 to monitor the traffic from each FIU. One way to do this is by having separate API keys used for SDKs shared with different FIUs.
We can also think of other ways of achieving this, for example, each AA request can carry a signature of the embedded FIU. The AA can then verify the signature and attribute the call to the right FIU and if the FIU is not authorized on the AA network, the request can be rejected.
9. Do not broadcast sensitive information using an implicit intent.
- 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
10. Store data safely
- 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) and/or use encrypted shared preferences.
- Don’t store sensitive information using external storage or use file based encryption. 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.
How to Ensure AA SDK is Running Out of Process
An android application can have multiple activities and each activity can potentially run in a different process. Assume an FIU app having 3 activities fiu-01, fiu-02 and fiu-03 and a 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 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<activity-name>]. 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) {
//
}
}
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
Read more about the Android process and application lifecycle here. Read more about the Android activity lifecycle here.
Note: For this approach to work, one needs to also ensure two apps are not sharing the same sharedUserId and process. To achieve this make sure that the FIU app has not set sharedUserID in the manifest. The following code snippet can help in achieving this.
public String getSharedUserId(Context context){
return context.getPackageManager().getPackageInfo(
getApplicationContext().getPackageName(),
PackageManager.GET_META_DATA).sharedUserId)
}
Refer to the API Doc
The above API that gives access to package information can also be used to read details about services and activities defined in the FIU app and ensure that these services and activities do not share process space with the android SDK.
If you have any suggestions or feedback to give related to these guidelines, please feel free to contact us.
References
- Android App security best practices
- Android Application Secure Design/Secure Coding Guidebook – Secure Coding Working Group, Japan Smartphone Security Association(JSSEC)
- Android Secure Coding Standard – Carnegie Mellon University
- SafetyNet Verify Apps API