5

I'm a software engineer building an Android App that will be used by a government agency.

One requirement in our contract is that the app must be FIPS 140 compliant. https://en.wikipedia.org/wiki/FIPS_140

To be FIPS compliant our app must zeroize and clear any password objects in RAM, when the android app is closed. (By zeroing and clearing the password from RAM, we reduce the window of opportunity for attackers. i.e. this mitigates cold-boot attack risk: https://en.wikipedia.org/wiki/Cold_boot_attack)

To satisfy this requirement, we initially followed the advice in the following two SO posts to capture the user password as a CharArray instead of a string

//First collect the password from Edit Text as a []char
int pl = passwordEditText.length();
char[] password = new char[pl];
passwordEditText.getText().getChars(0, pl, password, 0);

//Now set the password on viewmodel
viewModel.setPassword(password) 

Once we have the password, we use it to call a 3rd party webservice library that fetches data for display on the screen.

ViewModel pseudocode:

public DataObject getData(char[] password){
     return this.webService.getData(password);
}

When the user is done with our app, we call the following method to zeroize and clear the password

ViewModel pseudocode:

public zeroPassword(){
    Arrays.fill(this.password, 0);
    this.password = null;
}

This is all fine and dandy because char arrays in java are passed by reference (unlike Strings that are immutable), and we effectively zeroize any trace of the password character array from memory in the zeroPassword method.

HOWEVER...

We dug into the 3rd party WebService code (this.webService.getData(password)) and it turns out that under the covers, the webservice converts the char array password into a string, and then passes it around before making a network call.

Basically - Even though we zeroize the char array reference in our Android ViewModel code, because the char array is taken by a 3rd party lib and used to create a string, the Password will still exist in memory :(

OPTIONS

At this point we're considering two options:

  1. Option 1 is to get a copy of the third party library and modify it so that it doesn't work with password strings. This way we can change any password string usage to use char arrays, buffers etc - all objects that we can zeroize at some point)
  2. Option 2 - We investigate some way to zeroize and clear all memory pages used by our android app (i.e. shut down the whole app and clear RAM), when the user closes the app.

As a team we prefer option 2 because it would cover all of our bases. Option 1 will be challenging, invasive, time consuming, and messy.

UPDATE - Based on the answer here, it seems like Option 1 wont even actually work How can I ensure the destruction of a String object in Java? Java uses generational garbage collection, and copies objects all over the place, even char arrays, so zeroing char arrays isn't guaranteed to remove the password from RAM.

Is there a way to accomplish what we've been asked to do? i.e. fully wipe any trace of the password from memory?

Can android security experts please opine?

Thanks

Parzie
  • 210
  • 1
  • 12
  • I'm not sure if this is helpful or know the implementation details, but is it possible you could take advantage of c? https://stackoverflow.com/questions/18205330/how-to-access-values-from-c-to-java-in-android Potentially, you could save the password here and then clear the variable holding the password from the c code once you're done with it. – MikeOscarEcho Mar 06 '20 at 20:37

2 Answers2

0

According to ViewModel Docs:

When the owner activity is finished, the framework calls the ViewModel objects's onCleared() method so that it can clean up resources.

You don't need to manually create/call destructor to clean up ViewModel resources, because this lifecycle component already has a mechanism to clean-up its own resources.

To make it easier to understand, ViewModel has the following behavior:

  • When Activity is re-created on configuration changes: we still have the same ViewModel instance.

  • When Activity is finished: ViewModel will automatically call onCleared() to cleanup resources for us, so we don’t even have to do manual unbind/clean-up.

The reason why some ViewModel object still exist in the memory is because the Activity (which has the ViewModel) is still active, OR there might be another class which holds reference to this Activity.

Harry Timothy
  • 1,148
  • 8
  • 17
  • Thanks for the details @herrytmthy. ViewModel onCleared() will certainly release any objects from memory. However, it would not necessarily zero any objects. i.e. if an attacker were to access the device RAM, after Viewmodel onCleared, there may still be copies of the password that the attacker could view. – Parzie Mar 05 '20 at 19:27
  • 1
    @Parzie AFAIK, as there is no such thing as destructor in Java, there is no workaround to completely zero every instances in every cases. I had the same experience once when the Penetration Tester said about copies of password in RAM. **SOLUTION**: That is when Cryptography came to rescue. If you are afraid of the readability, then don't keep reference of any confidential information before you encode/encrypt it. A very simple solution :) – Harry Timothy Mar 06 '20 at 07:49
0

Using V8 to run a service worker at app shutoff, for example something like:

addEventListener("fetch", event => {
    event.respondWith(fetchAndReplace(event.request));
});
async function fetchAndReplace(request) {
    const response = await fetch(request);
    let type = response.headers.get("Content-Type") || "";
    if (!type.startsWith("application/")) {
        return response;
    }

    let newHeaders = new Headers(response.headers);

    newHeaders.set('Clear-Site-Data', '"cache", "cookies",  "storage",  
    "executionContexts"');

    return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: newHeaders
    });
}

See Clear-Site-Data on MDN. "Site" is misleading as "site" ~= only websites.

intr0
  • 61
  • 1
  • 3