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