Как обезопасить пароли базы данных в PHP?

404

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

user18359
источник
1
Для полной безопасности вам необходимо установить ssl-соединение, иначе любой пользователь в вашей сети все равно сможет прослушать введенный вами пароль.
Чарльз Ма
1
Вы имеете в виду пароли пользователей или пароль базы данных, используемые в строке подключения?
Озгур Озцитак
4
Пароль базы данных, используемый в строке подключения. Спасибо!
user18359 19.09.08

Ответы:

238

Несколько человек неправильно восприняли это как вопрос о том, как хранить пароли в базе данных. Это не правильно. Речь идет о том , как сохранить пароль , который позволяет получить в базе данных.

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

user11318
источник
8
Спасибо. Если я правильно понимаю, файл php будет включать в себя файл конфигурации, позволяющий использовать пароль. Например, я создаю файл с именем app1_db_cfg.php, в котором хранятся логин, pword и имя базы данных. Тогда моя страница application.php содержит app1_db_cfg.php, и я в деле!
user18359 19.09.08
28
Я согласен, что конфиг должен быть должным образом защищен. Однако знать, как это сделать, - дело системных администраторов, а не разработчиков. Я не согласен с ценностью сильного шифрования в этом случае. Если вы не можете защитить свой конфигурационный файл, что заставляет вас думать, что вы можете защитить свои ключи?
user11318 21.09.08
10
Я предпочитаю использовать учетную запись базы данных, которой разрешен доступ к базе данных только с веб-сервера. И тогда я не пытаюсь зашифровать конфигурацию, я просто храню ее вне веб-корня.
gnud
11
Я использую переменную окружения apache, чтобы установить путь, так что даже путь к файлу неизвестен в исходном коде. Это также позволяет использовать разные пароли для разработки и производства в зависимости от настроек Apache на сервере.
Geedew
15
Помните, что даже файлы, хранящиеся вне каталога, доступного через Интернет, должны быть прочитаны сценарием, который их использует. Если кто-то включает этот файл, а затем выгружает данные из файла, он увидит пароль.
Рик Мак Гиллис
104

Если вы размещаете на чужом сервере и не имеете доступа за пределами своего корня, вы всегда можете поместить свой пароль и / или соединение с базой данных в файл, а затем заблокировать файл с помощью .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>
Kellen
источник
3
Спасибо, это именно то, что я искал.
Дэвид Гладфелтер
28
Определенно, но если у кого-то есть доступ к оболочке, ваша учетная запись все равно будет взломана.
Келлен
4
Это плохая практика, потому что вы можете случайно зафиксировать свои учетные данные в хранилище.
Porlune
2
@Ankit: если не-дружественный пользователь может загрузить файл на сервер и выполнить его, значит, сервер не настроен должным образом.
Келлен
6
@Porlune: разработчики должны заставить свою систему контроля версий игнорировать файл паролей, т. Е. Используя .gitignore. Но да, следует позаботиться о файлах, которые содержат конфиденциальные данные.
Келлен
45

Самый безопасный способ - вообще не указывать информацию в вашем PHP-коде.

Если вы используете Apache, это означает, что вы должны указать детали подключения в файле httpd.conf или в файле виртуальных хостов. Если вы сделаете это, вы можете вызвать mysql_connect () без параметров, что означает, что PHP никогда не будет выводить вашу информацию.

Вот как вы указываете эти значения в этих файлах:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

Затем вы открываете свое соединение MySQL следующим образом:

<?php
$db = mysqli_connect();

Или вот так:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Ларс Нистрем
источник
1
Пожалуйста, проверьте правильные значения ini_get («значения по умолчанию») php.net/manual/en/class.mysqli.php
Val
4
да, но любой пользователь (или хакер, злоупотребляющий плохо написанным PHP-скриптом) может прочитать пароль через ini_get().
Marki555
1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Как вы справляетесь с этим?
tonix
2
Marki555 говорит, что злоумышленник, который может запускать код PHP, может также вызывать функции PHP, что, очевидно, является правдой и с чем-то не справиться. Я также хотел бы добавить, что я больше не следую совету, который я даю в этом ответе, а вместо этого использую переменные среды. Концепция аналогична: не храните свои учетные данные в коде, а вставляйте их как-нибудь. Это действительно не имеет значения, если вы используете ini_get()или getenv().
Ларс Нистрем
2
@DeepBlue Если вы можете внедрить ini_get (), вы также можете внедрить file_get_contents (anypath). Пока у php есть способ получить пароль, так же как и любой вредоносный код.
Вареса
40

Храните их в файле вне веб-корня.

da5id
источник
29
А также, как упоминалось в другом месте, за пределами контроля источника.
Фрэнк Фармер
6
мы сможем включить это? например, в PHP мы можем тогда сделать include('../otherDirectory/configfile.conf')?
MTK
1
Вы все предлагаете хранить учетные данные за пределами wwwroot. Хорошо, я понимаю фон безопасности. Но как его хранить в контроле версий (пример конфигурации)? Обычно wwwroot является корнем git repo, поэтому, если есть что-то снаружи - это будет вне VC. Представьте, что новый разработчик пытается настроить локальный экземпляр для разработки - откуда ему знать магию типа «возьми этот файл, скопируй его наружу и заполни»?
Крестный отец
@TheGodfather Идея состоит в том, что у нового разработчика должны быть свои собственные учетные данные для их собственной среды разработки. Хотя хорошей практикой является наличие файла readme с инструкциями или комментариями в коде, указывающего, как его следует настроить (но не фактические данные).
PhoneixS
@TheGodfather, файл readme?
Пейсер
35

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

pdavis
источник
85
что если админ умирает?
Раду Мурзеа
36
@RaduMurzea это смешно. Когда вы слышали о смерти Sys Admins? Они как Макдональдс, они просто появляются / исчезают из ниоткуда!
ILikeTacos
13
@Radu Murzea У вас есть 2 или более администраторов, тогда у вас есть четность, как в массиве рейдов. Вероятность отказа нескольких дисков одновременно намного ниже.
element11
5
а когда серверы перезагружаются? Как насчет времени, которое требуется, чтобы разбудить администратора, чтобы он набрал пароль в..etc.etc. лол
Джон Хант
1
Не уверен, что вы подразумеваете под «хранится в памяти». Веб-приложения PHP обычно ничего не хранят в памяти дольше, чем время, необходимое для ответа на отдельный запрос о просмотре страницы.
BDSL
15

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

  1. Создайте пользователя ОС для своего приложения. Смотрите http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Создайте (не сеансовую) переменную среды ОС для этого пользователя с паролем
  3. Запустите приложение от имени этого пользователя

Преимущества:

  1. Вы не будете проверять ваши пароли в системе контроля версий случайно, потому что вы не можете
  2. Вы случайно не испортите права доступа к файлам. Ну, вы можете, но это не повлияет на это.
  3. Может быть прочитано только пользователем root или тем пользователем. Root может прочитать все ваши файлы и ключи шифрования в любом случае.
  4. Если вы используете шифрование, как вы храните ключ безопасно?
  5. Работает х-платформа
  6. Обязательно не передавайте envvar недоверенным дочерним процессам

Этот метод предложен Heroku, которые очень успешны.

Нил Макгиган
источник
11

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

mysql_connect("localhost", "me", "mypass");

В противном случае лучше сбросить учетные данные после оператора connect, поскольку учетные данные, которые не находятся в памяти, не могут быть прочитаны из памяти ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Боб Фэнджер
источник
9
Если у кого-то есть доступ к памяти, вы все равно облажались. Это бессмысленная фальшивая безопасность. Вне webroot (или, по крайней мере, защищенный .htaccess, если у вас нет доступа выше вашего webroot), это единственный безопасный вариант.
Uliwitness
2
@uliwitness - Это все равно, что сказать, что если кто-то может взломать замок вашего сетевого операционного центра с помощью ацетиленовой горелки, это означает, что дверь также является поддельной защитой. Хранение конфиденциальной информации, связанной с самой узкой областью, всегда имеет смысл.
Люк А. Лебер
1
Как насчет echo $ db_user или печати $ db_pass? Даже разработчики в одной команде не должны быть в состоянии выяснить производственные полномочия. Код не должен содержать ничего для печати с информацией для входа в систему.
Мохаммед Джорайд
8

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

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

  • Не используйте комбинацию имени пользователя / пароля для чего-либо еще
  • Сконфигурируйте сервер базы данных так, чтобы он принимал соединения от веб-хоста только для этого пользователя (локальный хост даже лучше, если БД находится на одном компьютере). Таким образом, даже если учетные данные раскрыты, они никому не нужны, если у них нет другого доступа к машина.
  • Обфусцируйте пароль (даже ROT13 подойдет), он не будет защищен, если некоторые получат доступ к файлу, но, по крайней мере, предотвратит случайный просмотр его.

Питер

Vagnerr
источник
8

Если вы используете PostgreSQL, он ~/.pgpassавтоматически ищет пароли. Смотрите руководство для получения дополнительной информации.

Джим
источник
8

Ранее мы сохраняли БД user / pass в файле конфигурации, но с тех пор достигли параноидального режима - приняв политику Defence in Depth .

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

Мы перешли на хранение пользовательских / передаваемых переменных среды, установленных в Apache VirtualHost. Эта конфигурация доступна для чтения только пользователю root - надеюсь, ваш пользователь Apache не работает от имени пользователя root.

С этим связано то, что теперь пароль находится в глобальной переменной PHP.

Чтобы снизить этот риск, у нас есть следующие меры предосторожности:

  • Пароль зашифрован. Мы расширяем класс PDO, чтобы включить логику для расшифровки пароля. Если кто-то прочитает код, где мы устанавливаем соединение, не будет очевидно, что соединение устанавливается с зашифрованным паролем, а не с самим паролем.
  • Зашифрованный пароль перемещается из глобальных переменных в приватную переменную . Приложение делает это немедленно, чтобы уменьшить окно, в котором значение доступно в глобальном пространстве.
  • phpinfo()выключен. PHPInfo - это простая цель, чтобы получить обзор всего, включая переменные среды.
Кортни Майлз
источник
6

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

Если у вас нет средств, позволяющих процессу php-сервера получать доступ к базе данных, это почти все, что вы можете сделать.

Крис
источник
5

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

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

Джейсон Уодсворт
источник
1
К сожалению, PHP-файл конфигурации может быть прочитан phpinfo (), и если кто-то оставит какой-нибудь тестовый скрипт позади, удачливый злоумышленник сможет прочитать пароль. Вероятно, лучше оставить пароль подключения в файле за пределами корневого каталога веб-сервера. Тогда единственный способ получить к нему доступ - либо с помощью оболочки, либо путем выполнения произвольного кода, но в этом случае вся безопасность теряется в любом случае.
MarioVilas
5

Просто положить его в конфигурационный файл куда-то, как обычно. Просто убедитесь, что вы:

  1. запретить доступ к базе данных с любых серверов за пределами вашей сети,
  2. позаботьтесь о том, чтобы случайно не показывать пароль пользователям (в сообщении об ошибке или через файлы PHP, случайно используемые как HTML и т. д.)
Marijn
источник
5

Мы решили это следующим образом:

  1. Используйте memcache на сервере, с открытым соединением с другого сервера паролей.
  2. Сохраните в memcache пароль (или даже весь зашифрованный файл password.php) плюс ключ дешифрования.
  3. Веб-сайт вызывает ключ memcache, содержащий парольную фразу файла паролей, и расшифровывает в памяти все пароли.
  4. Сервер паролей отправляет новый зашифрованный файл паролей каждые 5 минут.
  5. Если вы используете зашифрованный password.php в своем проекте, вы помещаете аудит, который проверяет, был ли этот файл затронут внешне - или просмотрен. Когда это происходит, вы автоматически можете очистить память, а также закрыть сервер для доступа.
Аси Азулай
источник
4

Дополнительный прием заключается в использовании отдельного файла конфигурации PHP, который выглядит следующим образом:

<?php exit() ?>

[...]

Plain text data including password

Это не мешает вам правильно устанавливать правила доступа. Но в случае, если ваш веб-сайт взломан, «require» или «include» просто выйдут из скрипта в первой строке, поэтому получить данные еще сложнее.

Тем не менее, никогда не допускайте конфигурационные файлы в каталог, к которому можно получить доступ через Интернет. У вас должна быть папка «Web», содержащая ваш код контроллера, css, картинки и js. Это все. Все остальное идет в автономные папки.

е-удовлетворяться
источник
но тогда как скрипт php считывает учетные данные, хранящиеся в файле?
Кристофер Махан
3
Вы используете fopen (), как для обычного текстового файла.
Э-Уда
2
@ E-удовлетворительно хорошо, это помешает хакеру require/ includeно как это сделать fopen?
dmnc
«это не мешает вам правильно устанавливать правила доступа»
e-sat
@ э-сат, это довольно умно. Интересно, почему никто не подумал об этом. Тем не менее , все еще уязвимы для проблемы с копией редактора. feross.org/cmsploit
Пейсер
4

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

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

алчный
источник
3
Нет смысла снова шифровать пароль . Кто-то, кто может получить незашифрованный пароль, может также получить любой пароль, необходимый для расшифровки пароля. Однако использование ACL & .htaccess - хорошая идея.
Uliwitness
2
@uliwitness Я думаю, что вы, возможно, неправильно поняли - что вы подразумеваете под « снова зашифровывать »? Это всего лишь одно шифрование. И вы не хотите использовать парольные фразы (предназначенные для использования человеком) для его шифрования, достаточно сильное управление ключами, например, защищенное ОС, таким образом, что простой доступ к файловой системе не предоставит доступ к ключу.
AviD
3
Шифрование не волшебство - вместо защиты ключа AES с помощью ACL вы можете просто сохранить пароль там. Нет разницы между доступом к ключу AES или дешифрованному паролю, шифрование в этом контексте - просто змеиный жир.
MarioVilas
@MarioVilas что? Если пароль зашифрован, а ключ шифрования защищен ОС, то в чем разница? Шифрование не волшебство - оно просто уплотняет всю секретность в меньший ключ шифрования. Вряд ли snakeoil, в этом контексте он просто перемещает всю эту секретность в ОС.
AviD
6
@ AviD Почему ОС может защитить ключ, но не сами данные? Ответ: он может защитить оба, поэтому шифрование не очень помогает. Было бы иначе , если только данные были сохранены , и ключ шифрования был получен, например, из пароля , который должен был быть набран пользователем.
МариоВилас