Как «обнулить» и обеспечить удаление строки из памяти - PullRequest
0 голосов
/ 17 марта 2020

Я понимаю основную концепцию сборки мусора, о том, что как только у определенного объекта c больше нет указателей, ссылающихся на него, он становится "сборщиком мусора".

Означает ли это, что он освобожден, но его значение все еще доступно для чтения с помощью отладчика / дизассемблера (по крайней мере, пока этот адрес не записан)?

Я знаю, что с большинством объектов (Те, кто реализует интерфейс IDisposable в C#, вы можете вызвать метод Dispose() и быть уверенным, что к памяти больше никогда не будет доступа. Но как насчет строк?

Я знаю с сборкой мусора (в iOS он известен как ARC), как только вы получаете 0 ссылок, объект «избавляется» от себя. Я беспокоюсь, что мое приложение (тонны унаследованного кода) имеет множество утечек памяти с сильными ссылками, и я не хочу, чтобы данные, чувствительные к PCI * , все еще оставались в памяти долгое время после того, как я "установил String в null". При установке строки в нулевое значение ставится нулевой завершающий символ для каждого символа в string?

Вот некоторые ссылки на некоторые исследования, которые я провел до сих пор, и я думаю, что, может быть, то, что я ищу, может быть писать / переписывать после того, как я закончу с неуправляемым мной mory:

Документы Microsoft по утилизации

Строковый маршалинг

Небезопасный код

System.String Class

TLDR:

  1. Я знаю, я могу просто установить String на null но я все еще не верю, что в моем приложении нет конфиденциальных данных, хранящихся в памяти, на которые все еще может ссылаться злоумышленник.

  2. Как вы гарантируете (надеюсь, из кода / модульных тестов), что строка никогда не будет снова ссылаться из памяти (даже со стороны злоумышленника).

Извините, если я параноик, я только что видел очень много плохого управления памятью (большая часть из глубоко внедренного стороннего фреймворка) в этой базе кода.

Ответы [ 2 ]

1 голос
/ 18 марта 2020

Я понимаю основную концепцию сборки мусора, о том, что если у определенного объекта c больше нет указателей, ссылающихся на него, он становится "сборщиком мусора".

Почти. Суть в том, что объект не собирается сразу после последней ссылки на этот объект. После того, как этот объект находится в состоянии ожидания и ожидает запуска процесса сбора мусора.

Означает ли это, что он освобожден, но его значение все еще доступно для чтения с помощью отладчика / дизассемблера (по крайней мере, пока этот адрес не будет записан)?

Да. Как я упоминал выше, освобожденные объекты все еще находятся в памяти и ждут запуска G C. Поскольку сборщик мусора не определен c, вы не знаете точно, когда сборщик мусора выполняет свою работу. Более того, вы все равно можете получить ссылку на этот объект (с помощью метода Finalize Finalize override docs link )

Я знаю, что с большинством объектов (которые реализуют интерфейс IDisposable в C# вы Можно вызвать метод Dispose () и быть уверенным, что к памяти больше никогда не будет доступа. Но как насчет строк?

Основное использование этого интерфейса - освобождение неуправляемых ресурсов Сборщик мусора автоматически освобождает память, выделенную для управляемого объекта, когда этот объект больше не используется. Используйте метод Dispose этого интерфейса для явного освобождения неуправляемых ресурсов вместе с сборщиком мусора. Утилизация управляемого Объект не означает, что этот объект является выпусками. Утилизируйте, измените только внутреннее состояние этого объекта (например, он освобождает исходную ссылку на растровое изображение), но объект остается тем же - он потребляет память, он все еще может использоваться, вы можете вызвать его методы, et c. Только G * 10 35 * удаляет объект из памяти. Таким образом, поскольку строка является управляемым объектом, она освобождается G C.

Как вы гарантируете (надеюсь, из кодовых / модульных тестов), что строка никогда не будет снова ссылаться из памяти ( даже от злонамеренного стороннего производителя).

IMO, решение состоит в том, чтобы реализовать свой собственный упаковщик строк с функцией, подобной dispose - например, после использования экземпляра этого класса оболочки и больше не требуется, вы можете вызвать метод Free (), и ваша реализация перезапишет значение базовой строки в памяти (в безопасном или небезопасном контексте). Но это требует точного управления ресурсами. Кроме того, перезапись строки должна вызываться методом Finalize () для обеспечения обнуления памяти после того, как объект был G C -ed.

0 голосов
/ 30 апреля 2020

Принял ответ @ barac340, поскольку он помог мне понять управление памятью при поиске решения.

  1. Я просто использую SecureString, используя один метод, который отправляет его по зашифрованным каналам а затем удаляет переданную SecureString.
  2. Я использую класс Marshal для перезаписи нулевых символов в каждом байте для длины байта SecureString, начиная с адреса памяти SecureString в неуправляемом Память.
  3. Затем я избавляюсь от него, освобождая кучу нулевых символов для сборки мусора. :)

Я хочу пояснить, что это известная проблема в Xamarin. iOS, что адрес памяти SecureString НЕ зашифрован в защищенной строке, поэтому даже если память освобождается для G C с использованием как есть, он все еще может быть доступен в виде простого текста посредством проверки памяти.

Я НЕ создал пользовательский класс, не потому, что он не был бы полезен для повторного использования, я только используйте это в одном месте в этом случае. И большинство моих «будущих» сценариев использования потребовало бы удаления указанной строки после первого «get» фактического String значения SecureString. Так что сейчас я просто поместил распоряжение в функцию, которая использует строку. В частности, поскольку я уже использую Marshal для чтения String, имело смысл писать в него после использования в том же методе.

Если возникнет необходимость в пользовательском классе, для чего я ' м дублируя "ExtraSecureString", я сделаю это.

...