2012-04-24 3 views
53

У меня есть приложение Java, которое подключается к базе данных.
Имя пользователя и пароль для базы данных хранятся в файле свойств.
Какова распространенная практика, заключающаяся в том, чтобы избежать сохранения пароля в открытом виде в файле свойств, сохраняя при этом параметр, позволяющий пользователю изменить его?
Главной мотивацией здесь является предотвращение того, что кто-то смотрит на плечо администратора и видит пароль, когда администратор редактирует файл свойств.
Я прочитал here, что есть встроенный способ сделать это на C#.
Зная java, я не ожидаю найти встроенное решение, но я хотел бы услышать, что делают другие люди.
Если я не нахожу хороший выбор, я, вероятно, собираюсь зашифровать его с помощью постоянного пароля, который будет храниться в коде. Но я не хотел бы так поступать, потому что это неправильно.Защита пароля в файле свойств

Редактировать 12.12.2012 Похоже, что нет волшебства, и я должен сохранить пароль в коде или что-то подобное. В конце мы реализовали нечто очень похожее на то, что Jasypt, о котором упоминалось в одном из ответов. Итак, я принимаю ответ Jasypt, потому что это самое близкое к определенному ответу.

+3

Лучшее, на что вы можете надеяться, это obfustication, если программа может его прочитать, любой, у кого есть доступ к файлам, тоже может быть. Это не значит, что вы не можете получить доступ к ним. – lynks

+0

Шифрование его постоянным паролем, который хранится в коде, кажется законным способом сделать это, если основная проблема связана с людьми, которые смотрят на плечо администратора. – ZeroOne

+0

Сколько людей обращается к базе данных? Не нужен ли им пароль для доступа к основной базе данных? Зачем вам хранить второй или этот? –

ответ

40

enter image description here

Jasypt обеспечивает org.jasypt.properties.EncryptableProperties класса для загрузки, управления и прозрачно дешифровки зашифрованных значений в файлах .properties, что позволяет сочетание обоего зашифрованных и не зашифрованных значений в одном файле.

http://www.jasypt.org/encrypting-configuration.html

Используя объект org.jasypt.properties.EncryptableProperties, приложение сможет правильно читать и использовать .properties файл так:

datasource.driver=com.mysql.jdbc.Driver 
datasource.url=jdbc:mysql://localhost/reportsdb 
datasource.username=reportsUser 
datasource.password=ENC(G6N718UuyPE5bHyWKyuLQSm02auQPUtm) 

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

Как мы читаем это значение? как это:

/* 
* First, create (or ask some other component for) the adequate encryptor for 
* decrypting the values in our .properties file. 
*/ 
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();  
encryptor.setPassword("jasypt"); // could be got from web, env variable...  
/* 
* Create our EncryptableProperties object and load it the usual way. 
*/ 
Properties props = new EncryptableProperties(encryptor); 
props.load(new FileInputStream("/path/to/my/configuration.properties")); 

/* 
* To get a non-encrypted value, we just get it with getProperty... 
*/ 
String datasourceUsername = props.getProperty("datasource.username"); 

/* 
* ...and to get an encrypted value, we do exactly the same. Decryption will 
* be transparently performed behind the scenes. 
*/ 
String datasourcePassword = props.getProperty("datasource.password"); 

// From now on, datasourcePassword equals "reports_passwd"... 
+12

Итак, в принципе, теперь пароль жестко закодирован в программе? – mazaneicha

+8

«Пароль», который вы видите в примере, используется для выполнения шифрования/дешифрования значений. В этом примере он жестко закодирован, но его можно извлечь из любой точки (например, переменной среды). Однако значения (-и) свойств, которые вы не хотите хранить в виде обычного текста, ** зашифровываются ** и затем дешифруются при чтении методом getProperty(). Это в основном слой обвинений, но он решает проблему плечевого серфинга и случайного доступа к конфиденциальным данным в покое. –

+1

@MadsHansen Спасибо за информацию. Я не думаю, что буду использовать его для этого проекта (уже слишком далеко от кодового замораживания ...), но я обязательно запомню его для следующей версии/проекта. – daramasala

9

Бедные мужчины компромиссным решение заключается в использовании несколько упрощенного подхода подписи.

Для примера DBA устанавливает пароль базы данных приложений к случайной строке 50 символов. TAKqWskc4ncvKaJTyDcgAHq82X7tX6GfK2fc386bmNw3muknjU

Он или она даст половину пароля для разработчиков приложений, которые затем жестко кодирует его в Java двоичный.

частная строка pass1 = «TAKqWskc4ncvKaJTyDcgAHq82»

Другая половина пароля передается в качестве аргумента командной строки. DBA предоставляет pass2 системной поддержке или администратору, который либо вводит в нее время запуска приложения, либо помещает его в сценарий запуска автоматизированного приложения.

ява -jar /myapplication.jar -pass2 X7tX6GfK2fc386bmNw3muknjU

При запуске приложения оно использует pass1 + pass2 и подключается к базе данных.

Это решение имеет много преимуществ без упомянутых недостатков.

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

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

Исходный код также может быть полудоступным для чтения, а пароль не даст вам доступа к приложению.

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

+1

Это может быть небезопасно.Предоставление учетных данных через командную строку обычно не рекомендуется из-за регистрации ОС. Злоумышленник просто откроет исходный файл -> прочитает половину пароля, затем введите 'history' в командной строке и voila! –

7

Как насчет предоставления пользовательского механизма аутентификации N-фактора?

Перед объединением доступных методов, давайте предположим, что мы можем выполнить следующее:

1) Hard-код внутри программы Java

2) Хранить в .properties файл

3) Запрашивать ввести пароль из командной строки

4) Задать пользователю ввести пароль из формы

5) Попросите пользователя загрузить пароль-фай ле из командной строки или формы

6) обеспечивает пароль через сеть

7) много альтернатив (например, Draw секрет, отпечатков пальцев, IP-специфические, бла-бла-бла)

1 вариант: Мы могли бы сделать вещи более сложными для злоумышленника, используя обфускацию, но это не считается хорошей контрмерой. Хороший кодер может легко понять, как это работает, если он/она может получить доступ к файлу. Мы могли бы даже экспортировать двоичный файл для каждого пользователя (или просто часть обфускации или ключевую часть), поэтому злоумышленник должен иметь доступ к этому файлу, специфичному для пользователя, а не к другому дистрибутиву. Опять же, мы должны найти способ изменения паролей, например, путем перекомпиляции или использования отражения в режиме поведения на лету.

второй вариант: Мы можем сохранить пароль в файле .properties в зашифрованном виде, поэтому он не виден непосредственно от злоумышленника (так же, как jasypt делает). Если нам нужен менеджер паролей, нам понадобится мастер-пароль, который снова должен быть где-то сохранен - ​​внутри.файл класса, хранилище ключей, ядро, другой файл или даже в памяти - все имеют свои плюсы и минусы.
Но теперь пользователи просто отредактируют файл .properties для смены пароля.

3-ая опция: введите пароль при запуске из командной строки, например. java -jar /myprogram.jar -p sdflhjkiweHIUHIU8976hyd.

Это не требует сохранения пароля и останется в памяти. Однако команды history и журналы OS могут быть вашим злейшим врагом. Чтобы изменить пароли «на лету», вам необходимо реализовать некоторые методы (например, прослушивать входные данные консоли, RMI, сокеты, REST bla bla bla), но пароль всегда будет оставаться в памяти.

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

4-й вариант: укажите пароль из пользовательской формы, а не из командной строки. Это обойдутся проблемой каротажа.

5-й вариант: предоставить файл как пароль, сохраненный ранее на другом носителе, -> затем файл жесткого удаления. Это снова обойдутся проблемой каротажа, а также не потребует типизации, которая может быть украдена плечом-серфингом. Когда требуется изменение, укажите другой файл, а затем снова удалите его.

6-й вариант: еще раз, чтобы избежать плеч-серфинга, можно реализовать вызов метода RMI, чтобы предоставить пароль (через зашифрованный канал) с другого устройства, например, с помощью мобильного телефона. Однако теперь вам необходимо защитить свой сетевой канал и получить доступ к другому устройству.

Я бы выбрал комбинацию вышеуказанных методов для достижения максимальной безопасности, поэтому вам нужно было бы получить доступ к файлам .class, файлу свойств, журналам, сетевому каналу, серфингу для плеч, мужчине посередине, другим файлам bla bla bla , Это можно легко реализовать с помощью операции XOR между всеми sub_passwords для создания фактического пароля.

Мы не можем быть защищены от несанкционированного доступа в память, но этого можно достичь только с помощью ограниченного доступа оборудования (например, смарт-карт, HSM, SGX), где все вычисляется в них, без кого-либо, даже законный владелец может получить доступ к ключам или алгоритмам дешифрования. Опять же, можно также украсть это оборудование, сообщается side-channel attacks, что может помочь злоумышленникам в извлечении ключей, а в некоторых случаях вам нужно доверять другой стороне (например, с SGX вы доверяете Intel). Конечно, ситуация может ухудшиться, когда будет возможно клонирование (де-сборка) в защищенном анклаве, но я думаю, это займет несколько лет, чтобы быть практичным.

Также можно рассмотреть решение для обмена ключами, в котором полный ключ разделяется между разными серверами. Однако после реконструкции полный ключ может быть украден. Единственный способ смягчить вышеупомянутую проблему - secure multiparty computation.

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