Background
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.
Assumptions
- JS code can’t call methods on the native
ReactSecureEditText
control (where it would e.g. be able to callgetText
). Some methods have nonetheless been fortified to prevent unknown listeners from registering (e.g., inaddTextChangedListener
), and we could envision doing the same forgetText
. - 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 ReactSecureTextInputManager
/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.getText
and 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 updateExtraData
, addEventEmitters
and setOnKeyPress
have been overridden (and sealed with the final
keyword).
2. Custom classes with no reuse of RN superclasses
This approach derives SecureTextInputManager
from BaseViewManager<SecureEditText, LayoutShadowNode>
and SecureEditText
from Android’s EditText
. It still reuses some RN helper classes such as ReactViewBackgroundManager
, ReactTextInputShadowNode
or ContentSizeWatcher
. They are not huge classes so we could envision copying them as well, but some might contain dependencies that are impossible to extract.
Pros/cons
- 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.