Строки неизменны . Это означает, что после того, как вы создали String
, если другой процесс может создавать дамп памяти, вы не сможете (кроме рефлексии ) избавиться от данных до того, как начнется сборка мусора .
С массивом вы можете явно стереть данные после того, как вы поработаете с ним. Вы можете перезаписать массив чем угодно, и пароль не будет нигде в системе, даже до сборки мусора.
Так что да, это есть проблема безопасности - но даже при использовании char[]
только уменьшает окно возможностей для атакующего, и это только для этого конкретного типа атаки.
Как отмечено в комментариях, возможно, что массивы, перемещаемые сборщиком мусора, будут оставлять в памяти случайные копии данных. Я полагаю, что это зависит от реализации - сборщик мусора может очистить всю память, чтобы избежать подобных вещей. Даже если это произойдет, все еще есть время, в течение которого char[]
содержит действительные символы в качестве окна атаки.
char[]
местах, отключает эту линию атаки, что невозможно при использованииString
.В то время как другие предложения здесь кажутся действительными, есть еще одна веская причина. С обычным у
String
вас гораздо больше шансов случайно напечатать пароль в журналах , мониторах или других небезопасных местах.char[]
менее уязвим.Учти это:
Печать:
источник
toString
-classname@hashcode
.[C
представляетchar[]
, остальное шестнадцатеричный хэш-код.Password
тип класса для этого. Это менее непонятно и сложнее случайно пройти где-нибудь.Чтобы процитировать официальный документ, в руководстве по архитектуре криптографии Java говорится о паролях
char[]
иString
паролях (о шифровании на основе паролей, но, конечно, в целом о паролях):В Руководстве 2-2 Руководства по безопасному кодированию для языка программирования Java версии 4.0 также говорится нечто подобное (хотя изначально оно относится к ведению журнала):
источник
String
он достаточно хорошо понят и как он себя ведет в JVM ... есть веские причины, чтобы использовать егоchar[]
вместо безопасногоString
обращения с паролями.At which point
это зависит от приложения, но общее правило - делать это, как только вы получаете что-то, что должно быть паролем (открытым текстом или иным образом). Например, вы получаете его из браузера как часть HTTP-запроса. Вы не можете контролировать доставку, но вы можете контролировать свое собственное хранилище, поэтому, как только вы его получите, поместите его в символ [], сделайте то, что вам нужно с ним, затем установите все в «0» и позвольте gc вернуть его.Массивы символов (
char[]
) можно очистить после использования, установив для каждого символа ноль, а для строк - нет. Если кто-то каким-то образом может видеть образ памяти, он может видеть пароль в виде простого текста, если используются строки, но еслиchar[]
используется, после очистки данных с нулями пароль является безопасным.источник
HttpServletRequest
в виде открытого текста. Если версия JVM - 1.6 или ниже, она будет в постоянном пространстве. Если он в 1.7, он все еще будет читаемым, пока не будет собран. (Всякий раз, когда это так.)intern()
произвольные строки. Но вы правы в том, чтоString
экземпляры существуют в первую очередь (до тех пор, пока они не собраны), и превращение их вchar[]
массивы впоследствии не изменит их.new String()
илиStringBuilder.toString()
я управлял приложениями с большим количеством строковых констант, и в результате у нас было много пермгена. До 1.7.intern()
произвольной строки может вызвать выделение эквивалентной строки в пространстве permgen. Последний мог получить GC'ed, если бы не было буквальной строки с тем же содержимым, разделяющим этот объект ...Некоторые люди считают, что вам нужно перезаписать память, используемую для хранения пароля, когда он вам больше не нужен. Это сокращает интервал времени, в течение которого злоумышленнику приходится считывать пароль из вашей системы, и полностью игнорирует тот факт, что злоумышленнику уже необходим достаточный доступ для захвата памяти JVM, чтобы сделать это. Злоумышленник с таким большим доступом может поймать ваши ключевые события, делая это совершенно бесполезным (AFAIK, поэтому, пожалуйста, исправьте меня, если я ошибаюсь).
Обновить
Благодаря комментариям я должен обновить свой ответ. Очевидно, есть два случая, когда это может добавить (очень) незначительное улучшение безопасности, поскольку это уменьшает время, когда пароль может попасть на жесткий диск. Тем не менее, я думаю, что это излишне для большинства случаев использования.
Если возможно, отключение дампов ядра и файла подкачки решит обе проблемы. Однако им потребуются права администратора и они могут снизить функциональность (меньше памяти для использования), а извлечение ОЗУ из работающей системы все равно будет иметь значение.
источник
Я не думаю, что это обоснованное предложение, но, по крайней мере, я могу догадаться о причине.
Я думаю, что мотивация состоит в том, чтобы убедиться, что вы можете стереть все следы пароля в памяти быстро и с уверенностью после его использования. С помощью a
char[]
вы можете перезаписать каждый элемент массива пробелом или чем-то определенным. Вы не можете редактировать внутреннее значениеString
таким образом.Но это само по себе не хороший ответ; почему бы просто не убедиться в том, что ссылка на
char[]
илиString
не сбежит? Тогда нет проблем с безопасностью. Но дело в том, чтоString
объекты можноintern()
редактировать теоретически и поддерживать в постоянном пуле. Я полагаю, использованиеchar[]
запрещает эту возможность.источник
char[]
можно будет изменить, и тогда не имеет значения, собраны они или нет. И поскольку интернирование строк должно выполняться явно для не-литералов, это то же самое, что сказать, что на achar[]
может ссылаться статическое поле.Ответ уже дан, но я хотел бы поделиться проблемой, которую я обнаружил в последнее время, со стандартными библиотеками Java. В то время как они очень заботятся о замене строк пароля
char[]
везде (что, конечно, хорошо), другие важные для безопасности данные, похоже, упускаются из виду, когда дело доходит до очистки их из памяти.Я имею в виду, например, класс PrivateKey . Рассмотрим сценарий, в котором вы бы загружали закрытый ключ RSA из файла PKCS # 12, используя его для выполнения какой-либо операции. Теперь, в этом случае, прослушивание пароля само по себе не очень поможет, если физический доступ к файлу ключа должным образом ограничен. Как злоумышленнику, вам было бы гораздо лучше, если бы вы получили ключ вместо пароля. Желаемой информацией может быть утечка коллектора, дампы ядра, сеанс отладчика или файлы подкачки - это только некоторые примеры.
И, как выясняется, нет ничего, что позволяло бы вам удалять личную информацию
PrivateKey
из памяти, потому что нет API, который позволял бы стирать байты, которые формируют соответствующую информацию.Это плохая ситуация, так как эта статья описывает, как это обстоятельство может быть потенциально использовано.
Например, библиотека OpenSSL перезаписывает критические разделы памяти перед освобождением закрытых ключей. Поскольку Java является сборщиком мусора, нам потребуются явные методы для очистки и аннулирования частной информации для ключей Java, которые должны применяться сразу после использования ключа.
источник
PrivateKey
, которая фактически не загружает свой частный контент в память: например, через аппаратный токен PKCS # 11. Возможно, программная реализация PKCS # 11 могла бы позаботиться об очистке памяти вручную. Возможно, лучше использовать что-то вроде хранилища NSS (которое разделяет большую часть своей реализации сPKCS11
типом хранилища в Java).KeychainStore
(OSX хранилища ключей) нагрузки на полное содержание секретного ключа в егоPrivateKey
экземпляры, но это не нужно. (Не уверен, чтоWINDOWS-MY
KeyStore делает в Windows.)Как утверждает Джон Скит, нет другого пути, кроме как с помощью отражения.
Однако, если рефлексия - вариант для вас, вы можете сделать это.
когда беги
Примечание: если char [] String был скопирован как часть цикла GC, есть вероятность, что предыдущая копия находится где-то в памяти.
Эта старая копия не будет отображаться в дампе кучи, но если у вас есть прямой доступ к необработанной памяти процесса, вы можете ее увидеть. В общем, вы должны избегать любого, имеющего такой доступ.
источник
'***********'
.Scanner
внутреннем буфере и, поскольку вы не использовалиSystem.console().readPassword()
, в читаемой форме в окне консоли. Но для большинства практических случаев длительностьusePassword
выполнения является актуальной проблемой. Например, при установлении соединения с другим компьютером это занимает значительное время и сообщает злоумышленнику, что настало время для поиска пароля в куче. Единственное решение - не дать злоумышленникам прочитать кучу памяти ...Это все причины, поэтому следует выбирать массив char [] вместо String для пароля.
1. Поскольку строки являются неизменяемыми в Java, если вы храните пароль в виде обычного текста, он будет доступен в памяти до тех пор, пока сборщик мусора не очистит его, и поскольку строка String используется в пуле строк для повторного использования, существует довольно высокая вероятность того, что он будет остаются в памяти на долгое время, что создает угрозу безопасности.
Поскольку любой, кто имеет доступ к дампу памяти, может найти пароль в виде открытого текста, это еще одна причина, по которой вы всегда должны использовать зашифрованный пароль, а не простой текст. Поскольку строки являются неизменяемыми, содержимое строк не может быть изменено, потому что любое изменение приведет к созданию новой строки, в то время как если вы используете char [], вы все равно можете установить все элементы как пустые или нулевые. Таким образом, хранение пароля в массиве символов явно снижает риск кражи пароля.
2. Сама Java рекомендует использовать метод getPassword () из JPasswordField, который возвращает char [], вместо устаревшего метода getText (), который возвращает пароли в виде открытого текста с указанием соображений безопасности. Хорошо следовать советам команды Java и придерживаться стандартов, а не идти против них.
3. При использовании String всегда существует риск печати простого текста в файле журнала или консоли, но если вы используете массив, вы не будете печатать содержимое массива, а вместо этого будет напечатано его расположение в памяти. Хотя это и не реальная причина, это все же имеет смысл.
Ссылка из этого блога . Надеюсь, это поможет.
источник
Изменить: Возвращаясь к этому ответу после года исследований в области безопасности, я понимаю, что это весьма печально, что вы когда-либо сравнивать незашифрованные пароли. Пожалуйста, не надо. Используйте безопасный односторонний хеш с солью и разумным количеством итераций . Подумайте об использовании библиотеки: этот материал трудно понять правильно!
Оригинальный ответ: А как насчет того факта, что String.equals () использует оценку короткого замыкания и поэтому уязвим для временной атаки? Это может быть маловероятно, но теоретически вы можете рассчитать время сравнения пароля, чтобы определить правильную последовательность символов.
Еще несколько ресурсов о временных атаках:
источник
Arrays.equals
дляchar[]
столь же высока , как и дляString.equals
. Если кому-то было интересно, был выделенный класс ключей, инкапсулирующий действительный пароль и заботящийся о проблемах - о, подождите, у реальных пакетов безопасности есть выделенные классы ключей, эти вопросы и ответы касаются только их привычки , скажем, напримерJPasswordField
, использоватьchar[]
вместоString
(где фактические алгоритмы используют вbyte[]
любом случае).sleep(secureRandom.nextInt())
прежде чем отклонять попытку входа в систему, это не только исключает возможность синхронизации атак, но и противодействует грубым попыткам.Массив char не даст вам ничего против String, если вы не очистите его вручную после использования, и я не видел, чтобы кто-нибудь на самом деле делал это. Поэтому для меня предпочтение char [] vs String немного преувеличено.
Посмотрите на широко используемой библиотеке Spring Security здесь и спросить себя - это Spring Security ребята недееспособными или символ [] пароли просто не имеет смысла. Когда какой-нибудь злобный хакер захватит дамп памяти вашей оперативной памяти, убедитесь, что он / она получит все пароли, даже если вы используете сложные способы их скрытия.
Тем не менее, Java постоянно меняется, и некоторые страшные функции, такие как функция дедупликации String в Java 8, могут работать с объектами String без вашего ведома. Но это другой разговор.
источник
Строки являются неизменяемыми и не могут быть изменены после того, как они были созданы. Создание пароля в виде строки оставит случайные ссылки на пароль в куче или в пуле строк. Теперь, если кто-то берет кучу дампов процесса Java и тщательно просматривает, он сможет угадать пароли. Конечно, эти неиспользуемые строки будут собираться мусором, но это зависит от того, когда включится GC.
С другой стороны, char [] изменяются, как только аутентификация завершена, вы можете перезаписать их любым символом, таким как все M или обратные слэши. Теперь, даже если кто-то получит дамп кучи, он не сможет получить пароли, которые в данный момент не используются. Это дает вам больше контроля в том смысле, как вы сами очищаете содержимое объекта от ожидания, пока GC сделает это.
источник
strings
ИString
пул (пул ранее использованных строк) ОБА хранился в Пермгене до 1.7. Также см. Раздел 5.1: docs.oracle.com/javase/specs/jvms/se6/html/… JVM всегда проверяла, имеютStrings
ли они одинаковое ссылочное значение, и будет ли вызыватьString.intern()
FOR YOU. В результате каждый раз, когда JVM обнаруживает идентичные строки вconstant_pool
куче или в куче, она перемещает их в permgen. И я работал над несколькими приложениями с "creeping permgen" до 1.7. Это была настоящая проблема.constant_pool
каталог IN permgen, а затем, если строка использовалась более одного раза, она была интернирована.Строка является неизменной и идет в пул строк. После написания его нельзя перезаписать.
char[]
это массив, который вы должны перезаписать после того, как вы использовали пароль, и вот как это должно быть сделано:Один из сценариев, в котором злоумышленник может использовать это, - это аварийная остановка - когда JVM падает и генерирует дамп памяти - вы сможете увидеть пароль.
Это не обязательно злонамеренный внешний злоумышленник. Это может быть пользователь поддержки, который имеет доступ к серверу для целей мониторинга. Он мог заглянуть в сбой и найти пароли.
источник
request.getPassword()
создает строку и не добавляет ее в пул?ch = '0'
изменяет локальную переменнуюch
; это не влияет на массив. И ваш пример в любом случае бессмысленен, вы начинаете с экземпляра строки, которую вы вызываетеtoCharArray()
, создавая новый массив, и даже когда вы правильно перезаписываете новый массив, он не меняет экземпляр строки, поэтому он не имеет преимущества перед простым использованием строки пример.Arrays.fill(pass, '0');
Короткий и прямой ответ будет потому, что
char[]
изменчив, аString
объекты нет.Strings
в Java есть неизменяемые объекты. Вот почему они не могут быть изменены после создания, и поэтому единственный способ удаления их содержимого из памяти - сбор мусора. Только тогда память, освобожденная объектом, может быть перезаписана, и данные исчезнут.Теперь сборка мусора в Java не происходит с гарантированным интервалом. Таким
String
образом, он может сохраняться в памяти в течение длительного времени, и если в течение этого времени произойдет сбой процесса, содержимое строки может оказаться в дампе памяти или в каком-либо журнале.С помощью массива символов вы можете прочитать пароль, закончить работу с ним, как только сможете, и сразу же изменить его содержимое.
источник
Строка в Java неизменна. Поэтому, когда бы ни была создана строка, она будет оставаться в памяти до тех пор, пока не будет собрана сборка мусора. Таким образом, любой, кто имеет доступ к памяти, может прочитать значение строки.
Если значение строки будет изменено, то это приведет к созданию новой строки. Таким образом, как исходное значение, так и измененное значение остаются в памяти до тех пор, пока они не будут удалены.
С массивом символов содержимое массива может быть изменено или стерто после того, как цель пароля будет достигнута. Исходное содержимое массива не будет найдено в памяти после его изменения и даже до того, как начнется сборка мусора.
Из соображений безопасности лучше хранить пароль в виде массива символов.
источник
Это спорно, следует ли использовать строку или использовать Char [] для этой цели, потому что оба имеют свои преимущества и недостатки. Это зависит от того, что нужно пользователю.
Поскольку строки в Java являются неизменяемыми, всякий раз, когда кто-то пытается манипулировать вашей строкой, он создает новый объект, и существующая строка остается неизменной. Это можно рассматривать как преимущество для хранения пароля в виде строки, но объект остается в памяти даже после использования. Таким образом, если кто-то каким-то образом получил место в памяти объекта, этот человек может легко отследить ваш пароль, хранящийся в этом месте.
Char [] изменчив, но имеет то преимущество, что после его использования программист может явно очистить массив или переопределить значения. Таким образом, когда он используется, он очищается, и никто не может знать, какую информацию вы сохранили.
Исходя из вышеизложенных обстоятельств, можно получить представление о том, использовать ли String или Char [] для их требований.
источник
Строка дела:
Case CHAR ARRAY:
источник