Flutter компонент TextField
, наверняка знакомый всем, часто используется как входной контроль для ввода данных, особенно в сценариях аутентификации, таких как ввод пароля. При этом конфигурация obscureText: true
обеспечивает зашифрованный вид вводимых данных.
При успешной авторизации страница обычно уничтожается вместе со всей связанной информацией пользователя, но действительно ли данные пароля уничтожаются?
Если вы используете TextField
для ввода паролей, то вы можете столкнуться с предупреждением безопасности типа CWE-316. Основная причина этого — Flutter хранит в памяти открытый текст введенных данных во время взаимодействия с платформой.
Для воспроизведения этой проблемы вам потребуется инструмент для чтения данных оперативной памяти вашего приложения во время его выполнения. В данном случае рекомендовано использовать apk-medit.
medit
.adb push medit /data/local/tmp/medit
для передачи исполняемого файла на устройство.adb shell
для доступа к командной строке устройства.run-as <target-package-name>
, где <target-package-name>
— это имя вашего пакета.cp /data/local/tmp/medit ./medit
для копирования исполняемого файла../medit
для запуска режима просмотра памяти.Успешно запустив инструмент, вы должны увидеть состояние готовности, показанное на следующем рисунке:Затем введите в поле ввода пароль "abcd12345" и выполните команду find abcd12345
в терминале. Вы найдете семь связанных записей в категории String
.
Следующим шагом будет очистка введенного текста с помощью контроллера TextField
, удаление текущего экрана и переход на чистый экран. После этого активируйте сборку мусора в Flutter DevTools. Наконец, снова выполните команду find abcd12345
. Результаты будут следующими:
При этом в памяти остаются еще 5 связанных данных. Выберите один адрес, например 0x7194a57b
, и выполните команду dump
: dump 0x7194a500 0x7194a5ff
. Результат показан ниже:
Эта проблема существует на многих платформах, таких как Android, iOS и Linux. Но откуда она берется? Для этого стоит рассмотреть процесс ввода текста в Flutter.
Как кросс-платформенная система, Flutter использует каналы платформы для ввода текстовых данных. Например, на Android это реализуется через систему InputConnection
.На Android, когда клавиатура хочет взаимодействовать с некоторыми View, система вызывает метод onCreateInputConnection
объекта View
, который возвращает экземпляр InputConnection
для использования клавиатурой. Разработчики могут переопределить некоторые методы InputConnection
, чтобы перехватывать ввод или реагировать на определённые ключевые события.Например, контроллер EditText
поддерживает ввод текста, поскольку его родительский класс TextView
реализует EditableInputConnection
и переопределяет метод onCreateInputConnection
объекта View
.
Аналогично, в Flutter объект
FlutterView
также переопределяет метод onCreateInputConnection
и реализует InputConnectionAdaptor
для взаимодействия. Здесь мы кратко представляем объекты, которые будут использоваться далее:
InputConnection
, используемая для взаимодействия между клавиатурой и Flutter, внутри которой содержатся объекты: TextInputChannel
, ListenableEditingState
, InputMethodManager
, KeyboardManager
и др.;MethodChannel
, которое используется для взаимодействия с Dart и выполнения некоторых логических операций;InputConnection
требует интерфейса Editable
, а это его подкласс. Внутри Android framework содержимое и состояние ввода через клавиатуру управляются через интерфейс Editable
;FlutterPlugin
, владея TextInputChannel
и InputMethodManager
для выполнения некоторых логических операций связанных с вводом. Кроме того, сам он также реализует интерфейс ListenableEditingState.EditingStateWatcher
, вызываемый при вводе текста;Представив функционал этих объектов, вернёмся к процессу ввода текста.Когда вы вводите текст с клавиатуры, введенный текст попадает в метод endBatchEdit
класса InputConnectionAdaptor
, после чего происходит следующее:- Введённый текст сохраняется в объекте ListenableEditingState
(параметр mEditable
в исходном коде);
TextInputPlugin
для форматирования данных и передачи их через TextInputChannel
;Map
и передаются в метод updateEditingState
класса TextInputClient
на стороне Dart;Map
, уровень Dart обновляет значение в объекте TextEditingValue
, что приводит к отображению введённого текста.Как видно, основной процесс заключается в том, чтобы взаимодействовать с InputConnectionAdaptor
для получения введённого текста и состояния, затем упаковывать эти данные в Map
и передавать их на уровень Dart, где они расшифровываются и отображаются.
Перейдём теперь к проблеме CWE-316. В данном случае, временно сохранённые в памяти открытые пароли находятся именно в методе TextInputClient.updateEditingState
, то есть в переданном из нативного уровня в Dart Map
. Эти данные остаются в памяти после передачи, что может привести к утечкам информации.
На самом деле, эта проблема была обсуждена в issue Flutter #84708. Хотя официальная классификация проблемы указывает на её приоритет P3, ответы свидетельствуют о том, что проблема CWE-316 скорее всего является следствием недопонимания, так как если третья сторона имеет доступ к данным устройства, то практически невозможно полностью защититься от утечек.Кроме того, анализ текущего дизайна Dart показывает, что объекты типа String
являются неизменяемыми. Как только открытый String
попадает в кучу Dart (heap
), его удаление становится неопределенным. Даже после сборки мусора (GC
) содержимое памяти остаётся нетронутым до тех пор, пока весь участок памяти не будет очищен и не будет возвращён операционной системой или заново использован для хранения нового объекта.
Дополнительно стоит отметить два аспекта работы InputConnectionAdaptor
: методы performEditorAction
и sendKeyEvent
.
IME_ACTION_GO
, IME_ACTION_SEND
, IME_ACTION_DONE
, нажимаются, то через TextInputChannel
код сразу передаётся в Dart;Поэтому, исходя из текущей версии, если используется TextField
или EditableText
, проблема с остатками данных в процессе передачи может существовать постоянно.
Конечно, если вы используете только строки вместо EditableText
, возможности Dart, такие как типизированные данные или указатели FFI, могут частично решить эту проблему.Если у вас есть какие-либо идеи относительно CWE-316 для TextField
, пожалуйста, оставьте ваши комментарии для обсуждения!
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )