Почему char предпочитает использовать String для паролей?

В Swing поле пароля имеет getPassword() (возвращает char[] ) вместо обычного getText() (возвращает String ). Точно так же я столкнулся с предложением не использовать String для обработки паролей.

Почему String создает угрозу безопасности при использовании паролей? Это неудобно использовать char[] .

Строки неизменяемы . Это означает, что после того, как вы создали String , если другой процесс может сбрасывать память, нет никакого способа (кроме отражения ), вы можете избавиться от данных до того, как начнется garbage collection .

С помощью массива вы можете явно стереть данные после того, как вы закончите с ним. Вы можете переписать массив всем, что угодно, и пароль не будет присутствовать нигде в системе, даже до сбора мусора.

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

Как отмечено в комментариях, возможно, что массивы, перемещаемые сборщиком мусора, оставят в памяти остаточные копии данных. Я считаю, что это специфично для реализации – сборщик мусора может очистить всю память, как есть, чтобы избежать такого рода вещей. Даже если это так, еще есть время, в течение которого char[] содержит фактические символы в качестве windows атаки.

Хотя другие предложения здесь выглядят действительно, есть еще одна веская причина. С простой String вас гораздо больше шансов случайно распечатать пароль для журналов , мониторов или какого-то другого небезопасного места. char[] менее уязвим.

Учти это:

 public static void main(String[] args) { Object pw = "Password"; System.out.println("String: " + pw); pw = "Password".toCharArray(); System.out.println("Array: " + pw); } 

Печать:

 String: Password Array: [[email protected] 

Чтобы процитировать официальный документ, руководство по архитектуре криптографии Java говорит об char[] и String (о шифровании на основе паролей, но это, в основном, касается паролей, конечно):

Казалось бы логичным собирать и хранить пароль в объекте типа java.lang.String . Однако вот оговорка: Object s типа String неизменяемы, т. Е. Нет определенных методов, которые позволят вам изменить (переписать) или обнулить содержимое String после использования. Эта функция делает объекты String непригодными для хранения конфиденциальной информации, такой как пароль пользователя. Вы всегда должны собирать и хранить секретную информацию безопасности в массиве char .

В Руководстве 2-2 «Руководства по безопасному кодированию для языка программирования Java» в версии 4.0 также говорится о чем-то подобном (хотя он первоначально находится в контексте ведения журнала):

Руководящий принцип 2-2: не регистрировать высокочувствительную информацию

Некоторая информация, такая как номера социального страхования (SSN) и пароли, очень чувствительна. Эта информация не должна храниться дольше, чем необходимо, и там, где она может быть видна даже администраторами. Например, его нельзя отправлять в лог-файлы, и его присутствие не должно обнаруживаться при поиске. Некоторые временные данные могут храниться в изменяемых структурах данных, таких как массивы символов, и очищаться сразу после использования. Очистка структур данных снижает эффективность типичных систем времени исполнения Java, поскольку объекты переносятся в памяти прозрачно программисту.

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

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

Некоторые люди считают, что вам нужно перезаписать память, используемую для хранения пароля, как только она вам больше не понадобится. Это уменьшает время, которое атакующий должен прочитать пароль из вашей системы и полностью игнорирует тот факт, что злоумышленнику уже достаточно нужен доступ, чтобы захватить JVM-память для этого. Злоумышленник с таким доступом может поймать ваши ключевые события, делая это совершенно бесполезным (AFAIK, поэтому, пожалуйста, поправьте меня, если я ошибаюсь).

Обновить

Благодаря комментариям я должен обновить свой ответ. По-видимому, есть два случая, когда это может добавить (очень) незначительное улучшение безопасности, поскольку это сокращает время, когда пароль может приземлиться на жесткий диск. Тем не менее, я думаю, что это слишком много для большинства случаев использования.

  • Ваша целевая система может быть плохо сконфигурирована, или вы должны предположить, что она есть, и вы должны быть параноидальными в отношении дампов ядра (может быть действительным, если системы не управляются администратором).
  • Ваше программное обеспечение должно быть слишком параноидальным, чтобы предотвратить утечку данных, когда злоумышленник получает доступ к аппаратным средствам – используя такие вещи, как TrueCrypt (прекращено), VeraCrypt или CipherShed .

Если возможно, отключение дампов ядра и файла подкачки позаботится обо всех проблемах. Тем не менее, они потребуют прав администратора и могут уменьшить функциональность (меньше памяти для использования) и вытащить ОЗУ из работающей системы, все равно будет актуальной проблемой.

  1. Строки неизменны в Java, если вы храните пароль как обычный текст, он будет доступен в памяти до тех пор, пока сборщик мусора не очистит его, и поскольку строки используются в пуле String для повторного использования, существует довольно высокая вероятность того, что он останется в памяти надолго продолжительность, представляющая угрозу безопасности. Поскольку любой, у кого есть доступ к дампу памяти, может найти пароль в виде открытого текста
  2. Рекомендация Java с использованием getPassword() JPasswordField, который возвращает метод char [] и устаревший getText() который возвращает пароль в ясном тексте с указанием причины безопасности.
  3. toString () всегда существует риск печати обычного текста в файле журнала или консоли, но если вы используете Array, вы не будете печатать содержимое массива, а его память будет распечатана.

     String strPwd = "passwd"; char[] charPwd = new char[]{'p','a','s','s','w','d'}; System.out.println("String password: " + strPwd ); System.out.println("Character password: " + charPwd ); 

    Строковый пароль: passwd

    Пароль персонажа: [C @ 110b2345

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

Я не думаю, что это правильное предложение, но я могу по крайней мере догадаться по этой причине.

Я считаю, что мотивация заключается в том, что вы можете быстро и с уверенностью стереть все следы пароля в памяти и после его использования. С помощью char[] вы можете перезаписать каждый элемент массива пустым или что-то точно. Вы не можете редактировать внутреннее значение String таким образом.

Но это одно не является хорошим ответом; почему бы не просто убедиться, что ссылка на char[] или String не исчезает? Тогда нет проблем с безопасностью. Но дело в том, что объекты String могут быть intern() в теории и поддерживаться в постоянном пуле. Я полагаю, что использование char[] запрещает эту возможность.

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

Я имею в виду, например, class PrivateKey . Рассмотрим сценарий, в котором вы бы загрузили частный ключ RSA из файла PKCS # 12, используя его для выполнения некоторой операции. Теперь в этом случае обнюхивание пароля само по себе не поможет вам, пока физический доступ к ключевому файлу будет надлежащим образом ограничен. Как атакующий, вам будет намного лучше, если вы получите ключ напрямую, а не пароль. Желаемая информация может быть утечка много, дампы ядра, сеанс отладчика или файлы подкачки – вот лишь некоторые примеры.

И, как оказалось, нет ничего, что PrivateKey бы очистить личную информацию PrivateKey из памяти, потому что нет API, который позволяет стереть байты, которые формируют соответствующую информацию.

Это плохая ситуация, поскольку в этом документе описывается, как это обстоятельство может быть потенциально использовано.

Например, библиотека OpenSSL перезаписывает критические разделы памяти перед тем, как освободить секретные ключи. Поскольку Java собирает мусор, нам нужны явные методы для очистки и аннулирования личной информации для Java-ключей, которые должны применяться сразу же после использования ключа.

Как утверждает Джон Скит, нет никакого способа, кроме как использовать reflection.

Однако, если reflection является для вас вариантом, вы можете это сделать.

 public static void main(String[] args) { System.out.println("please enter a password"); // don't actually do this, this is an example only. Scanner in = new Scanner(System.in); String password = in.nextLine(); usePassword(password); clearString(password); System.out.println("password: '" + password + "'"); } private static void usePassword(String password) { } private static void clearString(String password) { try { Field value = String.class.getDeclaredField("value"); value.setAccessible(true); char[] chars = (char[]) value.get(password); Arrays.fill(chars, '*'); } catch (Exception e) { throw new AssertionError(e); } } 

при запуске

 please enter a password hello world password: '***********' 

Примечание: если символ char [] был скопирован как часть цикла GC, есть вероятность, что предыдущая копия находится где-то в памяти.

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

Edit: Возвращаясь к этому ответу после года исследований в области безопасности, я понимаю, что это приводит к довольно неудачным последствиям, что вы когда-либо сравнивали бы пароли открытого текста. Пожалуйста, не надо. Используйте безопасный односторонний hash с солью и разумное количество итераций . Подумайте о том, как использовать библиотеку: этот материал трудно понять!

Исходный ответ: Как насчет того факта, что String.equals () использует оценку короткого замыкания и поэтому уязвим для временной атаки? Это может быть маловероятно, но теоретически вы можете сравнить время с паролем, чтобы определить правильную последовательность символов.

 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; // Quits here if Strings are different lengths. if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; // Quits here at first different character. while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; } 

Еще несколько ресурсов по временным атакам:

  • Урок времени при атаках
  • Дискуссия о тайминговых атаках на Exchange Stack Exchange
  • И, конечно, страница Википедии с временной привязкой

Это все причины, нужно выбрать char [] array вместо String для пароля.

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

2. Сама Java рекомендует использовать метод getPassword () JPasswordField, который возвращает метод char [] и устаревший метод getText (), который возвращает пароль в открытом тексте с указанием причины безопасности. Хорошо следовать рекомендациям команды Java и придерживаться стандарта, а не идти против него.

3. При использовании String всегда существует риск печати обычного текста в файле журнала или консоли, но если вы используете Array, вы не будете печатать содержимое массива, а его память будет распечатана. хотя и не настоящая причина, но все же имеет смысл.

  String strPassword="Unknown"; char[] charPassword= new char[]{'U','n','k','w','o','n'}; System.out.println("String password: " + strPassword); System.out.println("Character password: " + charPassword); String password: Unknown Character password: [[email protected] 

Ссылка на: http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html Надеюсь, это поможет.

Нет ничего, что массив char дает вам vs String, если вы не очистите его вручную после использования, и я не видел, чтобы кто-то действительно делал это. Поэтому для меня предпочтение char [] vs String немного преувеличено.

Взгляните на широко используемую библиотеку Spring Security здесь и спросите себя: парни Spring Security некомпетентные или char [] пароли просто не имеют большого смысла. Когда какой-то неприятный хакер захватывает память вашей памяти, убедитесь, что она получит все пароли, даже если вы используете сложные способы скрыть их.

Тем не менее, Java все время меняется, и некоторые страшные функции, такие как функция дедупликации строк в Java 8, могут нести объекты String без вашего ведома. Но это разные разговоры.

Strings are immutable and cannot be altered once they have been created. Creating a password as a string will leave stray references to the password on the heap or on the String pool. Now if someone takes a heap dump of the Java process and carefully scans through he might be able to guess the passwords. Of course these non used strings will be garbage collected but that depends on when the GC kicks in.

On the other side char[] are mutable as soon as the authentication is done you can overwrite them with any character like all M’s or backslashes. Now even if someone takes a heap dump he might not be able to get the passwords which are not currently in use. This gives you more control in the sense like clearing the Object content yourself vs waiting for the GC to do it.

The short and straightforward answer would be because char[] is mutable while String objects are not.

Strings in Java are immutable objects. That is why they can’t be modified once created, and therefore the only way for their contents to be removed from memory is to have them garbage collected. It will be only then when the memory freed by the object can be overwritten, and the data will be gone.

Now garbage collection in Java doesn’t happen at any guaranteed interval. The String can thus persist in memory for a long time, and if a process crashes during this time, the contents of the string may end up in a memory dump or some log.

With a character array , you can read the password, finish working with it as soon as you can, and then immediately change the contents.

1) Since Strings are immutable in Java if you store the password as plain text, it will be available in memory until Garbage collector clears it and since String is used in String pool for reusability, there is pretty high chance that it will remain in memory for the long duration, which poses a security threat. Since anyone who has access to memory dump can find the password in clear text and that’s another reason you should always use an encrypted password than plain text. Since Strings are immutable, there are no way contents of Strings can be changed because any change will produce new String, while if you char[] you can still set all his element as blank or zero. So Storing password in character array mitigates security risk of stealing the password.

2) Java itself recommends using getPassword() method of JPasswordField which returns a char[] and deprecated getText() method which returns password in clear text stating security reason. It’s good to follow advice from Java team and adhering to standard rather than going against it.

String in java is immutable. So whenever a string is created, it will remain in the memory until it is garbage collected. So anyone who has access to the memory can read the value of the string.
If the value of the string is modified then it will end up creating a new string. So both the original value and the modified value stay in the memory until it is garbage collected.

With the character array, the contents of the array can be modified or erased once the purpose of the password is served. The original contents of the array will not be found in memory after it is modified and even before the garbage collection kicks in.

Because of the security concern it is better to store password as a character array.

String is immutable and it goes to the string pool. Once written, it cannot be overwritten.

char[] is an array which you should overwrite once you used the password and this is how it should be done:

 char[] passw = request.getPassword().toCharArray() if (comparePasswords(dbPassword, passw) { allowUser = true; cleanPassword(passw); cleanPassword(dbPassword); passw=null; } private static void cleanPassword (char[] pass) { for (char ch: pass) { ch = null; } } 

One scenario where the attacker could use it is a crashdump – when the JVM crashes and generates a memory dump – you will be able to see the password.

That is not necessarily a malicious external attacker. This could be a support user that has access to the server for monitoring purposes. He could peek into a crashdump and find the passwords.

  • Открытие защищенного паролем pdf-файла с iTextSharp
  • Невозможно импортировать ключевой файл «blah.pfx» - ошибка «Ключ-файл может быть защищен паролем»
  • Программно изменить тип ввода EditText с PASSWORD на NORMAL и наоборот
  • Почему плохие текстовые пароли плохо, и как я убеждаю своего босса, что его заветные веб-сайты находятся под угрозой?
  • Шрифт подсказки пароля в Android
  • Есть ли альтернатива JPasswordField?
  • Есть ли способ взломать пароль в проекте Excel VBA?
  • Java 256-битное шифрование на основе AES на основе паролей
  • Сброс пароля ROOT в MySQL 5.6
  • Отключить функциональность браузера «Сохранить пароль»
  • ASP.NET Identity default Password Hasher, как он работает и безопасен ли он?
  • Interesting Posts
    Давайте будем гением компьютера.