Очистить массив во всех потоках - PullRequest
5 голосов
/ 30 июня 2019

В Java рекомендуется использовать char[] для хранения паролей или другой конфиденциальной информации, чтобы иметь возможность очищать ее вручную, когда данные больше не нужны.

Как можно очистить такой массив во всехпотоки?Если я правильно понимаю, потоки могут вносить изменения только в свой кеш, но не в общую память, поэтому следующее не будет работать надежно:

char[] password = ...
...
Arrays.fill(password, '\0');
  • Верно ли это предположение или потоки всегдазапись в общую память?
  • Необходимо ли использовать volatile (или другую синхронизацию), чтобы убедиться, что общая память обновляется?
    • Требуется ли для этого отношение произойдет до , потому что в противном случае компилятор / JVM пропустит синхронизацию памяти из-за оптимизации?
  • Есть ли другие потокидолжны установить отношение случай-до , чтобы очистить содержимое массива из их кэша, или это незначительно?Возможно, потому что кеш будет использоваться для других более часто используемых данных, а массив будет отброшен, учитывая, что он больше не используется активно.

Редактировать: утверждение, что char[] должноиспользоваться для паролей была основана на Почему символ [] предпочтительнее, чем строки паролей , однако после того, как раз, глядя на него, это тоже немного спорным.

Ответы [ 2 ]

2 голосов
/ 30 июня 2019

Создание ссылки на массив volatile не гарантирует изменчивый доступ к его содержимому.Вы можете использовать AtomicIntegerArray, если вы хотите многопоточный безопасный доступ.В противном случае вы можете захотеть обернуть ваш массив char в свой пользовательский класс с синхронизацией вокруг его методов.Хотя последний будет менее производительным.

Обратите внимание, что использование массива символов вместо строки может быть не совсем безопасным.Выгрузка памяти процесса в то время, когда ваш массив символов содержит данные, все еще возможна, если у злоумышленника есть доступ к вашей машине, и если у него есть, у вас гораздо более серьезные проблемы, чем эта.Кроме того, сборка мусора может переместить ваши данные в другое место во время фазы сжатия, оставив ваш пароль в освобожденной «мусорной» памяти, которая еще не была перезаписана (учитывая, что вы говорите об общих членах между потоками, это даже более вероятно произойдет, так как вашмассив char считается долгоживущим и копируется в области памяти, зарезервированные для объектов более старого поколения).

1 голос
/ 30 июня 2019

Я думаю, у jbx есть хороший ответ.Если у злоумышленника есть доступ к вашей основной памяти, у вас, вероятно, больше проблем, чем беспокоиться о случайной строке пароля в памяти.Беспокойство также по поводу кэша L3 кажется довольно перегруженным.

Но в интересах кода я укажу, что хотя создание массива volatile не поможет, почти любая другая форма синхронизации поможет.Все они имеют семантику, которая требует, чтобы все записи были сделаны видимыми.Таким образом, вы можете гарантировать, что изменения в массиве видны.

public class Password {

  private final char[] password;

  public Password( char[] p ) {
     password = Arrays.copy( p, p.length );
  }

  public synchronized boolean compare( char[] p ) {
      return Arrays.equal( password, p );
  }

  public synchronized clear() {
    Arrays.fill(password, 42 );
  }
}

Код не был протестирован.

Здесь я использую synchronized просто для обеспечения видимости памяти.Атомность является лишь побочным эффектом и, вероятно, не нужна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...