.class
Файлы Java довольно легко декомпилировать. Как я могу защитить свою базу данных, если мне нужно использовать данные для входа в код?
.class
Файлы Java довольно легко декомпилировать. Как я могу защитить свою базу данных, если мне нужно использовать данные для входа в код?
Ответы:
Никогда не вставляйте пароли в свой код жестко. Это недавно было внесено в список 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
метод после отображения диалогового окна с запросом имени пользователя и пароля. Если вам необходимо подключиться к базе данных, вы можете просто использовать getUsername
и getPassword
методы для получения сохраненных значений. Учетные данные для входа в систему не будут жестко закодированы в ваших двоичных файлах, поэтому декомпиляция не представляет угрозы безопасности.
Важное примечание: файлы настроек - это просто текстовые XML-файлы. Убедитесь, что вы предприняли соответствующие шаги для предотвращения просмотра неавторизованных пользователей неавторизованных файлов (разрешения UNIX, разрешения Windows и т. Д.). В Linux, по крайней мере, это не проблема, потому что при вызове создается Preferences.userNodeForPackage
XML-файл в домашнем каталоге текущего пользователя, который в любом случае не читается другими пользователями. В Windows ситуация может быть иной.
Более важные примечания: в комментариях к этому и другим ответам было много обсуждений о том, какая архитектура является правильной для этой ситуации. В исходном вопросе на самом деле не упоминается контекст, в котором используется приложение, поэтому я расскажу о двух ситуациях, которые могу придумать. Первый - это случай, когда человек, использующий программу, уже знает (и имеет право знать) учетные данные базы данных. Во втором случае вы, разработчик, пытаетесь сохранить в секрете учетные данные базы данных от лица, использующего программу.
Первый случай: пользователю разрешено знать учетные данные для входа в базу данных
В этом случае сработает решение, о котором я говорил выше. Класс Java Preference
будет хранить имя пользователя и пароль в виде обычного текста, но файл настроек будет доступен для чтения только авторизованному пользователю. Пользователь может просто открыть XML-файл настроек и прочитать учетные данные для входа в систему, но это не представляет угрозы для безопасности, поскольку пользователь изначально знал учетные данные.
Второй случай: попытка скрыть учетные данные для входа от пользователя
Это более сложный случай: пользователь не должен знать учетные данные для входа, но ему по-прежнему нужен доступ к базе данных. В этом случае пользователь, запускающий приложение, имеет прямой доступ к базе данных, что означает, что программе необходимо заранее знать учетные данные для входа. Упомянутое выше решение не подходит для этого случая. Вы можете сохранить учетные данные для входа в базу данных в файле настроек, но пользователь сможет читать этот файл, поскольку он будет владельцем. На самом деле, на самом деле нет хорошего способа безопасного использования этого кейса.
Правильный случай: использование многоуровневой архитектуры
Правильный способ сделать это - создать промежуточный уровень между сервером базы данных и клиентским приложением, который аутентифицирует отдельных пользователей и позволяет выполнять ограниченный набор операций. У каждого пользователя будут свои собственные учетные данные для входа, но не для сервера базы данных. Учетные данные позволят получить доступ к среднему уровню (уровню бизнес-логики) и будут разными для каждого пользователя.
У каждого пользователя будет собственное имя пользователя и пароль, которые можно будет хранить локально в файле настроек без какого-либо риска для безопасности. Это называется трехуровневой архитектурой (уровни - это ваш сервер базы данных, сервер бизнес-логики и клиентское приложение). Это более сложный, но на самом деле наиболее безопасный способ делать подобные вещи.
Основной порядок действий:
getInventoryList
.Обратите внимание, что в течение всего процесса клиентское приложение никогда не подключается напрямую к базе данных . Уровень бизнес-логики получает запрос от аутентифицированного пользователя, обрабатывает запрос клиента на список инвентаризации и только после этого выполняет SQL-запрос.
Поместите пароль в файл, который будет читать приложение. НИКОГДА не вставляйте пароли в исходный файл. Период.
В Ruby для такого использования есть малоизвестный модуль DBI :: DBRC . Не сомневаюсь, что у Java есть аналог. Во всяком случае, написать его несложно.
Вы пишете веб-приложение? Если это так, используйте JNDI для внешней настройки приложения. Обзор доступен здесь :
JNDI предоставляет приложению единый способ поиска удаленных сервисов и доступа к ним по сети. Удаленная служба может быть любой корпоративной службой, включая службу обмена сообщениями или службу для конкретного приложения, но, конечно, приложение JDBC в основном заинтересовано в службе базы данных. После того как объект DataSource создан и зарегистрирован в службе именования JNDI, приложение может использовать JNDI API для доступа к этому объекту DataSource, который затем можно использовать для подключения к источнику данных, который он представляет.
Независимо от того, что вы делаете, конфиденциальная информация будет где-то храниться в каком-то файле. Ваша цель - сделать это как можно сложнее. Насколько это удастся, зависит от вашего проекта, потребностей и толщины кошелька вашей компании.
Лучший способ - нигде не хранить пароли. Это достигается за счет использования хэш-функций для генерации и хранения хэшей паролей:
hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366
Алгоритмы хеширования - это односторонние функции. Они превращают любой объем данных в «отпечаток пальца» фиксированной длины, который нельзя отменить. У них также есть свойство, что если ввод изменяется даже на крошечный бит, результирующий хеш будет совершенно другим (см. Пример выше). Это отлично подходит для защиты паролей, потому что мы хотим хранить пароли в форме, которая защищает их, даже если сам файл паролей скомпрометирован, но в то же время мы должны иметь возможность проверить правильность пароля пользователя.
Несвязанное примечание: в старые времена Интернета, когда вы нажимали ссылку «забыл мой пароль», веб-сайты отправляли вам по электронной почте ваш пароль в виде обычного текста. Вероятно, они хранили их где-то в базе данных. Когда хакеры получали доступ к своей базе данных, они получали доступ ко всем паролям. Поскольку многие пользователи использовали один и тот же пароль на нескольких веб-сайтах, это было огромной проблемой безопасности. К счастью, в настоящее время это не обычная практика.
Теперь возникает вопрос: как лучше всего хранить пароли? Я бы счел это решение ( Stormpath службы аутентификации и управления пользователями) чертовски идеальным:
Очевидно, что вы не гугл или банк, так что это избыточное решение для вас. Но тогда возникает вопрос: какой уровень безопасности требует ваш проект, сколько у вас времени и денег?
Для многих приложений, хотя это и не рекомендуется, хранение жестко закодированного пароля в коде может быть достаточно хорошим решением. Однако, легко добавив пару дополнительных шагов безопасности из приведенного выше списка, вы можете сделать свое приложение намного более безопасным.
Например, предположим, что шаг 1 не является приемлемым решением для вашего проекта. Вы не хотите, чтобы пользователи вводили пароль каждый раз, или вы даже не хотите, чтобы пользователи знали пароль. Тем не менее, у вас где-то есть конфиденциальная информация, и вы хотите ее защитить. У вас есть простое приложение, нет сервера для хранения ваших файлов, или это слишком хлопотно для вашего проекта. Ваше приложение работает в средах, в которых невозможно безопасно хранить файлы. Это один из худших случаев, но все же с некоторыми дополнительными мерами безопасности вы можете получить гораздо более безопасное решение. Например, вы можете сохранить конфиденциальную информацию в файле и зашифровать его. Вы можете жестко запрограммировать закрытый ключ шифрования в коде. Вы можете обфускировать код, чтобы кому-то было труднее его взломать.по этой ссылке . (Я хочу еще раз предупредить вас, что это не на 100% безопасно. Умный хакер с правильными знаниями и инструментами может это взломать. Но, исходя из ваших требований и потребностей, это может быть достаточно хорошим решением для вас).
Этот вопрос показывает, как хранить пароли и другие данные в зашифрованном файле: 256-битное шифрование на основе паролей AES Java
MD5 - это алгоритм хеширования, а не алгоритм шифрования, короче говоря, вы не можете вернуться к хешированию, вы можете только сравнивать. В идеале его следует использовать при хранении информации для аутентификации пользователя, а не имени пользователя и пароля db. Имя пользователя db и pwd должны быть зашифрованы и сохранены в файле конфигурации, по крайней мере.