Наши приложения иногда обрабатывают конфиденциальную информацию о пользователях, такую как пароли, закрытые ключи или финансовую информацию, и я предполагаю, что многие люди не задумываются над тем, чтобы использовать String
для этих целей.
Дело против String
фактически сводится к его наиболее бесценной особенности; неизменность. Невозможно стереть String
перед тем, как вы освободите эту последнюю ссылку на него и предоставите сборщику мусора выполнять свою работу. Это означает, что содержимое этого String
может оставаться в куче еще долго после того, как вы закончите с ним.
Вредоносному ПО, работающему вместе с вашим Java-процессом, достаточно запустить jmap
https://stackoverflow.com/a/3042463/360211, чтобы выгрузить кучу вашего процесса и извлечь из нее строковые данные.
Строки неизменяемы. Это означает, что после создания
String
, если другой процесс может выгружать память, вы не сможете (кроме отражения) избавиться от данных до того, как начнется сборка мусора. - Джон Скит
Вот почему char[]
- распространенное решение. Вы можете очистить char[]
после того, как закончите с ним, что минимизирует временное окно атаки https://stackoverflow.com/a/8881376/360211, но атака все еще возможна.
Другая потенциальная проблема как String
, так и char[]
(и вообще любого решения с управляемыми объектами) заключается в том, что они могут перемещаться в куче сборщиком мусора, когда он пытается объединить поколения памяти. Как указывает Джон Скит в своем ответе, который был связан ранее, зависит от реализации, будет ли старая копия обнулена сборщиком мусора или наши конфиденциальные данные останутся в куче, несмотря на все наши усилия с achar[]
.
Другая атака заключается в том, что программа выделяет большой объем оперативной памяти и анализирует строки, пытаясь найти данные, оставшиеся от предыдущей программы, запущенной по этому адресу памяти.
По этим причинам у нас должен быть способ минимизировать эффективность окна этих векторов атак и минимизировать временное окно, в котором они могут возникать, и это должно быть легко или, по крайней мере, не намного сложнее, чтобы люди могли его использовать.
Идеальное решение
- Разрешить очистку строковых данных, когда мы закончим
- Запретить перемещение / копирование данных GC
- Обфускируйте эти данные, чтобы они не были видны в дампе памяти.
Разрешить очистку строковых данных, когда мы закончим
Это позволит любой тип буфера чтения / записи. Нам просто нужно держаться подальше от String
.
Запретить перемещение / копирование данных GC
Нам нужен буфер, который не контролируется сборщиками мусора. Это гарантирует, что несколько копий не могут остаться после того, как мы закончили с ним.
Для этого мы можем использовать ByteBuffer.allocateDirect
. В документации для https://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html говорится только о прямом буфере может существовать вне управляемой кучи, но это, по крайней мере, закрепленная память, поскольку они безопасны для ввода-вывода с кодом, отличным от JVM, поэтому GC не будет перемещать этот буфер и делать копии.
Скрыть данные
Вы можете использовать любой вид обфускации по своему желанию, но в идеале должна иметься возможность деобфускации по одному символу за раз. Если выбранный вами метод требует деобфускации всех символов одновременно, тогда память будет содержать все символы в виде обычного текста одновременно, что приведет к отмене нашей хорошей работы.
Один простой способ добиться этого - использовать xor с достаточно большим ключом. См. Https://en.wikipedia.org/wiki/XOR_cipher.
Если вы выбираете случайный ключ данных, по крайней мере, такой же длинный, как и данные, злоумышленник должен найти как ключ, так и запутанные данные, чтобы прочитать сообщение.
Если бы мы могли сохранить ключ в секрете, это был бы невзламываемый метод шифрования, но помните, что у нас есть и ключ, и данные в памяти, поэтому будет справедливо сказать, что это просто запутывание.
SecureCharBuffer
Итак, к счастью, я проделал для вас эту базовую обфускацию. SecureCharBuffer
позволяет легко набирать символы и читать. Он разделяет данные на два неуправляемых буфера и реализуетClosable
, поэтому их можно использовать в try
с ресурсами.
Https://github.com/novacrypto/SecureString
Это ранняя версия, поэтому мы будем благодарны за все отзывы.