Наши приложения иногда обрабатывают конфиденциальную информацию о пользователях, такую ​​как пароли, закрытые ключи или финансовую информацию, и я предполагаю, что многие люди не задумываются над тем, чтобы использовать 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

Это ранняя версия, поэтому мы будем благодарны за все отзывы.