Безопасное использование String для паролей с использованием отражения для содержимого скраба до сбора мусора

Использует ли отражение для очистки String с помощью String безопасно использовать char[] для паролей?

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

Однако char[] не так удобен, как String, поэтому было бы удобно, если бы можно было "скрасить" String при необходимости, тем самым сделав String безопасным, как char[].

Ниже приведен метод, который использует отражение для обнуления полей String.

Является ли этот метод "ОК" и позволяет ли он сделать String безопаснее, чем char[] для паролей?

public static void scrub(String str) throws NoSuchFieldException, IllegalAccessException {
    Field valueField = String.class.getDeclaredField("value");
    Field offsetField = String.class.getDeclaredField("offset");
    Field countField = String.class.getDeclaredField("count");
    Field hashField = String.class.getDeclaredField("hash");
    valueField.setAccessible(true);
    offsetField.setAccessible(true);
    countField.setAccessible(true);
    hashField.setAccessible(true);
    char[] value = (char[]) valueField.get(str);
    // overwrite the relevant array contents with null chars
    Arrays.fill(value, offsetField.getInt(str), countField.getInt(str), '\0');
    countField.set(str, 0); // scrub password length too
    hashField.set(str, 0); // the hash could be used to crack a password
    valueField.setAccessible(false);
    offsetField.setAccessible(false);
    countField.setAccessible(false);
    hashField.setAccessible(false);
}

Вот простой тест:

String str = "password";
scrub(str);
System.out.println('"' + str + '"');

Вывод:

""

Примечание.. Вы можете предположить, что пароли не являются константами String, и поэтому вызов этого метода не окажет отрицательного влияния на интернированные строки.

Кроме того, я оставил метод довольно "сырым" состоянием для простоты. Если бы я использовал его, я бы не объявил исключений (try/catch/ignoring them) и повторил повторный код.

Ответ 1

Существуют две потенциальные проблемы безопасности:

  • Строка может совместно использовать свой базовый массив с другими строками; например если String был создан путем вызова substring на более крупном String. Поэтому, когда вы обнуляете весь массив value, вы можете перезаписать состояние других строк..., которые не содержат паролей.

    Излечим только нулевую часть массива поддержки, которая используется в строке пароля.

  • JLS (17.5.3) предупреждает, что эффекты использования отражения для изменения переменных final составляют undefined.

    Однако контекст для этого - модель памяти Java и тот факт, что компилятору разрешено агрессивно кэшировать переменные final. В этом случае:

    • вы ожидаете, что строка будет ограничена потоком, а

    • вам больше не следует использовать какие-либо из этих переменных.

Я бы не ожидал, что любая из них станет реальными проблемами... modulo фиксирует чрезмерно агрессивное обнуление value.


Но настоящая проблема - Velociraptors.: -)


Я озадачен тем, что на самом деле вы пытаетесь переустановить пароли, подобные этому. Когда вы думаете об этом, то, что вы защищаете, это возможность того, что кто-то может читать память процесса... или ядро ​​дампа или файл подкачки... для получения паролей. Но если кто-то может это сделать, ваша системная безопасность должна быть уже скомпрометирована... cos "эти вещи, скорее всего, требуют доступа root (или эквивалента). И если у них есть доступ к root, они могут" отлаживать" вашу программу и ловить пароли до того, как ваше приложение закроет их.

Ответ 2

Один аргумент, который я имею против String, заключается в том, что слишком просто непреднамеренно сделать копию. Безопасное использование строк возможно в теории, но вся экосистема библиотеки основана на предположении, что вполне нормально копировать строки. В конце концов, учитывая все ограничения, строки могут быть не такими удобными для этого случая использования, как обычно.