У меня есть небольшое решение, которое использует шаблоны 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[];
}
Строки неизменяемы. Это означает, что когда вы создали String
, если другой процесс может сбрасывать память, нет способа (кроме reflection ) вы можете избавиться от данных перед сборкой мусора удары.
С помощью массива вы можете явно стереть данные после того, как закончите с ним. Вы можете переписать массив всем, что угодно, и пароль не будет присутствовать нигде в системе, даже до сбора мусора.
Итак, это является проблемой безопасности - но даже при использовании char[]
только уменьшает окно возможностей для злоумышленника, и только для этого конкретного типа атаки.
Как отмечено в комментариях, возможно, что массивы перемещаются сборщиком мусора оставит бродячие копии данных в памяти. Я считаю, что это специфично для реализации - сборщик мусора может очистить всю память, когда она идет, чтобы избежать такого рода вещей. Даже если это так, еще есть время, в течение которого char[]
содержит фактические символы в качестве окна атаки.
Строка неизменна и идет в пул строк.
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 и найти пароли.
Чтобы указать официальный документ, Руководство по архитектуре криптографии Java говорит об этом char[]
vs. String
паролях (о шифровании на основе пароля, но это, в основном, касается паролей, конечно) :
Казалось бы логичным собирать и хранить пароль в объекте типа
java.lang.String
. Однако вот оговорка:Object
s типаString
являются неизменяемыми, т. Е. Нет определенных методов, которые позволят вам изменить (перезаписать) или обнулить содержимоеString
после использования. Эта функция делает объектыString
непригодными для хранения секретной информации, такой как пароль пользователя. Вы всегда должны собирать и хранить конфиденциальную информацию безопасности в массивеchar
.Руководство 2-2 Руководства по безопасному кодированию для языка программирования Java, версия 4.0 также говорит что-то подобное (хотя оно первоначально находится в контексте ведения журнала):
Руководство 2-2: Не записывайте высокочувствительную информацию
Некоторая информация, такая как номера социального страхования (SSN) и пароли, очень чувствительна. Эта информация не должна храниться дольше, чем необходимо, и там, где она может быть видна даже администраторами. Например, его нельзя отправлять в лог-файлы, и его присутствие не должно обнаруживаться при поиске. Некоторые временные данные могут храниться в изменяемых структурах данных, таких как массивы символов, и очищаться сразу после использования. Очистка структур данных снижает эффективность типичных систем времени выполнения Java, поскольку объекты переносятся в памяти прозрачно программисту.
Это руководство также имеет последствия для реализации и использования библиотек более низкого уровня, которые не имеют семантических знаний о данные, с которыми они имеют дело. Например, низкоуровневая библиотека синтаксического анализа строк может регистрировать текст, над которым он работает. Приложение может анализировать SSN с библиотекой. Это создает ситуацию, когда SSN доступны администраторам с доступом к файлам журнала.
String
довольно хорошо понят и как он ведет себя в JVM ... есть веские причины использовать char[]
вместо String
при безопасном обращении с паролями.
– SnakeDoc
27 June 2014 в 01:50
Нет ничего, что массив char дает вам vs String, если вы не очистите его вручную после использования, и я не видел, чтобы кто-то действительно делал это. Итак, для меня предпочтение char [] vs String немного преувеличено.
Взгляните на широко используемую библиотеку Spring Security здесь и спросите себя - ребята из Spring Security некомпетентны или char [], просто не имеют большого смысла. Когда какой-то неприятный хакер захватывает память вашей памяти, убедитесь, что она получит все пароли, даже если вы используете сложные способы скрыть их.
Тем не менее, Java все время меняется, а некоторые страшные функции, такие как Функция дедупликации строк Java 8 может ставить объекты String без вашего ведома. Но это разные разговоры.
Arrays.equals
для char[]
выше, чем для String.equals
. Если кто-то заботился, существовал специальный ключевой класс, инкапсулирующий фактический пароль и заботящийся о проблемах - о, подождите, настоящие пакеты безопасности имеют i> выделенные ключевые классы, этот Q & amp; A - только о привычка i> вне их, скажем, например JPasswordField
, использовать char[]
вместо String
(где фактические алгоритмы используют byte[]
в любом случае).
– Holger
9 March 2017 в 11:22
sleep(secureRandom.nextInt())
, прежде чем отклонять попытку входа в систему, что не только устраняет возможность временных атак, но и делает попытки противников грубой силой.
– Holger
9 March 2017 в 11:24
Ответ уже дан, но я хотел бы поделиться проблемой, которую я обнаружил в последнее время со стандартными библиотеками 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.)
– Bruno
21 January 2012 в 15:31
Строки неизменяемы и не могут быть изменены после их создания. Создание пароля в виде строки приведет к остаточному обращению к паролю в куче или в пуле строк. Теперь, если кто-то возьмет кучу кучи Java-процесса и тщательно проверит его, он сможет угадать пароли. Конечно, эти неиспользуемые строки будут собирать мусор, но это зависит от того, когда GC запускается.
С другой стороны char [] изменяются, как только выполняется аутентификация, вы можете перезаписать их любым символом как все М или обратные косые черты. Теперь даже если кто-то берет кучу кучи, он, возможно, не сможет получить пароли, которые в настоящее время не используются. Это дает вам больше контроля в том смысле, как очистка содержимого объекта самостоятельно или до ожидания выполнения GC.
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
constant_pool
, который был расположен в подмножестве, а затем, если строка использовалась более одного раза, она была бы интернирована.
– avgvstvs
9 March 2017 в 17:39
getPassword()
JPasswordField, который возвращает метод char [] и устаревший метод getText()
, который возвращает пароль в текстовом выражении причина безопасности. 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 [] не только достаточно, вам нужно стереть контент, чтобы быть более безопасным. Я также предлагаю работать с хешированным или зашифрованным паролем вместо обычного текста и освобождать его из памяти, как только будет завершена аутентификация.
Хотя другие предложения здесь выглядят действительно, есть еще одна веская причина. С обычным 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
toString
- classname@hashcode
. [C
представляет char[]
, остальное - шестнадцатеричный хэш-код.
– Konrad Garus
20 January 2012 в 14:39
Password
. Это менее неясное и куда труднее случайно куда-то пройти.
– rightfold
31 August 2015 в 17:32
Как утверждает Джон Скит, нет никакого способа, кроме как использовать отражение.
Однако, если отражение является для вас вариантом, вы можете это сделать.
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, есть вероятность, что предыдущая копия находится где-то в памяти.
Эта старая копия не появится в дампе кучи, но если у вас есть прямой доступ к необработанной памяти процесса, вы можете ее увидеть. В общем, вы должны избегать любого, кто имеет такой доступ.
'***********'
.
– chux
27 August 2015 в 19:21
Массивы символов (char[]
) можно очистить после использования, установив каждый символ в ноль, а строки - нет. Если кто-то может каким-то образом увидеть изображение в памяти, они могут видеть пароль в виде обычного текста, если используются строки, но если используется char[]
, после очистки данных с 0, пароль защищен.
HttpServletRequest
в виде открытого текста. Если версия JVM версии 1.6 или ниже, она будет находиться в пространстве перменгенов. Если он находится в 1.7, он все равно будет доступен для чтения, пока он не будет собран. (Когда бы это ни было.)
– avgvstvs
5 February 2016 в 16:19
intern()
произвольными строками. Но вы правы в том, что экземпляры String
существуют в первую очередь (до тех пор, пока они не собраны) и превращают их в char[]
массивы впоследствии не меняют.
– Holger
9 March 2017 в 11:04
new String()
или StringBuilder.toString()
я управлял приложениями с множеством строковых констант, и в результате у нас было много ползучести пермгенов. До 1.7.
– avgvstvs
11 March 2017 в 19:43
intern()
на произвольной строке может привести к выделению эквивалентной строки в пространстве permgen. Последний может получить GC'ed, если не было личной строки того же содержимого, совместно использующего этот объект ...
– Holger
13 March 2017 в 12:20
Строка в java неизменна. Поэтому всякий раз, когда создается строка, она остается в памяти до тех пор, пока не будет собрана мусор. Поэтому любой, кто имеет доступ к памяти, может прочитать значение строки. Если значение строки будет изменено, это приведет к созданию новой строки. Таким образом, как исходное значение, так и измененное значение остаются в памяти, пока не будет собран мусор. С помощью массива символов содержимое массива может быть изменено или удалено после того, как будет применена цель пароля. Исходное содержимое массива не будет найдено в памяти после его модификации и даже до того, как будет собрана сборка мусора. Из-за проблемы безопасности лучше хранить пароль в виде массива символов.
1) Так как Строки неизменны в Java, если вы храните пароль в виде обычного текста, он будет доступен в памяти до тех пор, пока сборщик мусора не очистит его, и поскольку String используется в пуле строк для повторного использования, существует довольно высокая вероятность того, что он будет остаются в памяти в течение длительного времени, что создает угрозу безопасности. Поскольку любой, у кого есть доступ к дампу памяти, может найти пароль в открытом тексте, и это еще одна причина, по которой вы всегда должны использовать зашифрованный пароль, чем обычный текст. Поскольку строки являются неизменными, невозможно изменить содержимое строк, потому что любое изменение приведет к созданию новой строки, а если вы char [], вы все равно можете установить весь его элемент как пустой или нулевой. Таким образом, хранение пароля в массиве символов снижает риск безопасности воровства пароля.
2) Сама Java рекомендует использовать метод getPassword () JPasswordField, который возвращает метод char [] и устаревший метод getText (), который возвращает пароль в ясном текст с указанием причины безопасности. Хорошо следовать советам команды Java и придерживаться стандарта, а не идти против него.
Я не думаю, что это правильное предложение, но я могу по крайней мере угадать причину.
Я думаю, что мотивация хочет убедиться, что вы можете стереть все следы пароля в памяти быстро и с уверенностью после его использования. С помощью char[]
вы можете переписать каждый элемент массива с пустым или что-то точно. Вы не можете редактировать внутреннее значение String
таким образом.
Но это одно не является хорошим ответом; почему бы не просто убедиться, что ссылка на char[]
или String
не исчезает? Тогда нет проблем с безопасностью. Но дело в том, что String
объекты могут быть intern()
изложены в теории и сохранены в постоянном пуле. Я полагаю, что использование char[]
запрещает эту возможность.
char[]
может быть изменен, а затем не имеет значения, собрано это или нет. И так как интерпретация строк должна выполняться явно для нелитералов, это то же самое, что сказать, что на char[]
можно ссылаться на статическое поле.
– Groo
16 January 2012 в 19:26
Это все причины, нужно выбрать 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 Надеюсь, это поможет.
Некоторые люди считают, что вам нужно перезаписать память, используемую для хранения пароля, как только она вам больше не понадобится. Это уменьшает время, которое атакующий должен прочитать пароль из вашей системы и полностью игнорирует тот факт, что злоумышленнику уже достаточно нужен доступ, чтобы захватить JVM-память для этого.
Обновление
Благодаря комментариям, которые у меня есть, я хочу, чтобы это было возможно. обновите мой ответ. По-видимому, есть два случая, когда это может добавить (очень) незначительное улучшение безопасности, поскольку это сокращает время, когда пароль может приземлиться на жесткий диск.
Если возможно, отключение основных дампов и файла подкачки позаботится обо всех проблемах. Тем не менее, они потребуют прав администратора и могут уменьшить функциональность (меньше памяти для использования) и вытащить ОЗУ из работающей системы все равно будут иметь серьезную озабоченность.
char[]
могут быть оставлены в памяти и никогда не будут очищены до тех пор, пока эта память не будет повторно использована. Я не знаю источника, который подтверждает это. В любом случае, я сомневаюсь, что String будет очищаться во время GC, но в то время, когда объект перераспределяется по этой памяти. – Mark Peters 16 January 2012 в 16:30SecureString
, что еще лучше - но относительно больно использовать. – Jon Skeet 16 January 2012 в 22:42