Як захистити паролі бази даних в PHP?


404

Коли програма PHP з'єднує базу даних, звичайно, потрібно пройти логін та пароль. Якщо я використовую єдиний логін для мінімального дозволу для своєї програми, PHP повинен десь знати, що цей логін та пароль. Який найкращий спосіб захистити цей пароль? Здається, що просто записати його в PHP-коді - це не дуже гарна ідея.


1
Щоб бути повністю безпечним, вам потрібно встановити з'єднання ssl, інакше кожен у вашій мережі все ще може нюхати введений вами пароль.
Чарльз Ма

1
Ви маєте на увазі паролі користувачів або пароль бази даних, використовуваний у рядку з'єднання?
Ozgur Ozcitak

4
Пароль бази даних, який використовується в рядку з'єднання. Дякую!
користувач18359

Відповіді:


238

Кілька людей неправильно читають це як питання про збереження паролів у базі даних. Це неправильно. Йдеться про те, як зберігати пароль, який дозволяє вам потрапити до бази даних.

Звичайним рішенням є переміщення пароля з вихідного коду у файл конфігурації. Потім залиште адміністрацію та закріпіть цей файл конфігурації до системних адміністраторів. Таким чином розробникам не потрібно нічого знати про виробничі паролі, і немає запису пароля у вашому джерелі управління.


8
Дякую. Якщо я правильно це розумію, тоді файл php буде включати в конфігураційний файл, що дозволяє йому використовувати пароль. наприклад, я створюю файл під назвою "app1_db_cfg.php", який зберігає ім'я для входу, pword та db. Тоді моя сторінка application.php включає в себе "app1_db_cfg.php", і я працюю!
користувач18359

28
Я погоджуюся, що конфігурацію потрібно належним чином захистити. Однак знати, як це зробити, це справа системних адміністраторів, а не розробників. Я не погоджуюся з значенням сильного шифрування в цьому випадку. Якщо ви не можете захистити свій конфігураційний файл, чому ви вважаєте, що можете захистити свої ключі?
користувач11318

10
Я вважаю за краще використовувати обліковий запис бази даних, дозволений доступ до бази даних тільки з веб-сервера. І тоді я не переймаюся шифруванням конфігурації, я просто зберігаю її поза веб-коренем.
gnud

11
Я використовую змінну середовища apache для встановлення шляху так, що навіть вихідний шлях до файлу невідомий у вихідному коді. Це також добре дозволяє встановити інший пароль для розробки та виробництва, виходячи з того, які параметри Apache є на сервері
geedew

15
Будь ласка, майте на увазі, що навіть файли, що зберігаються за межами веб-доступного каталогу, повинні читати сценарій, який їх використовує. Якщо хтось включає цей файл, а потім скидає дані з файлу, вони побачать пароль.
Рік Мак-Гілліс

104

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

<files mypasswdfile>
order allow,deny
deny from all
</files>

3
Дякую, саме це я шукав.
Девід Гладфелтер

28
Безумовно, але якщо хтось має доступ до оболонки, весь ваш рахунок все одно порушений.
kellen

4
Це погана практика, оскільки ви можете випадково скористатися своїми обліковими записами в сховище.
Порлуне

2
@Ankit: Якщо можливо недружнє завантаження файлу на сервер і виконання його, сервер не налаштований належним чином.
kellen

6
@Porlune: Розробники повинні змусити їх систему управління версіями ігнорувати файл паролів, тобто за допомогою .gitignore. Але так, слід бути обережним із файлами, що містять конфіденційні дані.
kellen

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()Як ти з цим справляєшся?
тонікс

2
Marki555 говорить, що зловмисник, який може запустити PHP-код, також може викликати функції PHP, що, очевидно, правда і неможливо щось зробити. Я також хотів би додати, що я більше не дотримуюся порад, які я даю у цій відповіді сам, а натомість використовую змінні середовища. Концепція схожа, хоча: не зберігайте свої облікові дані в коді, а вводите їх якось. Це не має значення, використовуєте ви ini_get()чи getenv().
Lars Nyström

2
@DeepBlue Якщо ви можете ввести ini_get (), ви можете також ввести file_get_contents (будь-який шлях). Поки у php є спосіб дійти до пароля, такий буде і будь-який шкідливий код.
Вареза

40

Збережіть їх у файлі поза веб-коренем.


29
А також, як було зазначено в іншому місці, поза контролем джерел.
Френк Фермер

6
ми могли б включити його? наприклад, в PHP ми можемо тоді це зробити include('../otherDirectory/configfile.conf')?
mtk

1
Ви всі пропонуєте зберігати облікові дані за межами wwwroot. Гаразд, я розумію фон безпеки. Але як він повинен зберігатися в контролі версій тоді (зразок конфігурації)? Зазвичай wwwroot є коренем git repo, тому, якщо є щось зовні - це буде поза VC. Уявіть, що новий розробник намагається налаштувати локальний екземпляр для розробки - як він повинен знати магію на кшталт "взяти цей файл, скопіювати його зовні та заповнити"?
Хрещений батько

@TheGodfather Ідея полягає в тому, щоб новий розробник мав власні облікові дані для власного середовища розробки. Хоча є хорошою практикою читати з інструкціями чи коментарями в коді, які вказують, як слід його налаштувати (але не фактичні дані).
PhoneixS

@TheGodfather, файл readme?
Pacerier

35

Для надзвичайно безпечних систем ми шифруємо пароль бази даних у файлі конфігурації (який сам захищений системним адміністратором). Після запуску програми / сервера програма потім запитує системного адміністратора на ключ розшифровки. Потім пароль з бази даних зчитується з конфігураційного файла, розшифровується та зберігається в пам'яті для подальшого використання. Все ще не на 100% захищений, оскільки він зберігається в розшифрованій пам'яті, але вам доведеться викликати це "досить безпечно" в якийсь момент!


85
що робити, якщо адміністратор помре?
Раду Мурзеа

36
@RaduMurzea це смішно. Коли ви чули про те, як помирає Сис Адмінс? Вони як Макдональдс, вони просто з'являються / зникають з нізвідки!
ILikeTacos

13
@Radu Murzea Просто у вас 2 або більше адміністраторів, тоді ви маєте паритет, як рейдовий масив. Шанси виходу з ладу декількох приводів одночасно набагато нижчі.
елемент11

5
що робити, коли сервери перезапускаються? Як щодо часу, який потрібно розбудити адміністратора, щоб він набрав пароль в..etc.etc. lol
Джон Хант

1
Не впевнений, що ви маєте на увазі під "збереженим у пам'яті". Веб-додатки PHP зазвичай не зберігають нічого в пам'яті довше, ніж потрібно часу для відповіді на індивідуальний запит про перегляд сторінки.
bdsl

15

Це рішення є загальним, оскільки воно корисне як для відкритих, так і для закритих програм.

  1. Створіть користувача ОС для своєї програми. Дивіться http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Створіть змінну середовища (без сеансу) ОС для цього користувача з паролем
  3. Запустіть програму як цього користувача

Переваги:

  1. Ви не будете перевіряти ваші паролі в контролі джерела випадково, тому що не можете
  2. Ви не випадково викрутите дозволи на файл. Ну, може, але це не вплине на це.
  3. Читати може лише користувач root або той користувач. Корінь може будь-коли читати всі ваші файли та ключі шифрування.
  4. Якщо ви використовуєте шифрування, як ви надійно зберігаєте ключ?
  5. Працює x-платформа
  6. Будьте впевнені, щоб не передавати енввар недовіреним процесам дитини

Цей метод запропонований Хероку, які є дуже успішними.


11

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

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
Якщо хтось має доступ до пам'яті, ви все одно накрутили. Це безглузда підробка-безпека. Поза веб-коренею (або принаймні захищеною .htaccess, якщо ви не маєте доступу вище своєї веб-корені) - єдиний безпечний варіант.
uliwitness

2
@uliwitness - Це як би сказати, що лише тому, що хтось може прорізати замок вашого операційного центру мережею з ацетиленовим факелом, це означає, що двері також є фальшивою безпекою. Зберігати конфіденційну інформацію, прив’язану до максимально можливої ​​сфери, завжди має сенс.
Лука А. Лебер

1
Як щодо echo $ db_user або надрукування $ db_pass? Навіть розробники в одній команді не повинні мати можливість з'ясувати виробничі дані. Код не повинен містити нічого для друку про інформацію про вхід.
Мухаммед Джораїд

8

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

Крім того, ви знаходитесь у правильних рядках із мінімальним доступом до облікового запису, який використовується. Додайте до цього

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

Петро



8

Раніше ми зберігали DB / user DB у файлі конфігурації, але з тих пір потрапили в параноїдальний режим - прийнявши політику Defense в глибині .

Якщо ваша програма порушена, користувач матиме доступ до читання до вашого конфігураційного файлу, і тому зломщик може прочитати цю інформацію. Файли конфігурації також можуть потрапляти під контроль версій або копіюватися навколо серверів.

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

Суть цього в тому, що тепер пароль знаходиться в змінній Global PHP.

Для зменшення цього ризику у нас є такі запобіжні заходи:

  • Пароль шифрується. Ми розширюємо клас PDO, щоб включити логіку для розшифровки пароля. Якщо хтось читає код, де ми встановлюємо з'єднання, не буде очевидно, що з'єднання встановлюється зашифрованим паролем, а не самим паролем.
  • Зашифрований пароль переміщується з глобальних змінних у приватну змінну . Додаток робить це негайно, щоб зменшити вікно, яке значення доступне у глобальному просторі.
  • phpinfo()відключено. PHPInfo - це проста мета для отримання огляду всього, включаючи змінні середовища.

6

Помістіть пароль бази даних у файл, зробіть його лише для читання користувачеві, який обслуговує файли.

Якщо у вас є деякі засоби, які дозволяють лише дозволити процес роботи сервера PHP отримати доступ до бази даних, це майже все, що ви можете зробити.


5

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

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


1
На жаль, конфігураційний файл PHP може бути прочитаний програмою phpinfo (), і якщо хтось не залишить тестовий скрипт за щасливим зловмисником, він зможе прочитати пароль. Мабуть, найкраще залишити пароль з'єднання у файлі поза корінням веб-сервера. Тоді єдиний спосіб отримати доступ до нього - це або з оболонкою, або шляхом довільного коду, але в цьому сценарії вся безпека все одно втрачається.
MarioVilas

5

Просто помістити його в файл конфігурації десь так, як це робиться зазвичай. Просто переконайтесь, що ви:

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

5

Ми вирішили це таким чином:

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

4

Додатковим фокусом є використання окремого конфігураційного файла PHP, який виглядає так:

<?php exit() ?>

[...]

Plain text data including password

Це не заважає вам правильно встановити правила доступу. Але у випадку, коли ваш веб-сайт зламаний, "вимагати" або "включити" просто вийде зі скрипту на першому рядку, тому отримати дані ще складніше.

Тим не менш, ніколи не дозволяйте конфігураційним файлам у каталозі, до якого можна отримати доступ через Інтернет. У вас повинна бути папка "Веб", яка містить код контролера, css, зображення та js. Це все. Все інше зберігається в автономних папках.


але як тоді скрипт php читає облікові дані, що зберігаються у файлі?
Крістофер Махан

3
Ви використовуєте fopen (), як для звичайного текстового файлу.
e-satis

2
@ e-satis ok, це не дозволить хакеру робити require/ includeале як не допустити fopen?
dmnc

"це не заважає вам правильно встановити правила доступу"
e-satis

@ e-satis, це досить розумно. дивно, чому ніхто про це не думав. Однак , все ще вразлива до проблеми копіювання редактора. feross.org/cmsploit
Pacerier

4

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

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


3
Немає сенсу знову шифрувати пароль . Хтось, хто міг отримати незашифрований пароль, також може отримати будь-яку парольну фразу, необхідну для розшифрування пароля. Однак використання ACL та .htaccess є хорошою ідеєю.
uliwitness

2
@uliwitness Я думаю, що ви, можливо, неправильно зрозуміли - що ви маєте на увазі під "шифруванням знову "? Це просто одне шифрування. І ви не хочете використовувати парольні фрази (призначені для використання людиною) для їх шифрування, досить сильне управління ключами, наприклад, захищене ОС, таким чином, що просто доступ до файлової системи не надасть доступу до ключа.
AviD

3
Шифрування не є магічним - замість того, щоб захистити ключ AES за допомогою ACL, ви могли просто зберегти там пароль. Немає різниці між доступом до ключа AES або розшифрованого пароля, шифрування в цьому контексті - це лише зміїна олія.
MarioVilas

@MarioVilas whaat? Якщо пароль зашифрований, захищений ОС за допомогою шифрувального ключа, то чому немає різниці? Шифрування не є магічним - воно просто ущільнює всю секретність у менший ключ шифрування. Навряд чи зміїко, в цьому контексті він просто переміщує всю таємницю в ОС.
AviD

6
@AviD як же ОС може захистити ключ, але не самі дані? Відповідь: вона може захистити і те, і інше, тому шифрування насправді не допомагає. Було б інакше, якби зберігалися тільки дані, а ключ шифрування був отриманий, наприклад, із пароля, який повинен був ввести користувач.
MarioVilas
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.