Exposing sensitive data to RN is inherently insecure due to the difficulty in controlling hundreds of NPM dependencies that RN (and our app) depends upon. The most obvious target is the
TextEdit class which is used to allow the user to enter sensitive text such as passwords. The alternative to the pure RN approach is to cut out the text update notifications that contain the text being typed and reduce the attack surface area as much as possible. The research-phase project does this by using a custom-made
ReactSecureEditText class which is used in the same way as RN’s
ReactEditText (along with other supporting classes), except for setting and retrieving text contents, which are made available only to native code.
- JS code can’t call methods on the native
ReactSecureEditTextcontrol (where it would e.g. be able to call
getText). Some methods have nonetheless been fortified to prevent unknown listeners from registering (e.g., in
addTextChangedListener), and we could envision doing the same for
- JS code doesn’t need to know the contents of a secure edit box, and native code doesn’t need to be notified of changes to the edit box contents (although this particular functionality wouldn’t be hard to implement if needed).
1. Overriding RN classes
The idea is to still take advantage of
ReactEditText (overriding insecure methods and removing the insecure behavior or making the method throw an exception), and a new JS helper class
SecureTextInput (to replace
TextInput). The JS code creates
<SecureTextInput> with a
registrationID property which is used to register the native edit with
ReactSecureTextInputManager. Native code can manipulate the contents of the input fields by calling
ReactSecureTextInputManager.setText with the respective values used in
registrationID. Other JS code can’t retrieve the text from the edit field or calculate it, because
setOnKeyPress have been overridden (and sealed with the
2. Custom classes with no reuse of RN superclasses
This approach derives
BaseViewManager<SecureEditText, LayoutShadowNode> and
SecureEditText from Android’s
EditText. It still reuses some RN helper classes such as
ContentSizeWatcher. They are not huge classes so we could envision copying them as well, but some might contain dependencies that are impossible to extract.
- With method 1, the maintenance burden is much smaller, but more attention must be paid to RN upgrades, to ensure that new insecure public methods aren’t being added in the new release. The risk seems low, as that core functionality is not bound to be frequently changing, but it is still there;
- With method 2, for maintainability sake, we limit the functionality of the edit control available to JS (e.g. support for setting multi-line, placeholders, images, max length, etc.) to reduce the amount of code that must be copied over from RN and later maintained. It can therefore easily happen that a
<SecureTextInput>looks or behaves slightly different from other
<TextInput>controls, as it might be lacking some support code from RN.