Файлы Java .class
можно легко декомпилировать. Как я могу защитить свою базу данных, если мне нужно использовать данные входа в код?
Как я могу защитить имя пользователя и пароль MySQL от декомпиляции?
Ответ 1
Никогда не записывайте пароли в свой код. Это было недавно поднято в Топ-25 самых опасных ошибок программирования:
Жесткое кодирование секретной учетной записи и пароль в ваше программное обеспечение чрезвычайно удобно - для квалифицированных обратные инженеры. Если пароль то же самое во всем вашем программном обеспечении, то каждый клиент становится уязвимым когда этот пароль неизбежно становится известен. И поскольку он жестко закодирован, это огромная боль, чтобы исправить.
Вы должны хранить информацию о конфигурации, включая пароли, в отдельном файле, который приложение считывает при запуске. Это единственный реальный способ предотвратить утечку пароля в результате декомпиляции (никогда не компилируйте его в двоичный файл).
Для получения дополнительной информации об этой распространенной ошибке вы можете прочитать статью статьи CWE-259. В статье содержится более подробное определение, примеры и множество других сведений о проблеме.
В Java одним из самых простых способов сделать это является использование класса Preferences. Он предназначен для хранения всех видов настроек программы, некоторые из которых могут включать имя пользователя и пароль.
import java.util.prefs.Preferences;
public class DemoApplication {
Preferences preferences =
Preferences.userNodeForPackage(DemoApplication.class);
public void setCredentials(String username, String password) {
preferences.put("db_username", username);
preferences.put("db_password", password);
}
public String getUsername() {
return preferences.get("db_username", null);
}
public String getPassword() {
return preferences.get("db_password", null);
}
// your code here
}
В приведенном выше коде вы можете вызвать метод setCredentials
после отображения диалога askign для имени пользователя и пароля. Когда вам нужно подключиться к базе данных, вы можете просто использовать методы getUsername
и getPassword
для извлечения сохраненных значений. Учетные данные для входа не будут жестко закодированы в ваши двоичные файлы, поэтому декомпиляция не будет представлять угрозу безопасности.
Важное примечание: Файлы настроек - это просто текстовые XML файлы. Убедитесь, что вы предпринимаете соответствующие шаги, чтобы предотвратить несанкционированный доступ к необработанным файлам (разрешения UNIX, разрешения Windows и т.д.). В Linux, по крайней мере, это не проблема, потому что вызов Preferences.userNodeForPackage
создаст XML файл в текущем домашнем каталоге пользователя, который в любом случае не читается другими пользователями. В Windows ситуация может быть иной.
Важные примечания: В комментариях к этому ответу и другим вопросам было много обсуждений относительно правильной архитектуры для этой ситуации. В исходном вопросе не упоминается контекст, в котором используется приложение, поэтому я расскажу о двух ситуациях, о которых я могу думать. Первое - это случай, когда пользователь, использующий программу, уже знает (и имеет право знать) учетные данные базы данных. Во-вторых, это тот случай, когда вы, разработчик, пытаетесь сохранить секретные данные базы данных от человека, использующего программу.
Первый случай: пользователь имеет право знать учетные данные для входа в базу данных
В этом случае решение, упомянутое выше, будет работать. Класс Java Preference
будет хранить имя пользователя и пароль в виде обычного текста, но файл настроек будет доступен только для авторизованного пользователя. Пользователь может просто открыть XML файл предпочтений и прочитать учетные данные для входа, но это не угроза безопасности, потому что пользователь знал учетные данные для начала.
Второй случай: попытка скрыть учетные данные пользователя от пользователя
Это более сложный случай: пользователь не должен знать учетные данные для входа, но все же нуждается в доступе к базе данных. В этом случае пользователь, запускающий приложение, имеет прямой доступ к базе данных, что означает, что программе необходимо заранее знать учетные данные для входа. Решение, упомянутое выше, не подходит для этого случая. Вы можете сохранить учетные данные для входа в базу данных в файле настроек, но пользователь сможет прочитать этот файл, так как он будет владельцем. На самом деле, действительно нет хорошего способа использовать этот случай безопасным способом.
Правильный пример: использование многоуровневой архитектуры
Правильный способ сделать это - иметь средний уровень между сервером базы данных и вашим клиентским приложением, который проверяет подлинность отдельных пользователей и позволяет выполнять ограниченный набор операций. Каждый пользователь будет иметь свои собственные учетные данные, но не для сервера базы данных. Учетные данные позволят получить доступ к среднему уровню (уровень бизнес-логики) и будут отличаться для каждого пользователя.
У каждого пользователя есть свое имя пользователя и пароль, которые могут храниться локально в файле настроек без какого-либо риска для безопасности. Это называется трехуровневой архитектурой(уровни - ваш сервер базы данных, сервер бизнес-логики и клиентское приложение). Это сложнее, но на самом деле это самый безопасный способ сделать это.
Основной порядок операций:
- Клиент аутентифицируется с использованием уровня бизнес-логики с использованием личного имени пользователя/пароля пользователя. Имя пользователя и пароль известны пользователю и никак не связаны с учетными данными входа в базу данных.
- Если аутентификация завершается успешно, клиент делает запрос на уровень бизнес-логики, запрашивая некоторую информацию из базы данных. Например, инвентаризация продуктов. Обратите внимание, что запрос клиента не является SQL-запросом; это удаленный вызов процедуры, например
getInventoryList
. - Уровень бизнес-логики соединяется с базой данных и получает запрошенную информацию. Уровень бизнес-логики отвечает за формирование безопасного SQL-запроса на основе пользовательского запроса. Любые параметры SQL-запроса должны быть дезинфицированы для предотвращения атак SQL-инъекций.
- Уровень бизнес-логики возвращает список инвентаря обратно в клиентское приложение.
- Клиент отображает список инвентаря для пользователя.
Обратите внимание, что во всем процессе клиентское приложение никогда не подключается напрямую к базе данных. Уровень бизнес-логики получает запрос от аутентифицированного пользователя, обрабатывает запрос клиента для списка инвентаря и только затем выполняет SQL-запрос.
Ответ 2
Поместите пароль в файл, который будет читать приложение. НИКОГДА не вставляйте пароли в исходный файл. Период.
Для такого использования Ruby имеет малоизвестный модуль, называемый DBI:: DBRC. Я не сомневаюсь, что Java имеет эквивалент. В любом случае, нетрудно написать его.
Ответ 3
Вы пишете веб-приложение? Если это так, используйте JNDI, чтобы настроить его снаружи приложения. Обзор доступен здесь:
JNDI обеспечивает единый приложение для поиска и доступа к удаленному услуг по сети. Пульт дистанционного управления услугой может быть любое корпоративное обслуживание, включая службу обмена сообщениями или службы, зависящей от конкретного приложения, но Конечно, приложение JDBC заинтересованы в основном в базе данных оказание услуг. Как только объект DataSource создано и зарегистрировано в JNDI служба именования, приложение может использовать API JNDI для доступа к этому источнику данных объект, который затем может быть использован для подключиться к источнику данных представляет.
Ответ 4
Этот вопрос показывает, как хранить пароли и другие данные в зашифрованном файле: Java 256-битное шифрование на основе AES на основе пароля
Ответ 5
MD5 - это алгоритм хеширования, а не алгоритм шифрования, короче говоря, получить обратно wat u hashed, u можно сравнить только. В идеале его следует использовать при сохранении информации об аутентификации пользователя, а не имени пользователя и пароля db. db имя пользователя и pwd должны быть зашифрованы и сохранены в файле конфигурации, чтобы сделать меньше.
Ответ 6
Независимо от того, что вы делаете, конфиденциальная информация будет храниться где-нибудь в каком-то файле. Ваша цель - сделать так же сложно, насколько это возможно. Сколько из этого вы можете достичь, зависит от вашего проекта, потребностей и толщины кошелька вашей компании.
Лучший способ - не хранить какие-либо пароли нигде. Это достигается с помощью хеш-функций для генерации и хранения хэшей паролей:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Хэш-алгоритмы являются односторонними. Они превращают любой объем данных в "отпечаток пальца фиксированной длины", который нельзя отменить. Они также имеют свойство, что, если вход изменяется хотя бы небольшим, получившийся хэш полностью отличается (см. пример выше). Эта отлично подходит для защиты паролей, потому что мы хотим хранить пароли в форме, которая защищает их, даже если сам файл пароля скомпрометированы, но в то же время нам нужно убедиться, что правильный пароль пользователя.
Несвязанное примечание: В старые времена Интернета, когда вы нажмете ссылку "забыть мой пароль", веб-сайты отправят вам ваш простой текстовый пароль. Вероятно, они хранили где-то в базе данных. Когда хакеры получили доступ к своей базе данных, они получили бы доступ ко всем паролям. Поскольку многие пользователи используют один и тот же пароль на нескольких веб-сайтах, это была огромная проблема безопасности. К счастью, в наши дни это не обычная практика.
Теперь возникает вопрос: какой лучший способ хранить пароли? Я бы рассмотрел это (проверка подлинности и службы управления штурмовой службой) - довольно проклятое идеальное решение:
- Пользователь вводит учетные данные, и это подтверждается пароль hash
- Хэши паролей генерируются и сохраняются, а не пароли
- Хеши выполняются несколько раз
- Хеши генерируются с использованием случайно генерируемой соли
- Хэши зашифрованы с помощью закрытого ключа
- Закрытый ключ хранится в физически другом месте, чем хеши
- Закрытые ключи обновлены по времени
- Зашифрованные хэши подразделяются на куски
- Эти куски хранятся в физически отдельных местах.
Очевидно, что вы не Google или банк, так что это решение для вас. Но тогда возникает вопрос: насколько обеспечен ваш проект, сколько времени и денег у вас есть?
Для многих приложений, хотя это и не рекомендуется, хранение жестко закодированного пароля в коде может быть достаточно хорошим решением. Однако, легко добавляя несколько дополнительных шагов безопасности из приведенного выше списка, вы можете сделать ваше приложение более безопасным.
Например, допустим, что шаг 1 не является приемлемым решением для вашего проекта. Вы не хотите, чтобы пользователи вводили пароль каждый раз, или вы даже не хотите/нуждаетесь в том, чтобы пользователи знали пароль. Тем не менее у вас есть конфиденциальная информация, и вы хотите ее защитить. У вас есть простое приложение, нет сервера для хранения ваших файлов, или это слишком много хлопот для вашего проекта. Приложение работает в средах, где невозможно надежно хранить файлы. Это один из худших случаев, но с некоторыми дополнительными мерами безопасности вы можете иметь гораздо более безопасное решение. Например, вы можете хранить конфиденциальную информацию в файле, и вы можете зашифровать файл. У вас может быть секретный ключ шифрования, закодированный в коде. Вы можете запутать код, так что вы немного усложняете его взломать. Для этой цели существует множество библиотек, см. эту ссылку. (Я хочу еще раз предупредить вас, что это не на 100% безопаснее. Разумный хакер с правильными знаниями и инструментами может взломать это. Но исходя из ваших требований и потребностей, это может быть для вас достаточно хорошим решением).