Как я могу защитить имя пользователя и пароль MySQL от декомпиляции?


Java .class файлы могут быть декомпилированы довольно легко. Как я могу защитить свою базу данных, если мне нужно использовать данные для входа в код?

6 74

6 ответов:

никогда не вводите жесткие пароли в свой код. Это было поднято недавно в Топ-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-файл настроек и прочитать учетные данные для входа, но это не является угрозой безопасности, потому что пользователь знал учетные данные для начала.

второй случай: попытка скрыть учетные данные для входа от пользователя

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

правильный случай: использование многоуровневого архитектура

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

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

основной порядок операций:

  1. клиент аутентифицируется с помощью уровня бизнес-логики, используя личные данные пользователя имя пользователя/пароль. Имя пользователя и пароль известны пользователю и никак не связаны с учетными данными для входа в базу данных.
  2. если проверка подлинности прошла успешно, клиент отправляет запрос на уровень бизнес-логики с запросом некоторой информации из базы данных. Например, инвентаризация товаров. Обратите внимание, что запрос клиента не является SQL-запросом; это удаленный вызов процедуры, такой как getInventoryList.
  3. бизнес-логики подключается к базе данных и получает запрашиваемая информация. Уровень бизнес-логики отвечает за формирование безопасного SQL-запроса на основе запроса пользователя. Любые параметры SQL-запроса должны быть очищены, чтобы предотвратить атаки SQL-инъекций.
  4. уровень бизнес-логики отправляет список инвентаризации обратно в клиентское приложение.
  5. клиент отображает список инвентаризации для пользователя.

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

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

У Ruby есть малоизвестный модуль под названием DBI:: DBRC для такого использования. Я не сомневаюсь, что Java имеет эквивалента. В любом случае, это не трудно написать.

вы пишете веб-приложение? Если это так, используйте JNDI, чтобы настроить его внешне для приложения. Обзор доступен здесь:

JNDI обеспечивает равномерный путь для приложение для поиска и удаленного доступа услуги по сети. Дистанционное управление сервис может быть любым корпоративным сервисом, включая службу обмена сообщениями или специфическое для приложения обслуживание, но, конечно, приложение JDBC является интересует в основном база данных услуга. Однажды объект источника данных является создан и зарегистрирован в JNDI служба именования, приложение может использовать API JNDI для доступа к этому источнику данных объект, который затем может быть использован для подключения к источнику данных представляет.

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

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

hash("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
hash("hbllo") = 58756879c05c68dfac9866712fad6a93f8146f337a69afe7dd238f3364946366

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

несвязанной ноте: в старые времена интернета, когда вы нажимаете ссылку "Забыли мой пароль", веб-сайты будут отправлять вам по электронной почте свой обычный текстовый пароль. Вероятно, они хранили их где-то в базе данных. Когда хакеры получат доступ к своей базе данных, они получат доступ ко всем паролям. Поскольку многие пользователи используют один и тот же пароль на нескольких веб-сайтах, это огромная проблема безопасности. К счастью, сегодня это не обычная практика.

теперь возникает вопрос: каков наилучший способ хранения паролей? Я бы рассмотрел это (проверка подлинности и управление пользователями сервиса stormpath х) решение довольно чертовски идеальное:

  1. ваш пользователь вводит учетные данные, и это проверяется по хэш пароля
  2. хэши паролей генерируются и сохраняются, а не пароли
  3. хэши выполняются несколько раз
  4. хэши генерируется с помощью случайно сгенерированной соли
  5. хэш шифруется с помощью закрытого ключа
  6. закрытый ключ хранится в физически другом месте, чем хэши
  7. закрытые ключи на основе времени моды обновляется
  8. зашифрованные хэши делятся на куски
  9. эти куски хранятся в физически разных местах

очевидно, что вы не google или банк, так что это излишнее решение для вас. Но тогда возникает вопрос: сколько безопасности требует ваш проект, сколько времени и денег у вас есть?

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

например, предположим, что Шаг 1 не является приемлемым решением для вашего проекта. Вы не хотите, чтобы пользователи введите пароль каждый раз, или вы даже не хотите/нужно, чтобы пользователи знали пароль. Тем не менее у вас есть конфиденциальная информация где-то, и вы хотите защитить это. У вас есть простое приложение, нет сервера для хранения файлов или это слишком много хлопот для вашего проекта. Приложение работает в средах, где невозможно обеспечить безопасное хранение файлов. Это один из худших случаев, но все же с некоторыми дополнительными мерами безопасности вы можете иметь гораздо более безопасное решение. Например, вы можно хранить конфиденциальную информацию в файле, и вы можете зашифровать файл. Вы можете иметь закрытый ключ шифрования жестко закодирован в коде. Вы можете запутать код, поэтому вам будет немного сложнее его взломать. Для этого существует множество библиотек, см. этой ссылке. (Я хочу предупредить вас еще раз, что это не на 100% безопасно. Умный хакер с правильными знаниями и инструментами может взломать это. Но на основе ваших требований и потребностей, это может быть достаточно хорошее решение для вас).

этот вопрос показывает, как хранить пароли и другие данные в зашифрованном файле: Java 256-битное шифрование на основе пароля AES

MD5-это алгоритм хеширования, а не алгоритм шифрования, короче говоря, вы не можете вернуться в хеш, вы можете только сравнить. В идеале он должен использоваться при хранении информации аутентификации пользователя, а не имени пользователя и пароля БД. имя пользователя db и pwd должны быть зашифрованы и сохранены в файле конфигурации, чтобы сделать как минимум.