Очистить строку C# из памяти

Я пытаюсь очистить содержимое памяти строки C# по соображениям безопасности. Я знаю о SecureString класс, но к сожалению я не могу использовать SecureString вместо String в моем приложении. Строки, которые необходимо очистить, создаются динамически во время выполнения (например, я не пытаюсь очистить строковые литералы).

большинство результатов поиска я нашел в основном заявил, что очистка содержимого String невозможно (поскольку строка неизменяема) и SecureString должно быть используемый.

поэтому я придумал свое собственное решение (используя небезопасный код) ниже. Тестирование показывает, что решения работают, но я все еще не уверен, что с решением что-то не так? Есть ли лучшие?

static unsafe bool clearString(string s, bool clearInternedString=false) 
{
    if (clearInternedString || string.IsInterned(s) == null)
    {
        fixed (char* c = s)
        {
            for (int i = 0; i < s.Length; i++)
                c[i] = '';
        }
        return true;
    }
    return false;
}

EDIT: из-за комментариев о GC перемещение строки вокруг до clearString вызывается: как насчет следующего фрагмента?

string s = new string('', len);
fixed (char* c = s)
{
    // copy data from secure location to s
    c[0] = ...;
    c[1] = ...;
    ...

    // do stuff with the string

    // clear the string
    for (int i = 0; i < s.Length; i++)
        c[i] = '';
}

4 ответов


ваша проблема в том, что струны могут двигаться. Если GC запускается, он может переместить содержимое в новое место, но он не будет обнулять старое. Если вы обнулили строку, о которой идет речь, у вас нет гарантии, что ее копия не существует в другом месте в памяти.

здесь ссылке сборщику мусора .NET, и он говорит о уплотнении.

изменить: вот ваша проблема с обновлением:

// do stuff with the string

проблема в том, что как только он покидает ваш контроль, вы теряете способность убедиться, что он безопасен. Если бы это было полностью под вашим контролем, у вас не было бы ограничения только использования строкового типа. Проще говоря, эта проблема существует уже давно, и никто не придумал безопасный способ справиться с этим. Если вы хотите сохранить его в безопасности, лучше всего обращаться с ним другими способами. Очистка строки предназначена для предотвращения того, чтобы кто-то мог найти ее через дамп памяти. Лучший способ остановиться если вы не можете использовать защищенную строку, ограничьте доступ к машине, на которой выполняется код.


помимо стандартного ответа "вы вступаете в небезопасную территорию", который, я надеюсь, объясняет себя, рассмотрим следующее:

среда CLR не гарантирует, что в любой заданной точке существует только один экземпляр строки, и она не гарантирует, что строки будут собраны в мусор. Если бы я сделал следующее:--2-->

var input = "somestring";
input += "sensitive info";
//do something with input
clearString(input, false);

что это? (Предположим, что я не использую строковые литералы, и это вместо входов из некоторой среды какой-то)

строка создается с содержимым "somestring". Еще одна строка создается с содержимым "конфиденциальная информация", а еще одна строка создается с содержимым"somestringsensitive info". Очищается только последняя строка: "конфиденциальная информация" - нет. Это может быть или не может быть немедленно мусор собирается.

даже если вы заботитесь о том, чтобы всегда очищать любую строку с конфиденциальной информацией, среда CLR все равно не гарантирует, что только одна экземпляр строки существует.

edit: Что касается вашего редактирования, просто закрепление строки сразу может иметь желаемый эффект - нет необходимости копировать строку в другое место или что-то еще. Вам нужно сделать это сразу после получения указанной строки, и есть еще другие проблемы безопасности, о которых нужно беспокоиться. Вы не можете гарантировать, что, например, источник строки не имеет копии в своей памяти, без четкого понимания источник и как именно он все делает.

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

кроме того, если вы передадите его другим функциям, которые вы не писали сами, он может быть скопирован или не скопирован этой функцией.


невозможно сказать, сколько функций CLR и non-CLR проходит ваша строка, прежде чем она достигнет вашей функции, где вы пытаетесь ее очистить. Эти функции (управляемые и неуправляемые) могут создавать копии строки по различным причинам (возможно, несколько копий).

вы не можете знать все эти места и очистить их все так реалистично, вы не можете гарантировать, что ваш пароль будет очищен из памяти. Вы должны использовать SecureString вместо этого, но вам нужно понять, что вышесказанное все еще применяется: в какой-то момент в вашей программе вы получите пароль, и вам придется иметь его в памяти (даже если только на короткий срок, пока вы перемещаете его в безопасную строку). Это означает, что ваша строка все равно будет проходить через цепочки вызовов функций, которые вы не контролируете.


Если вы действительно можете использовать SecureString, и вы готовы написать небезопасный код, тогда вы можете написать свой собственный простой класс строк, который использует неуправляемую память и гарантирует, что вся память обнуляется перед освобождением.

однако вы никогда не сможете гарантировать, что ваши данные безопасны, так как вы никогда не имеете полного контроля над ними. Например, вирус, встроенный достаточно глубоко, может прочитать эту память во время работы программы, и это также возможность того, что процесс завершается, и в этом случае код деструктора не запускается, оставляя данные в нераспределенной памяти, которая может быть выделена другому процессу, и она будет по-прежнему первоначально содержать ваши конфиденциальные данные; кто-то может легко использовать инструмент, такой как visual studio для мониторинга памяти отлаженного процесса, или написать программу, которая выделяет память и выполняет поиск конфиденциальных данных.