cordovacordova-pluginscrosswalkcordova-plugin-proguard

cordova-plugin-crosswalk-webview - Logging all UI interaction - including sensitive data


This is an edited question - have got to the root of the problem so have added my own answer. Logcat was was outputting nearly every interaction with the UI, including what was typed our a password box (start of the word "password" highlighted with **):

D/cr_Ime  (10392): [ImeAdapter.java:313] showSoftKeyboard
D/cr_Ime  (10392): [InputMethodManagerWrapper.java:47] showSoftInput
D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [] [0 0] [-1 -1] [true]
D/cr_Ime  (10392): [ImeAdapter.java:387] dispatchKeyEvent: action [0], keycode [44]
D/cr_Ime  (10392): [AdapterInputConnection.java:393] sendKeyEvent [0] [44] [112]
D/cr_Ime  (10392): [AdapterInputConnection.java:239] updateSelectionIfRequired [1 1] [-1 -1]
D/cr_Ime  (10392): [InputMethodManagerWrapper.java:74] updateSelection: SEL [1, 1], COM [-1, -1]
D/cr_Ime  (10392): [ImeAdapter.java:253] updateKeyboardVisibility: type [2->2], flags [66], show [false], 
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [p] [1 1] [-1 -1] [false]
D/cr_Ime  (10392): [ImeAdapter.java:387] dispatchKeyEvent: action [1], keycode [44]
D/cr_Ime  (10392): [AdapterInputConnection.java:393] sendKeyEvent [1] [44] [112]
D/cr_Ime  (10392): [ImeAdapter.java:387] dispatchKeyEvent: action [0], keycode [29]
D/cr_Ime  (10392): [AdapterInputConnection.java:393] sendKeyEvent [0] [29] [97]
D/cr_Ime  (10392): [AdapterInputConnection.java:239] updateSelectionIfRequired [2 2] [-1 -1]
D/cr_Ime  (10392): [InputMethodManagerWrapper.java:74] updateSelection: SEL [2, 2], COM [-1, -1]
D/cr_Ime  (10392): [ImeAdapter.java:253] updateKeyboardVisibility: type [2->2], flags [66], show [false], 
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [•a] [2 2] [-1 -1] [false]
D/cr_Ime  (10392): [ImeAdapter.java:387] dispatchKeyEvent: action [1], keycode [29]
D/cr_Ime  (10392): [AdapterInputConnection.java:393] sendKeyEvent [1] [29] [97]
D/cr_Ime  (10392): [ImeAdapter.java:387] dispatchKeyEvent: action [0], keycode [47]
D/cr_Ime  (10392): [AdapterInputConnection.java:393] sendKeyEvent [0] [47] [115]
D/cr_Ime  (10392): [AdapterInputConnection.java:239] updateSelectionIfRequired [3 3] [-1 -1]
D/cr_Ime  (10392): [InputMethodManagerWrapper.java:74] updateSelection: SEL [3, 3], COM [-1, -1]
D/cr_Ime  (10392): [ImeAdapter.java:253] updateKeyboardVisibility: type [2->2], flags [66], show [false], 
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [••s] [3 3] [-1 -1] [false]

In the mix sendKeyEvent is also outputting the ASCII/UTF code of the keypress. This is happening on both a Genymotion emulated device and an actual device - both using a release apk. In release mode this behaviour is even more stark- just the **'d log entries above are outputted, making it really easy to see what the password is:

**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [p] [3 3] [-1 -1] [false]
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [•a] [3 3] [-1 -1] [false]
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [••s] [3 3] [-1 -1] [false]
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [•••s] [3 3] [-1 -1] [false]
**D/cr_Ime  (10392): [AdapterInputConnection.java:174] updateState [••••s] [3 3] [-1 -1] [false]

Etc...


Solution

  • After a fair bit of digging, the logging is happening somewhere between the crosswalk core & chromium native code, which seems to be unaffected by the logging levels you set in the Cordova configuration etc. The solution is to use ProGuard to remove the references to the android logging methods by specifying that it is safe to remove all calls to those methods. The suggested config to do this is:

     -keep class ** { *; }
     #Remove the logging classes - do not remove e, this has security implications...
     -assumenosideeffects class android.util.Log {
         public static *** d(...); 
         public static *** w(...); 
         public static *** v(...); 
         public static *** i(...); 
    } 
    

    The -keep class ** { *; } more or less keeps all classes - YMMV, you might want a more aggressive clean up to lower your APK size.

    Important Note

    Online help suggests using the default proguard-android.txt config alongside your custom config. In most circumstances this is good advice but unfortunately for this use case it includes the flag -dontoptimize, that disables the -assumenosideeffects clause we need to remove logging. This was unexpected and caused a lot of difficulties - I'm new to this stuff and couldn't work out what I was "getting wrong" in our custom config, whereas the config I was testing was disabled by default.

    To get round this I removed the reference to the default Proguard config from the build .gradle:

    android {
        buildTypes {
            release {        
                minifyEnabled = true
                // Original line with our custom proguard-android.pro for reference:
                // proguardFile getDefaultProguardFile('proguard-android.txt'), 'proguard-android.pro'
                proguardFiles 'proguard-android.pro'
            }
        }
    }
    

    Next I copied the contents of the default Proguard file and pasted into the start of our custom one, removing the offending -dontoptimize flag.