Безопасный способ выполнения основной авторизации [дубликат]

У меня есть небольшое решение, которое использует шаблоны T4 ( источник просмотра ).

Вы переходите от любого CLR POCO:

public class Parent : Person
{
    public string Name { get; set; }
    public bool? IsGoodParent { get; set; }
    public virtual ICollection Children { get; set; }
}

К Интерфейс TypeScript:

///
///
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}

2987
задан Rakete1111 13 January 2017 в 12:48
поделиться

17 ответов

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

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

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

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

3745
ответ дан Lonely Neuron 20 August 2018 в 11:00
поделиться
  • 1
    Я понимаю, что с реорганизацией памяти, которая может быть выполнена с помощью среды выполнения, копии даже char[] могут быть оставлены в памяти и никогда не будут очищены до тех пор, пока эта память не будет повторно использована. Я не знаю источника, который подтверждает это. В любом случае, я сомневаюсь, что String будет очищаться во время GC, но в то время, когда объект перераспределяется по этой памяти. – Mark Peters 16 January 2012 в 16:30
  • 2
    @Mark Peters: Если GC запускается, прежде чем вы очистите char-array, у вас будет другая копия. Но эта копия, по крайней мере, находится в тяжелой используемой области памяти, поэтому шансы высоки, она быстро перезаписывается. – Mnementh 16 January 2012 в 16:32
  • 3
    @ Xeon06: В .NET есть SecureString , что еще лучше - но относительно больно использовать. – Jon Skeet 16 January 2012 в 22:42
  • 4
    Мы замалчиваем тот факт, что вредоносный объект, который может читать эти данные, уже имеет доступ к памяти для чтения в вашу систему? Похоже, что было бы гораздо больше беспокоиться о том, что выполнение этого символа [] вместо String просто кажется мошенническим в океане. – corsiKa 12 June 2015 в 19:40
  • 5
    @corsika: Как я уже говорил в ответ, это уменьшает один конкретный вектор атаки, вот и все. Это делает вещи более трудными для атакующего. – Jon Skeet 12 June 2015 в 19:42

Строка неизменна и идет в пул строк.

char[] - это массив, который вы должны перезаписать после того, как вы использовали пароль, и вот как это должно быть сделано:

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

Это не обязательно вредоносный внешний злоумышленник. Это может быть пользователь службы поддержки, который имеет доступ к серверу для целей мониторинга. Он мог заглянуть в crashdump и найти пароли.

7
ответ дан ACV 20 August 2018 в 11:00
поделиться

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

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

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

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

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

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

613
ответ дан Bruno 20 August 2018 в 11:00
поделиться
  • 1
    это именно недостаток / фиктивная ссылка, о которой я говорю ниже ответа Джона, это известный источник с большой критикой. – bestsss 22 January 2012 в 22:45
  • 2
    @bestass, можете ли вы также привести ссылку? – user961954 11 August 2012 в 12:27
  • 3
    @bestass извините, но String довольно хорошо понят и как он ведет себя в JVM ... есть веские причины использовать char[] вместо String при безопасном обращении с паролями. – SnakeDoc 27 June 2014 в 01:50
  • 4
    еще раз, хотя пароль передается как строка из браузера в запрос как «строка» не char? так что независимо от того, что вы делаете, это строка, и в этот момент ее следует использовать и отбрасывать, никогда не хранить в памяти? – Dawesi 5 August 2018 в 19:50

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

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

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

32
ответ дан Community 20 August 2018 в 11:00
поделиться
  • 1
    Но это может быть и в сравнении с char [], где-то мы будем делать то же самое и при проверке пароля. так как char [] лучше, чем строка? – Mohit Kanwar 1 July 2015 в 05:41
  • 2
    Вы абсолютно правы, ошибка может быть сделана в любом случае. Зная о проблеме, самое главное здесь, учитывая отсутствие явного метода сравнения паролей в Java для паролей на основе String или char []. Я бы сказал, что искушение использовать compare () для Strings - хорошая причина пойти с char []. Таким образом, вы, по крайней мере, контролируете, как делается сравнение (без расширения String, что является болью imo). – Graph Theory 2 July 2015 в 21:03
  • 3
    Кроме того, сравнение паролей с открытым текстом в любом случае не так, искушение использовать Arrays.equals для char[] выше, чем для String.equals. Если кто-то заботился, существовал специальный ключевой класс, инкапсулирующий фактический пароль и заботящийся о проблемах - о, подождите, настоящие пакеты безопасности имеют выделенные ключевые классы, этот Q & amp; A - только о привычка вне их, скажем, например JPasswordField, использовать char[] вместо String (где фактические алгоритмы используют byte[] в любом случае). – Holger 9 March 2017 в 11:22
  • 4
    Программное обеспечение, относящееся к безопасности, должно делать что-то вроде sleep(secureRandom.nextInt()), прежде чем отклонять попытку входа в систему, что не только устраняет возможность временных атак, но и делает попытки противников грубой силой. – Holger 9 March 2017 в 11:24
  • 5
    Почему String-дедупликация страшна? Это применимо только тогда, когда есть по крайней мере две строки, имеющие одно и то же содержимое, так что может возникнуть опасность того, что эти две уже идентичные строки будут иметь один и тот же массив? Или давайте попробуем обратное: если нет дедупликации строк, какое преимущество возникает из-за того, что обе строки имеют отдельный массив (одного и того же содержимого)? В любом случае будет существовать массив этого содержимого, по крайней мере, до тех пор, пока не будет проживать самая длинная живая строка этого содержимого ... – Holger 9 March 2017 в 18:45
  • 6
    @Holger все, что не под вашим контролем, является потенциальным риском ... например, если у двух пользователей одинаковый пароль, эта замечательная функция сохранит оба из них в одиночном символе [], что станет очевидным, что они одинаковы, не уверены, что это огромный риск, но все же – Oleg Mikheev 9 March 2017 в 19:28
  • 7
    Если у вас есть доступ к памяти кучи и оба экземпляра строки, не имеет значения, указывают ли строки на один и тот же массив или на два массива одного и того же содержимого, каждый из которых легко узнать. Тем более, что в любом случае это не имеет значения. Если вы сейчас находитесь, вы получаете оба пароля, одинаковые или нет. Фактическая ошибка заключается в использовании незашифрованных паролей вместо соленых хэшей. – Holger 9 March 2017 в 19:35
  • 8
    @Holger, чтобы проверить пароль, он должен быть в ясном тексте в памяти в течение некоторого времени, 10 мс, даже если это просто создать соленый хэш из него. Затем, если произойдет, что в памяти хранятся два одинаковых пароля, даже в течение 10 мс, дедупликация может вступить в игру. Если он действительно ставит строки, они хранятся в памяти в течение гораздо более длительного времени. Система, которая не запускается в течение нескольких месяцев, будет собирать много из них. Просто теоретизирую. – Oleg Mikheev 10 March 2017 в 22:40
  • 9
    Кажется, у вас есть фундаментальное недоразумение в отношении дедупликации строк. Это не «статические строки», все, что он делает, позволяет строкам с тем же содержимым указывать на один и тот же массив, который фактически уменьшает число экземпляров массива, содержащих пароль открытого текста, как все, кроме одного экземпляр массива может быть немедленно восстановлен и перезаписан другими объектами. Эти строки все еще собираются, как и любая другая строка. Возможно, это помогает, если вы понимаете, что дедупликация фактически выполняется сборщиком мусора, для строк, которые выжили только в нескольких циклах GC. – Holger 13 March 2017 в 12:30

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

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

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

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

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

58
ответ дан emboss 20 August 2018 в 11:00
поделиться
  • 1
    Один из способов - использовать реализацию PrivateKey, которая фактически не загружает свой личный контент в памяти: например, с помощью аппаратного маркера PKCS # 11. Возможно, программная реализация PKCS # 11 может позаботиться о том, чтобы очистить память вручную. Возможно, использование чего-то типа хранилища NSS (которое разделяет большую часть своей реализации с типом хранилища PKCS11 в Java). KeychainStore (хранилище ключей OSX) загружает полное содержимое закрытого ключа в его экземпляры PrivateKey, но это не нужно. (Не знаете, что делает WINDOWS-MY KeyStore для Windows.) – Bruno 21 January 2012 в 15:31
  • 2
    @Bruno Конечно, аппаратные маркеры не страдают от этого, но как насчет ситуаций, когда вы более или менее вынуждены использовать программный ключ? Не у каждого развертывания есть бюджет, позволяющий получить HSM. Хранилища программных ключей в какой-то момент должны будут загрузить ключ в память, так что IMO нам по крайней мере будет предоставлена ​​возможность снова очистить память. – emboss 21 January 2012 в 16:18
  • 3
    Абсолютно, мне просто интересно, могут ли некоторые реализации программного обеспечения, эквивалентные HSM, лучше справляться с очисткой памяти. Например, при использовании Client-auth с Safari / OSX процесс Safari никогда не видит закрытого ключа, базовая библиотека SSL, предоставляемая ОС, напрямую связана с демоном безопасности, который побуждает пользователя использовать ключ из брелка. В то время как все это делается в программном обеспечении, подобное разделение может помочь, если подпись делегируется другой сущности (даже на основе программного обеспечения), которая могла бы разгрузить или очистить память лучше. – Bruno 21 January 2012 в 16:29
  • 4
    @Bruno: Интересная идея, дополнительный слой косвенности, который заботится о очистке памяти, действительно разрешит это прозрачно. Написание обложек PKCS # 11 для хранилища ключей программного обеспечения уже могло сделать трюк? – emboss 21 January 2012 в 16:45

Строки неизменяемы и не могут быть изменены после их создания. Создание пароля в виде строки приведет к остаточному обращению к паролю в куче или в пуле строк. Теперь, если кто-то возьмет кучу кучи Java-процесса и тщательно проверит его, он сможет угадать пароли. Конечно, эти неиспользуемые строки будут собирать мусор, но это зависит от того, когда GC запускается.

С другой стороны char [] изменяются, как только выполняется аутентификация, вы можете перезаписать их любым символом как все М или обратные косые черты. Теперь даже если кто-то берет кучу кучи, он, возможно, не сможет получить пароли, которые в настоящее время не используются. Это дает вам больше контроля в том смысле, как очистка содержимого объекта самостоятельно или до ожидания выполнения GC.

26
ответ дан Geek 20 August 2018 в 11:00
поделиться
  • 1
    Они будут только GC'd, если JVM в вопросе & gt; 1.6. До 1.7 все строки были сохранены в пергеном. – avgvstvs 5 February 2016 в 16:15
  • 2
    @avgvstvs: «все строки были сохранены в пермгене» просто мертва неправильно. Там хранились только интернированные строки, и если они не были получены из строковых литералов, на которые ссылается код, они все еще собирались в мусор. Просто подумай об этом. Если строки, как правило, никогда не были объединены в JVM до 1.7, как может любое Java-приложение выжить более чем на несколько минут? – Holger 9 March 2017 в 11:28
  • 3
    @Holger Это неверно. Interned strings И пул String (пул ранее использованных строк) были ОБА, хранящиеся в Пермгене до 1.7. Кроме того, см. Раздел 5.1: docs.oracle.com/javase/specs/jvms/se6/html/… JVM всегда проверяла Strings, чтобы увидеть, были ли они одинаковым ссылочным значением и позвоните String.intern() ДЛЯ ВАС. В результате каждый раз, когда JVM обнаруживал идентичные строки в constant_pool или куче, он перемещал их в permgen. И я работал над несколькими приложениями с «ползучим перменом». до 1,7. Это была настоящая проблема. – avgvstvs 9 March 2017 в 17:36
  • 4
    Итак, чтобы повторить: до 1.7, струны начали в куче, когда они были использованы, они были помещены в constant_pool, который был расположен в подмножестве, а затем, если строка использовалась более одного раза, она была бы интернирована. – avgvstvs 9 March 2017 в 17:39
  • 5
    @avgvstvs: нет пула ранее использованных строк. Вы бросаете совершенно разные вещи вместе. Существует один пул строк выполнения, содержащий строковые литералы и явно интернированные строки, но не другие. И каждый класс имеет свой постоянный пул, содержащий константы compile-time . Эти строки автоматически добавляются в пул выполнения, но только эти , а не каждая строка. – Holger 9 March 2017 в 18:34
  1. Строки неизменяемы в Java, если вы храните пароль в виде обычного текста, он будет доступен в памяти до тех пор, пока сборщик мусора не очистит его, и поскольку строки используются в пуле строк для повторного использования, существует довольно высокая вероятность того, что он будет остаются в памяти в течение длительного времени, что создает угрозу безопасности. Поскольку любой, у кого есть доступ к дампу памяти, может найти пароль в тексте clear
  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 );
    
    String password: passwd Пароль персонажа: [C @ 110b2345

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

118
ответ дан hackjutsu 20 August 2018 в 11:00
поделиться
  • 1
    «Поскольку любой, у кого есть доступ к дампу памяти, может найти пароль в открытом тексте» Как я могу получить доступ к дампу памяти и найти там пароль? – Mohit Kanwar 1 July 2015 в 05:44
  • 2
    @MohitKanwar Запуск дампа памяти через jmap или jvisualvm. Если установлен heapdumponoutofmemoryerror, вы можете запустить дамп удаленной кучи, вызывая состояние из памяти. После того, как у вас есть дамп, вы можете пройти через него с помощью инструмента анализатора памяти jvisualvm или eclipse или инструментов командной строки и проверить все объекты и их значения. – Ryan 5 August 2016 в 17:22

Хотя другие предложения здесь выглядят действительно, есть еще одна веская причина. С обычным 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: [C@5829428e
1085
ответ дан Kyle Rozendo 20 August 2018 в 11:00
поделиться
  • 1
    @voo, но я сомневаюсь, что вы зарегистрируетесь через прямую запись в поток и конкатенацию. структура каротажа преобразует char [] в хороший результат – bestsss 18 January 2012 в 03:14
  • 2
    @ Thr4wn Реализация по умолчанию toString - classname@hashcode. [C представляет char[], остальное - шестнадцатеричный хэш-код. – Konrad Garus 20 January 2012 в 14:39
  • 3
    Интересная идея. Я хотел бы указать, что это не переносит Scala, у которой есть значимая toString для массивов. – mauhiz 9 July 2015 в 08:36
  • 4
    Для этого я бы написал тип класса Password. Это менее неясное и куда труднее случайно куда-то пройти. – rightfold 31 August 2015 в 17:32
  • 5
    Почему кто-то предположил, что массив символов будет запущен как объект? Я не уверен, что понимаю, почему каждый любит этот ответ. Предположим, вы сделали это: System.out.println («Пароль» .toCharArray ()); – GC_ 22 August 2016 в 13:23

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

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

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: '***********'

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

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

41
ответ дан Peter Lawrey 20 August 2018 в 11:00
поделиться
  • 1
    Лучше также сделать что-то, чтобы предотвратить печать длины пароля, которую мы получаем из '***********'. – chux 27 August 2015 в 19:21
  • 2
    @chux вы можете использовать символ нулевой ширины, хотя это может быть более запутанным, чем полезным. Невозможно изменить длину массива char без использования Unsafe. ;) – Peter Lawrey 27 August 2015 в 20:16
  • 3
    Из-за дедупликации String Java 8 я думаю, что делать что-то подобное может быть довольно разрушительным ... вы можете очистить другие строки в своей программе, которые случайно имели такое же значение пароля String. Вряд ли, но возможно ... – jamp 8 February 2016 в 15:48
  • 4
    Ожидается, что в jjamp Java 9 будет эта функция, а также компактная строка (т. е. использование байта []]). Я не считаю, что это происходит на Java 8. – Peter Lawrey 8 February 2016 в 16:33
  • 5
    @PeterLawrey Должен быть включен с аргументом JVM, но он есть. Здесь можно прочитать: blog.codecentric.de/en/2014/08/… – jamp 8 February 2016 в 17:20

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

305
ответ дан Peter Mortensen 20 August 2018 в 11:00
поделиться
  • 1
    Небезопасно по умолчанию. Если мы говорим о веб-приложении, большинство веб-контейнеров передают пароль в объект HttpServletRequest в виде открытого текста. Если версия JVM версии 1.6 или ниже, она будет находиться в пространстве перменгенов. Если он находится в 1.7, он все равно будет доступен для чтения, пока он не будет собран. (Когда бы это ни было.) – avgvstvs 5 February 2016 в 16:19
  • 2
    @avgvstvs: строки не переносятся автоматически в пространство перменто, которое применяется только к интернированным строкам. Кроме того, пространство для перменов также подлежит сбору мусора только с меньшей скоростью. Реальная проблема с пространством permgen - это фиксированный размер, и именно поэтому никто не должен бессмысленно называть intern() произвольными строками. Но вы правы в том, что экземпляры String существуют в первую очередь (до тех пор, пока они не собраны) и превращают их в char[] массивы впоследствии не меняют. – Holger 9 March 2017 в 11:04
  • 3
    @Holger см. docs.oracle.com/javase/specs/jvms/se6/html/… "В противном случае создается новый экземпляр класса String, содержащий последовательность символов Unicode, заданную константой CONSTANT_String_info состав; этот экземпляр класса является результатом строкового литерала. Наконец, вызывается метод intern нового экземпляра String. & Quot; В 1.6, JVM будет звонить стажером для вас, когда он обнаруживает идентичные последовательности. – avgvstvs 9 March 2017 в 17:43
  • 4
    @Holger, вы правы, я скомбинировал постоянный пул и пул строк, но это также неверно, что пространство перменства only применяется к интернированным строкам. До 1.7, как constant_pool, так и string_pool располагались в пространстве перментонов. Это означает, что единственный класс строк, которые были выделены для кучи, были такими, как вы сказали: new String() или StringBuilder.toString() я управлял приложениями с множеством строковых констант, и в результате у нас было много ползучести пермгенов. До 1.7. – avgvstvs 11 March 2017 в 19:43
  • 5
    @avgvstvs: ну, строковые константы, как и мандаты JLS, всегда интернированы, следовательно, утверждение, что интернированные строки оказались в пространстве перментонов, неявно применяется к строковым константам. Единственное различие заключается в том, что строковые константы были созданы в пространстве перменов в первую очередь, тогда как вызов intern() на произвольной строке может привести к выделению эквивалентной строки в пространстве permgen. Последний может получить GC'ed, если не было личной строки того же содержимого, совместно использующего этот объект ... – Holger 13 March 2017 в 12:20

Строка в java неизменна. Поэтому всякий раз, когда создается строка, она остается в памяти до тех пор, пока не будет собрана мусор. Поэтому любой, кто имеет доступ к памяти, может прочитать значение строки. Если значение строки будет изменено, это приведет к созданию новой строки. Таким образом, как исходное значение, так и измененное значение остаются в памяти, пока не будет собран мусор. С помощью массива символов содержимое массива может быть изменено или удалено после того, как будет применена цель пароля. Исходное содержимое массива не будет найдено в памяти после его модификации и даже до того, как будет собрана сборка мусора. Из-за проблемы безопасности лучше хранить пароль в виде массива символов.

9
ответ дан Saathvik 20 August 2018 в 11:00
поделиться

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

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

13
ответ дан Sameer 20 August 2018 в 11:00
поделиться
  • 1
    Это просто бессмысленная переделка ответа Скита. – pmcilreavy 31 January 2017 в 11:22
  • 2
    @fallenidol Совсем нет. Читайте внимательно, и вы найдете различия. – Pritam Banerjee 11 September 2017 в 06:02

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

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

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

72
ответ дан Sean Owen 20 August 2018 в 11:00
поделиться
  • 1
    Я бы не сказал, что проблема в том, что ваши ссылки будут или не будут «убегать». Это просто, что строки будут оставаться неизмененными в памяти в течение некоторого дополнительного времени, в то время как char[] может быть изменен, а затем не имеет значения, собрано это или нет. И так как интерпретация строк должна выполняться явно для нелитералов, это то же самое, что сказать, что на char[] можно ссылаться на статическое поле. – Groo 16 January 2012 в 19:26
  • 2
    это не пароль в памяти как строка из сообщения формы? – Dawesi 5 August 2018 в 19:43

Это все причины, нужно выбрать 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: [C@110b053

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

32
ответ дан sP_ 20 August 2018 в 11:00
поделиться
  • 1
    Это избыточно. Этот ответ является точной версией ответа, написанной @SrujanKumarGulla stackoverflow.com/a/14060804/1793718 . Пожалуйста, не копируйте вставку или не дублируйте один и тот же ответ дважды. – Lucky 3 November 2016 в 08:57
  • 2
    В чем разница между 1.) System.out.println («Пароль персонажа:» + charPassword); и 2.) System.out.println (charPassword); Поскольку он дает тот же «неизвестный», как выход. – Vaibhav_Sharma 28 July 2017 в 11:13

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

Обновление

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

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

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

184
ответ дан stites 20 August 2018 в 11:00
поделиться
  • 1
    Я бы заменил «совершенно бесполезным». с "только незначительным улучшением безопасности". Например, вы можете получить доступ к дампу памяти, если у вас есть доступ для чтения к каталогу tmp, плохо сконфигурированной машине и сбою в вашем приложении. В этом случае вы не сможете установить кейлоггер, но вы могли бы анализировать дамп ядра. – Joachim Sauer 16 January 2012 в 18:23
  • 2
    Очистка незашифрованных данных из памяти, как только вы закончите с ней, считается лучшей практикой не потому, что она надежна (это не так); а потому, что он снижает уровень угрозы для вашей угрозы. Это не мешает атакам в режиме реального времени; а потому, что он служит инструментом уменьшения ущерба, значительно уменьшает объем данных, которые подвергаются ретроактивной атаке на моментальный снимок памяти (например, копия вашей памяти приложений, которая была записана в файл подкачки, или которая была зачитана в памяти с запущенного сервера и переместился на другой, пока его состояние не сработало). – Dan Neely 16 January 2012 в 18:26
  • 3
    Я склонен согласиться с отношением этого ответа. Я бы рискнул предложить большинство нарушений безопасности, происходящих на гораздо более высоком уровне абстракции, чем бит в памяти. Конечно, в гиперзащитных системах защиты, вероятно, есть сценарии, в которых это может быть серьезной проблемой, но серьезное мышление на этом уровне является излишним для 99% приложений, где используются .NET или Java (поскольку это связано с сбором мусора). – kingdango 17 January 2012 в 20:18
  • 4
    После проникновения Heartwelled из памяти сервера, раскрывая пароли, я бы заменил строку «только незначительное улучшение безопасности», с "абсолютно необходимо не использовать String для паролей, но вместо этого использовать char []. & quot; – Peter vdL 24 July 2014 в 06:15
  • 5
    @PetervdL с дуплером разрешал читать только конкретную повторно используемую коллекцию буферов (используемую как для критически важных данных безопасности, так и для сетевого ввода-вывода без очистки между ними - по соображениям производительности), вы не можете объединить это с Java String, поскольку они по дизайну не используются повторно , Также вы не можете читать в случайную память с помощью Java, чтобы получить содержимое строки. Проблемы языка и дизайна, которые приводят к бровям, просто невозможно с Java Strings. – josefx 30 July 2014 в 18:39
37
ответ дан Community 31 October 2018 в 08:59
поделиться
17
ответ дан Sameer 31 October 2018 в 08:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: