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

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


person Jakob Cosoroaba    schedule 14.01.2009    source источник
comment
Надеюсь, вы не против, я изменил теги на ваш вопрос. Я удалил имя пользователя и пароль и добавил обратное проектирование и декомпиляцию. Я считаю, что они более наглядны, чем оригиналы. Кстати, отличный вопрос по основам!   -  person William Brendel    schedule 14.01.2009
comment
Обратите внимание, что тот факт, что вы используете Java, здесь неуместен. Наличие жестко запрограммированных паролей на любом языке почти одинаково проблематично (двоичные строки также показывают строковые константы в программах на C).   -  person Joachim Sauer    schedule 14.01.2009
comment
@saua: Верно, но, возможно, кто-нибудь опубликует образец кода о том, как разделять имена пользователей и пароли в Java. Я мог бы даже сделать это сам, если бы у меня было время.   -  person William Brendel    schedule 14.01.2009
comment
Я добавил код Java, демонстрирующий это. Код на самом деле довольно простой, но этого должно быть достаточно, чтобы кто-то начал.   -  person William Brendel    schedule 14.01.2009
comment
@Midday: Не могли бы вы предоставить дополнительную информацию о своем приложении? В комментариях, кажется, есть некоторая путаница. Например, где запускается это приложение? На машине клиента? На удаленном сервере? Локальный сервер? В зависимости от вашего ответа могут быть более серьезные архитектурные проблемы.   -  person William Brendel    schedule 14.01.2009
comment
Я заметил, что многие ответы думают, что вы пытаетесь скрыть имя пользователя / пароли от неавторизованного пользователя, пока пользователь, запускающий приложение, в порядке. Я считаю, что вы хотите скрыть пароль от ВСЕХ. Пожалуйста, поясните это в вопросе.   -  person pek    schedule 14.01.2009
comment
Например, предположим, что учетные данные используются для подключения к серверу, на который никто, кроме приложения, не может войти.   -  person pek    schedule 14.01.2009


Ответы (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 после отображения диалогового окна с запросом имени пользователя и пароля. Когда вам нужно подключиться к базе данных, вы можете просто использовать методы getUsername и getPassword для получения сохраненных значений. Учетные данные для входа не будут жестко закодированы в ваших двоичных файлах, поэтому декомпиляция не представляет угрозы безопасности.

Важное примечание: файлы настроек представляют собой просто текстовые XML-файлы. Убедитесь, что вы предприняли соответствующие шаги для предотвращения просмотра сырых файлов неавторизованными пользователями (разрешения UNIX, разрешения Windows и т. Д.). В Linux, по крайней мере, это не проблема, потому что вызов Preferences.userNodeForPackage создаст XML-файл в домашнем каталоге текущего пользователя, который в любом случае не читается другими пользователями. В Windows ситуация может быть иной.

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

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

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

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

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

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

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

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

Основной порядок действий:

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

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

person William Brendel    schedule 14.01.2009
comment
Как именно это мешает кому-либо получить имя пользователя / пароль? Разве ты не можешь тогда просто прочитать это из файла? - person Joe Phillips; 14.01.2009
comment
Как я сказал в своем ответе, если ваши права доступа к файлам установлены правильно, только пользователь, запускающий программу, имеет доступ для чтения к этому файлу настроек. В средах UNIX это делается автоматически. Windows может потребовать дополнительных действий (я действительно не уверен, так как я мало пользуюсь Windows). - person William Brendel; 14.01.2009
comment
Я думаю, что идея в том, что пользователь, запускающий приложение, не тот, от кого вы пытаетесь от него избавиться. Если это так, вам придется его зашифровать. - person Michael Haren; 14.01.2009
comment
Да, Майкл прав. По сути, идея состоит в том, что вы уже знаете имя пользователя / пароль, поэтому нет необходимости скрывать его от себя. Однако он будет скрыт от других пользователей через права доступа к файлам. - person William Brendel; 14.01.2009
comment
@Michael - шифрование не поможет сохранить пароль от пользователя, запускающего приложение. Это просто подталкивает проблему к попытке защитить ключ, и в любом случае пользователю понадобится какой-то API где-то, чтобы использовать пароль. - person frankodwyer; 14.01.2009
comment
Если вы развертываете (пример) приложение для редактирования БД для пользователя и не хотите, чтобы он знал имя пользователя и пароль базы данных, значит, вы неправильно спроектировали решение, и клиентское программное обеспечение должно взаимодействовать с сервером (через например, веб-сервис), который выполняет работу с БД. - person JeeBee; 14.01.2009
comment
@JeeBee: Совершенно верно. В своем ответе я предположил, что пользователь знает учетные данные, и проблема заключается в том, чтобы найти способ сохранить эту информацию вне скомпилированного кода. Попытки предоставить ненадежным пользователям доверенным доступ к любой системе всегда заканчиваются неудачей. Хороший комментарий, Джиби. - person William Brendel; 14.01.2009
comment
Я добавил дополнительную информацию к своему исходному ответу. Он охватывает основы использования трехуровневой архитектуры, которая, вероятно, лучше всего соответствует тому, что хотел исходный плакат. - person William Brendel; 14.01.2009
comment
Это действительно прекрасный исчерпывающий ответ. - person JeeBee; 14.01.2009
comment
Я не совсем понимаю ваше высказывание: Клиент аутентифицируется на уровне бизнес-логики, используя личное имя пользователя / пароль пользователя. Имя пользователя и пароль известны пользователю и никак не связаны с учетными данными для входа в базу данных. Уровень бизнес-логики - это веб-сервис (написанный на java, php и т. Д.)? Если да, то где хранятся учетные данные пользователя? Perharps в файле конфигурации на платформе веб-сервисов? Но что, если мы хотим создать новые учетные записи для регистрации новых пользователей? Что тогда? Хотя можно хешировать эти учетные данные и отправлять их по сети в бизнес-логику. - person John Astralidis; 21.05.2015
comment
Я думаю, вы упускаете из виду суть цитируемой статьи. Вы не просто храните пароли в файле или базе данных, вы должны хранить пароли вне кода в сильно защищенном, зашифрованном файле конфигурации или базе данных. В противном случае, если вы можете установить правильные разрешения для файла паролей, вы могли бы установить такие же разрешения для .class, которые вы не хотите, чтобы люди декомпилировали. - person Tristan; 18.05.2017
comment
Как можно реализовать тот же сценарий с помощью приложения Node.js? Можно использовать утилиту Linux? - person Nah; 06.11.2017
comment
Из любопытства, почему бы просто не сохранить хешированные учетные данные для приложения в файле на веб-сервере, который можно получить с помощью защищенного паролем HTTP-запроса? Естественно, трехуровневая система будет работать лучше, но если это не вариант, кажется, что файл настроек на Java лучше подходит только для хранения учетных данных, необходимых для сбора хешированных учетных данных с сервера. Таким образом, ничего важного не сохраняется ни в двоичном файле приложения, ни в системе пользователя. - person ViaTech; 07.08.2018

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

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

person Keltia    schedule 14.01.2009
comment
Хотя это немного упрощает изменение паролей в дальнейшем, это не решает основную проблему безопасности. - person Brian Knoblauch; 14.01.2009
comment
Да. См. Также ответ Уильяма Бренделя. - person Keltia; 14.01.2009
comment
Метод, на который указали мы с Келтией, является общепринятым способом решения этой проблемы. Разделение учетных данных для входа в систему от скомпилированного кода - одна из основных практик обеспечения безопасности программного обеспечения. Помещение учетных данных для входа в отдельный файл - эффективный способ добиться этого. - person William Brendel; 14.01.2009
comment
Более того, тот факт, что информация о вашей конфигурации находится в виде простого текстового файла, должен быть отменен ограничениями операционной системы. Например, в UNIX файл с открытым текстом должен принадлежать пользователю, запускающему программу, и иметь разрешения 0600, поэтому только владелец может его прочитать. - person William Brendel; 14.01.2009
comment
Итак, файл может быть прочитан только пользователем, запустившим программу. Здорово. Это ничего не решает. :-) Я, пользователь, от которого мы пытаемся сохранить пароль в секрете, могу прочитать его так же легко, как и приложение ... - person Brian Knoblauch; 14.01.2009
comment
@Brian: Вы пытаетесь предоставить ненадежным пользователям доверенным доступ к системе и хотите, чтобы он был безопасным? Это просто невозможно. В этом случае вам действительно нужно переосмыслить свою архитектуру. Вот почему защита от копирования не работает (она должна давать ненадежным сторонам возможность расшифровать контент). - person William Brendel; 14.01.2009
comment
Такой способ затруднит доступ, но никоим образом ничего не защитит. Даже если данные в файле зашифрованы, код все равно можно декомпилировать (и это моя основная проблема на данный момент). Итак, я должен поместить разумные данные в файл, зашифровать и скрыть код, который имеет дело с шифрованием / дешифрованием ... - person marcolopes; 09.03.2014

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

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

person Tim Howland    schedule 14.01.2009
comment
предоставленная ссылка плохая - person James Oravec; 15.04.2016

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

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

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

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

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

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

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

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

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

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

person Caner    schedule 19.10.2017

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

person Aaron Digulla    schedule 08.10.2014
comment
Где-то в исходном коде все еще нужно расшифровать зашифрованный пароль для создания соединения, этот считающийся пароль все еще существует. - person Bear0x3f; 11.02.2017

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

person renegadeMind    schedule 14.01.2009
comment
Я слышал о людях, которые генерируют все возможные комбинации строк и хранят соответствующие хеши MD5. Поэтому, когда они находят чей-то хеш MD5, они просто находят хеш, который они сохранили, и получают соответствующую строку. - person Nav; 23.02.2016