Захистіть хеш-сіль для PHP-паролів


1174

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

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

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

  1. Механізм хешування повинен бути доступний у PHP
  2. Він повинен бути безпечним
  3. Він може використовувати сіль (у цьому випадку, чи всі солі однаково хороші? Чи є спосіб отримати хороші солі?)

Крім того, чи слід зберігати два бази в базі даних (одне, використовуючи MD5, а інше, наприклад, використовуючи SHA)? Зробило б це безпечніше чи небезпечніше?

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

Пов’язані запитання, які не дуже охоплюють моє запитання:

Яка різниця між SHA та MD5 у PHP
Просте шифрування пароля
Безпечні способи зберігання ключів та паролів для asp.net
Як би ви реалізували солоні паролі в Tomcat 5.5


13
openwall.com/phpass також дуже хороша бібліотека
Альфред

51
Md5 тепер абсолютно небезпечний
JqueryToAddNumbers

3
@NSAwesomeGuy Це залежить від того, для чого ви його використовуєте. Безсумнівне паролі MD5 - це нерівнозначно, але без грубої сили невідомі паролі MD5, але при гідному засолюванні все-таки надзвичайно недоцільно будувати райдужну таблицю для швидкого злому наборів паролів, а груба сила - це не надію.
Крейг Рінгер

12
PHP 5.5+ має захищений хеш паролів, вбудований у php.net/manual/en/function.password-hash.php
Теренс Джонсон

Відповіді:


982

ВІДМОВА : Ця відповідь була написана у 2008 році.

З тих пір PHP надав нам password_hashі password_verify, з моменту їх введення, вони є рекомендованим методом перемішування та перевірки паролів.

Теорія відповіді все ще добре прочитана.

TL; DR

Не треба

  • Не обмежуйте, які символи користувачі можуть вводити для паролів. Це роблять лише ідіоти.
  • Не обмежуйте довжину пароля. Якщо ваші користувачі хочуть, щоб вирок із суперкаліфрагілісткоюxpialidocious в ньому не перешкоджав їх використанню.
  • Не знімайте і не уникайте HTML та спеціальних символів у паролі.
  • Ніколи не зберігайте пароль свого користувача в простому тексті.
  • Ніколи не надсилайте електронної пошти пароль своєму користувачеві, за винятком випадків, коли він втратив їх, і ви надіслали тимчасовий.
  • Ніколи, ніколи не реєструйте паролі будь-яким чином.
  • Ніколи не хешуйте паролі з SHA1 або MD5 або навіть SHA256! Сучасні сухарики можуть перевищувати 60 і 180 мільярдів хеш / секунду (відповідно).
  • Чи не слід змішувати Bcrypt і з сирим виходом хеш () , або використовувати шістнадцятковий вихід або base64_encode його. (Це стосується будь-якого входу, у якого може бути шахрай \0, який може серйозно послабити безпеку.)

Дос

  • Використовуйте скріпт, коли можете; bcrypt, якщо ви не можете.
  • Використовуйте PBKDF2, якщо ви не можете використовувати ні bcrypt, ні scrypt, з хешами SHA2.
  • Скиньте всі паролі, коли база даних порушена.
  • Реалізуйте розумну мінімальну довжину 8-10 символів, плюс потрібно щонайменше 1 верхню літеру, 1 малу літеру, цифру та символ. Це поліпшить ентропію пароля, у свою чергу зробивши його складніше. (Див. Розділ «Що робить гарний пароль?» Для дебатів.)

Навіщо взагалі хеш-паролі?

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

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

Єремія Гроссман, генеральний директор Whitehat Security, заявив на блозі White Hat Security після недавнього відновлення пароля, що вимагало злому злому захисту його паролем:

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

(Наголос мій.)

Що робить гарний пароль все-таки?

Ентропія . (Не те, щоб я повністю підписався на точку зору Рандалла.)

Коротше кажучи, ентропія - це кількість варіацій пароля. Якщо паролем є лише малі римські літери, це лише 26 символів. Це не велика різниця. Альфа-цифрові паролі краще, з 36 символами. Але допустимий верхній і нижній регістр із символами становить приблизно 96 символів. Це набагато краще, ніж просто листи. Одна проблема полягає в тому, щоб зробити наші паролі запам'ятовуючими, ми вставляємо шаблони, що зменшує ентропію. На жаль!

Пароль ентропія наближена легко. Використання повного діапазону символів ascii (приблизно 96 символів, що набираються) дає ентропію 6,6 на символ, що на 8 символів для пароля все ще занадто низьке (52,679 біт ентропії) для подальшої безпеки. Але гарна новина полягає в тому, що довші паролі та паролі з символами unicode дійсно збільшують ентропію пароля і ускладнюють його зламати.

На сайті Crypto StackExchange триваліше обговорюється ентропія паролів . Хороший пошук в Google також дасть багато результатів.

У коментарях я спілкувався з @popnoodles, який вказував, що застосування політики паролів довжиною X з багатьма літерами, цифрами, символами тощо може насправді зменшити ентропію, зробивши схему паролів більш передбачуваною. Я згоден. Випадкова випадкова ситуація - це найбезпечніше, але найменш запам'ятоване рішення.

Наскільки я міг сказати, зробити найкращий у світі пароль - це Catch-22. Або його не запам'ятоване, занадто передбачуване, занадто коротке, занадто багато символів однокодування (важко набрати на пристрої Windows / Mobile), занадто довге тощо. Жоден пароль не є справді достатнім для наших цілей, тому ми мусимо захищати їх так, ніби вони були у Форт-Нокс.

Кращі практики

Bcrypt та scrypt - це поточні найкращі практики. Scrypt буде кращим, ніж bcrypt в часі, але він не бачив прийняття в якості стандарту Linux / Unix або веб-серверами, і ще не опублікував глибоких оглядів свого алгоритму. Але все-таки майбутнє алгоритму виглядає перспективно. Якщо ви працюєте з Ruby, є дорогоцінний камінь, який допоможе вам, і Node.js тепер має власний пакет скриптів . Ви можете використовувати Scrypt в PHP через розширення Scrypt або розширення Libsodium (обидва доступні в PECL).

Я настійно пропоную прочитати документацію для функції криптів, якщо ви хочете зрозуміти, як використовувати bcrypt, або знайти собі хорошу обгортку або використати щось на зразок PHPASS для більш застарілої реалізації. Я рекомендую мінімум 12 раундів bcrypt, якщо не 15-18.

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

Середня практика

Я вже майже не можу уявити цю ситуацію. PHPASS підтримує PHP 3.0.18 до 5.3, тому його можна використовувати майже на будь-якій можливій установці - і його слід використовувати, якщо ви точно не знаєте, що ваше середовище підтримує bcrypt.

Але припустимо, що ви взагалі не можете використовувати bcrypt або PHPASS. Що тоді?

Спробуйте впровадити PDKBF2 з максимальною кількістю раундів, які може сприйняти ваше оточення / програма / сприйняття користувача. Найнижча кількість, яку я рекомендував би, - 2500 патронів. Також переконайтеся, що він використовує hash_hmac (), якщо він доступний, щоб ускладнити відтворення операції.

Майбутні практики

Прихід у PHP 5.5 - це повна бібліотека захисту паролів, яка дозволяє усунути будь-які болі в роботі з bcrypt. Хоча більшість із нас застрягли з PHP 5.2 та 5.3 у більшості поширених середовищ, особливо спільних хостів, @ircmaxell створив рівень сумісності для API, що підтримується назад, сумісного з PHP 5.3.7.

Резюме криптографії та відмова від відповідальності

Обчислювальна потужність, необхідна для фактичного злому хешованого пароля, не існує. Єдиний спосіб комп'ютерів "зламати" пароль - це відтворити його та імітувати алгоритм хешування, який використовується для його захисту. Швидкість хешу лінійно пов'язана з його здатністю бути змушеною. Що ще гірше, більшість хеш-алгоритмів можна легко паралелізувати для виконання навіть швидше. Ось чому такі важливі дорогі схеми, як bcrypt та scrypt.

Ви не можете передбачити всі загрози або способи нападу, і тому ви повинні докласти максимум зусиль, щоб захистити своїх користувачів наперед . Якщо цього не зробите, то, можливо, навіть пропустите той факт, що на вас напали, поки не пізно ... і ви несете відповідальності . Щоб уникнути такої ситуації, почніть діяти параноїчно. Нападайте на власне програмне забезпечення (внутрішньо) та намагайтеся вкрасти облікові дані користувачів або змінити акаунти інших користувачів або отримати доступ до їх даних. Якщо ви не перевіряєте безпеку своєї системи, ви не можете звинувачувати нікого, крім себе.

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


9
секрет не допомагає, оскільки ваш пароль БД повинен бути секретним у будь-якому випадку - якщо вони зможуть отримати цей БД, вони також можуть знайти будь-який секрет, який ви використовуєте. однак важливо, щоб сіль була випадковою.
frankodwyer

2
зауважте, це не зовсім так, що "обчислювальна потужність для розшифровки" ще не існує. оскільки більшість паролів є словниковими словниками або словниками, атака на основі словника зазвичай дуже ефективна (отже, використання політики паролів та ітерації).
frankodwyer

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

4
Цікава ревізія. Чи хороший ідентифікатор користувача (скажімо, автоматичний приріст BIGINT)? Або оскільки це не випадково, це не добре? Крім того, мені доведеться зберігати нонсенс для кожного користувача в базі даних ... Чи забезпечує ключ сайту + nonce + HMAC істотну покращену безпеку над соленим (з ідентифікатором користувача) багаторазовим повторенням хеш? Аналогічно, чи корисним для безпеки є повторення HMAC кілька разів?
luiscubal

4
Надсилання тимчасового пароля через електронну пошту, що вимагає від користувача змінити його під час першого використання та надсилання «захищеного» посилання по електронній пошті, що дозволяє їм встановити свій пароль, однаково ризиковано. У будь-якому випадку кожен, хто перехоплює електронну пошту, може отримати доступ до облікового запису, доки він не використовує посилання або пароль до того, як це зробить призначений одержувач.
Тім Готьє

138

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

  • PHP 5.5 або вище: password_hash () - це хороша якість і є частиною PHP.
  • Старіші версії PHP: phpass- бібліотека OpenWall набагато краща за більшість спеціальних кодів - використовується в WordPress, Drupal тощо.

Більшість програмістів просто не мають досвіду безпечно писати криптокод, не вводячи вразливості.

Швидкий самотест: що таке розтягнення пароля і скільки ітерацій слід використовувати? Якщо ви не знаєте відповіді, вам слід скористатися password_hash(), оскільки розтягнення паролів зараз є важливою особливістю механізмів паролів через набагато більш швидкі процесори та використання графічних процесорів і FPGA для злому паролів зі швидкістю мільярдів відгадок в секунду (з графічними процесорами ).

Наприклад, ви можете зламати всі 8-символьні паролі Windows за 6 годин, використовуючи 25 графічних процесорів, встановлених на 5 настільних ПК. Це жорстоке нанесення, тобто перерахування та перевірка кожного 8-символьного пароля Windows , включаючи спеціальні символи, і не є словниковою атакою. Це було в 2012 році, станом на 2018 рік ви могли використовувати менше графічних процесорів або зламати швидше з 25 графічними процесорами.

Існує також безліч атак на райдужну таблицю на паролі Windows, які працюють на звичайних процесорах і дуже швидкі. Все це тому, що Windows все ще не солює і не розтягує свої паролі, навіть у Windows 10 - не робіть тієї самої помилки, як це робила Microsoft!

Дивись також:

  • відмінна відповідь з детальнішою інформацією про те, чому password_hash()або phpassнайкращий шлях.
  • хороша стаття в блозі з рекомендацією "факторів роботи" (кількість ітерацій) для основних алгоритмів, включаючи bcrypt, scrypt та PBKDF2.

1
але ці системи більш відомі і, можливо, вже поставлені під загрозу. але б'єш робити своє, коли ти не знаєш, чим займаєшся.
JqueryToAddNumbers

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

Враховуючи останні скиди паролів з LinkedIn, Last.fm та інших, це досить актуально. Ви в хорошій компанії, не знаючи, як написати свій механізм пароля!
RichVel

3
@PP - на мою думку, шанси алгоритму хешування для перевірки паролів, що має задній пристрій NSA, дуже низькі. Шанси того, хто не є справжнім експертом криптовалюти, напише новий механізм хешування паролів без інших уразливих ситуацій, значно нижчі. А типовий веб-сервер використовує лише хешування MD5 або SHA-1, що страшно - навіть Кріс Шифлетт інакше чудова книга Essential PHP Security рекомендує MD5 ...
RichVel

1
@RichVel - функція password_hash (). Як згадувалося раніше, він вбудований у ядро ​​PHP (aka / ext / standard).
CubicleSoft

43

Я б не зберігав хеш паролів двома різними способами, тому що тоді система принаймні така слабка, як і найслабший із використовуваних хеш-алгоритмів.


не для хешування паролів Зловмиснику потрібно лише зламати один хеш для отримання пароля. справа все-таки суперечка, оскільки ні в MD5, ні в SHA1 немає жодних практичних перерв у сценарії паролів.
frankodwyer

2
вибачте, я неправильно прочитав вашу відповідь, як рекомендую використовувати два хеші ... ви насправді правильні. Використання двох хешей послаблює систему у випадку з паролем, оскільки їм потрібно лише зламати слабший хеш.
frankodwyer

40

Як і в PHP 5.5, PHP має прості, безпечні функції для хешування та перевірки паролів, password_hash () та password_verify ()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

Коли password_hash()використовується, вона генерує випадкову сіль та включає її у виведений хеш (разом із вартістю та використовуваним алгоритмом.), А password_verify()потім зчитує цей хеш і визначає використовуваний метод солі та шифрування та перевіряє його за поданим паролем простого тексту.

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

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

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


33

Хоча на запитання відповіли, я просто хочу повторити, що солі, які використовуються для хешування, повинні бути випадковими, а не як адреса електронної пошти, як було запропоновано в першій відповіді.

Більше пояснення доступно за адресою: http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

Нещодавно у мене було обговорення, чи захищені паролем солені випадковими бітами безпечніші, ніж ті, що соляні з здогаданими або відомими солями. Подивимось: якщо система зберігання пароля порушена, а також система, яка зберігає випадкову сіль, зловмисник матиме доступ до хешу, а також солі, тож, чи є сіль випадковою чи ні, не має значення. Зловмисник може генерувати попередньо обчислені таблиці веселки, щоб зламати хеш. Ось цікава частина - генерувати попередньо обчислені таблиці не так банально. Візьмемо для прикладу модель безпеки WPA. Ваш пароль WPA насправді ніколи не надсилається до бездротової точки доступу. Натомість він хеширується з вашим SSID (мережевим іменем, як Linksys, Dlink тощо). Дуже вдале пояснення того, як це працює тут. Щоб отримати пароль з хеша, вам потрібно буде знати пароль, а також сіль (назва мережі). Church of Wifi вже попередньо обчислила хеш-таблиці, на яких розміщено 1000 найпопулярніших SSID та близько 1 мільйона паролів. Розмір усіх таблиць становить близько 40 ГБ. Як ви можете прочитати на їхньому сайті, хтось використовував 15 масивів FGPA протягом 3 днів для створення цих таблиць. Якщо припустити, що жертва використовує SSID як "a387csf3", а пароль як "123456", чи буде зламаний ці таблиці? Ні! .. не може. Навіть якщо пароль слабкий, таблиці не мають хешей для SSID a387csf3. Це краса наявності випадкової солі. Це стримує сухарики, які процвітають за попередньо обчисленими таблицями. Чи може це зупинити рішучого хакера? Напевно, ні. Але використання випадкових солей забезпечує додатковий рівень захисту. Поки ми на цю тему, обговоримо додаткову перевагу зберігання випадкових солей в окремій системі. Сценарій №1: Хеші паролів зберігаються в системі X, а значення солі, які використовуються для хешування, зберігаються в системі Y. Ці значення солі можна довідатися або відомі (наприклад, ім'я користувача) Сценарій №2: Хеши паролів зберігаються в системі X, а значення солі використовуються для хешування зберігаються в системі Y. Ці значення солі є випадковими. У випадку, якщо система X була порушена, як можна здогадатися, є величезна перевага використання випадкової солі в окремій системі (сценарій №2). Зловмиснику потрібно буде відгадати додаткові значення, щоб мати змогу зламати хеші. Якщо використовується 32-бітна сіль, для кожного здогаданого пароля можуть знадобитися 2 ^ 32 = 4,294,967,296 (близько 4,2 млрд) ітерацій. Хеші паролів зберігаються в системі X, а значення солі, що використовуються для хешування, зберігаються в системі Y. Ці значення солі можна довідатися або відомі (наприклад, ім'я користувача) Сценарій №2: Хеши паролів зберігаються в системі X, а значення солі, які використовуються для хешування, зберігаються на система Y. Ці значення солі випадкові. У випадку, якщо система X була порушена, як можна здогадатися, є величезна перевага використання випадкової солі в окремій системі (сценарій №2). Зловмиснику потрібно буде відгадати додаткові значення, щоб мати змогу зламати хеші. Якщо використовується 32-бітна сіль, для кожного здогаданого пароля можуть знадобитися 2 ^ 32 = 4,294,967,296 (близько 4,2 млрд) ітерацій. Хеші паролів зберігаються в системі X, а значення солі, що використовуються для хешування, зберігаються в системі Y. Ці значення солі можна довідатися або відомі (наприклад, ім'я користувача) Сценарій №2: Хеши паролів зберігаються в системі X, а значення солі, які використовуються для хешування, зберігаються на система Y. Ці значення солі випадкові. У випадку, якщо система X була порушена, як можна здогадатися, є величезна перевага використання випадкової солі в окремій системі (сценарій №2). Зловмиснику потрібно буде відгадати додаткові значення, щоб мати змогу зламати хеші. Якщо використовується 32-бітна сіль, для кожного здогаданого пароля можуть знадобитися 2 ^ 32 = 4,294,967,296 (близько 4,2 млрд) ітерацій. Ці значення солі випадкові. У випадку, якщо система X була порушена, як можна здогадатися, є величезна перевага використання випадкової солі в окремій системі (сценарій №2). Зловмиснику потрібно буде відгадати додаткові значення, щоб мати змогу зламати хеші. Якщо використовується 32-бітна сіль, для кожного здогаданого пароля можуть знадобитися 2 ^ 32 = 4,294,967,296 (близько 4,2 млрд) ітерацій. Ці значення солі випадкові. У випадку, якщо система X була порушена, як можна здогадатися, є величезна перевага використання випадкової солі в окремій системі (сценарій №2). Зловмиснику потрібно буде відгадати додаткові значення, щоб мати змогу зламати хеші. Якщо використовується 32-бітна сіль, для кожного здогаданого пароля можуть знадобитися 2 ^ 32 = 4,294,967,296 (близько 4,2 млрд) ітерацій.


7
Навіть якщо зловмисник отримує сіль, рядок "sitesalt: usersalt: password" все ще стійкий до попередньо обчислених таблиць, оскільки зловмиснику потрібно генерувати таблиці для кожного користувача (тому атака стає набагато повільнішою), якщо, звичайно, конкретний користувач націлюється ...
luiscubal

Щодо "Навіть якщо зловмисник отримує сіль, рядок" sitesalt: usersalt: password "все ще стійкий до попередньо обчислених таблиць", цілком згоден. Моя думка, що сайтalt, якщо зробити його випадковим і довгим, зробить систему більш безпечною, ніж вона (sitesalt) передбачуваною. Я бачив, як деякі люди рекомендують використовувати ідентифікатор електронної пошти тощо як сіль, і я заважаю цьому.
Гаурав Кумар

Ви пропустили те, що я спочатку писав. Я сказав використати випадкове запитання, збережене із записом, ПЛЮСУ електронної адреси. Додавання адреси електронної пошти створює додаткову ентропію для роботи хакера. Я з тих пір переписав свою відповідь на користь bcrypt.
Роберт К

28

Я просто хочу зазначити, що PHP 5.5 включає API хешування паролів, який забезпечує обгортку навколо crypt(). Цей API значно спрощує завдання хешування, перевірки та повторної перевірки хешей паролів. Автор також випустив пакет сумісності (у вигляді одного файлу password.php, який ви просто requireвикористовуєте), для тих, хто використовує PHP 5.3.7 та пізніших версій, і хочете використовувати це прямо зараз.

Наразі він підтримує лише BCRYPT, але має на меті його легко розширити, щоб включити інші методи хешування паролів, і оскільки техніка та вартість зберігаються як частина хешу, зміни вашої бажаної технології хешування / вартість не призведе до недійсності поточних хешей автоматично використовуватиме правильну техніку / вартість під час перевірки. Він також обробляє отримання "безпечної" солі, якщо ви чітко не визначаєте свою власну.

API відкриває чотири функції:

  • password_get_info() - повертає інформацію про даний хеш
  • password_hash() - створює хеш паролів
  • password_needs_rehash()- перевіряє, чи відповідає даний хеш заданим параметрам. Корисно перевірити, чи відповідає хеш вашій поточній схемі техніки / витрат, що дозволяє вам переробити при необхідності
  • password_verify() - перевіряє, що пароль відповідає хешу

На даний момент ці функції приймають константи паролів PASSWORD_BCRYPT і PASSWORD_DEFAULT, які на даний момент є синонімами. Різниця полягає в тому, що PASSWORD_DEFAULT "може змінюватися в нових версіях PHP, коли підтримуються нові, сильніші алгоритми хешування". Використання PASSWORD_DEFAULT та password_needs_rehash () під час входу в систему (і повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне повторне набір)

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


19

Я використовую Phpass, який є простим однофайловим класом PHP, який можна легко реалізувати майже в кожному проекті PHP. Дивіться також Н .

За замовчуванням він використовував найсильніше доступне шифрування, реалізоване в Phpass, яке є bcryptі повертається до інших шифрувань аж до MD5 для забезпечення зворотної сумісності з такими структурами, як Wordpress.

Повернутий хеш можна зберігати в базі даних таким, яким він є. Зразок використання для створення хешу:

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

Для перевірки пароля можна скористатися:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

14

РЕЧІ ЗАПАМНУЙТЕ

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

СЕРВЕР

ПОРТ

Незалежно від того, наскільки хороше ваше шифрування, якщо ви не захистите належним чином сервер, на якому працює PHP та DB, всі ваші зусилля марні. Більшість серверів функціонують відносно однаково, їм призначені порти, які дозволяють вам віддалено отримувати доступ до них через ftp або shell. Переконайтеся, що ви змінили порт за замовчуванням, який ви коли-небудь віддалене з'єднання активно. Не робивши цього, ви фактично змусили зловмисника зробити ще один менший крок у доступі до вашої системи.

USERNAME

Для всього, що є у світі, не використовуйте ім'я користувача admin, root або щось подібне. Крім того, якщо ви користуєтесь системою на базі unix, НЕ робіть доступ до коріннього облікового запису доступним, він завжди повинен бути лише sudo.

ПАРОЛЬ

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

БАНКА

СЕРВЕР

В ідеалі ви хочете, щоб ваш БД і ЗАЯВА на окремих серверах. Це не завжди можливо через витрати, але це дає певну безпеку, оскільки зловмиснику доведеться пройти два кроки для повного доступу до системи.

КОРИСТУВАЧ

Завжди у вашої програми є власний обліковий запис для доступу до БД, і надайте йому лише ті пільги, які знадобляться.

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

Як завжди НЕ роблять цей корінь чи щось подібне.

ПАРОЛЬ

Дотримуйтесь тих же вказівок, що і для всіх хороших паролів. Також не використовуйте один і той же пароль на будь-яких облікових записах SERVER або DB в тій же системі.

PHP

ПАРОЛЬ

НІКОЛИ ніколи не зберігайте пароль у вашому БД, замість цього зберігайте хеш та унікальну сіль, я поясню, чому пізніше.

ХАШЕННЯ

ОДНО ШЛЯХУЙТЕ !!!!!!!, Ніколи не хешуйте пароль таким чином, щоб його можна було змінити. Хеші повинні бути одним способом, тобто ви не перевертаєте їх і порівнюєте їх з паролем, а замість цього хеш вводили пароль таким же чином і порівняйте два хеши. Це означає, що навіть якщо зловмисник отримує доступ до БД, він не знає, що насправді є паролем, а лише його отриманий хеш. Що означає більше безпеки для ваших користувачів у найгіршому можливому сценарії.

Існує багато хороших хеш-функцій там ( password_hash, hashі т.д. ...), але вам потрібно вибрати хороший алгоритм, щоб хеш був ефективним. (bcrypt та подібні до нього пристойні алгоритми.)

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

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

СОЛІННЯ

Паролі завжди слід засолити перед хешированием. Salting додає до пароля випадкову рядок, щоб схожі паролі не були однаковими в БД. Однак якщо сіль не властива кожному користувачеві (тобто ви використовуєте тверду кодовану сіль), то ви майже зробили свою сіль марною. Тому що, як тільки зловмисник з'ясує одну сіль паролі, він має сіль для всіх.

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

КОРИСТУВАЧІ СТВОРЕННЯ ПАРОЛІВ

Якщо користувач створює пароль через інтерфейс, це означає, що він повинен бути відправлений на сервер. Це відкриває проблему безпеки, тому що це означає, що незашифрований пароль надсилається на сервер, і якщо зловмисник здатний прослуховувати та отримувати доступ, то вся ваша безпека в PHP не придатна. ЗАВЖДИ передають дані БЕЗКОШТОВНО, це робиться за допомогою SSL, але будьте втомлені, навіть SSL не є бездоганним (приклад цього - сердечний недолік OpenSSL).

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

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

Ось клас PHP, який легко створює хеш-сіль для пароля

http://git.io/mSJqpw


1
Вам слід викреслити SHA512 зі свого списку гідних алгоритмів хешу, оскільки це занадто швидко. Використовуйте його лише в поєднанні з PBKDF2. У той час як BCrypt заснований на blowfish, сам blowfish є алгоритмом шифрування, а не хешування.
martinstoeckli

1
Як ви зберігаєте випадкову сіль у БД? Я думаю, ви не хешуєте його (не може бути використаний для перевірки) і не зберігаєте в чистому вигляді (жодних реальних переваг, якщо зловмисник може прочитати БД). Отже, як це зробити?
Іазель

wmfrancia писав: "Salting додає до пароля випадкову рядок, щоб схожі паролі не були однаковими в БД". Це для мене немає сенсу. Хеші в БД вже будуть відрізнятися, оскільки це властивість хеш-функцій.
H2ONaCl

wmfancia написав щодо постійної солі: "раз нападник розбирає одну сіль паролі, він має сіль для всіх". Те саме можна сказати, що якщо хакер з'ясує, яке поле БД є сіллю, у нього є солі для всіх. Оскільки постійної солі, ймовірно, не було б у БД, це добре про постійну сіль.
H2ONaCl

Звичайно, ці коментарі не означають, що випадкова сіль на одного користувача не краща, ніж одна сіль на додаток. Це краще.
H2ONaCl

12

Google каже, що SHA256 доступний для PHP.

Ви обов'язково повинні використовувати сіль. Я рекомендую використовувати випадкові байти (і не обмежувати себе символами та цифрами). Як зазвичай, чим довше вибираєте, тим безпечніше і повільніше стає. Я думаю, 64 байти повинні бути добре.


13
64 біт має бути достатньо для когось?
Конерак

@Konerak, я б повернувся до цього через 20 років. :) Але так SHA256 дійсно доступний. Якщо ви хочете дізнатися, наскільки безпечний SHA256, ви можете перевірити це: security.stackexchange.com/questions/90064/…
Vincent Edward Gedaria Binua

8

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


2
багаторазове хешування також захищає від нападу словника та грубої сили - тобто просто змушує їх обчислювати більше часу.
frankodwyer

6
подвійне хешуваннявання не дасть тобі значної переваги, але багаторазові ітерації хешування все ще є можливою захистом від словника та брутальних атак. Промислові хеши для паролів промисловості використовують 1000+ раундів. PKCS # 5 PBKDF1 пропонує мінімум 1000 раундів.
Берк Д. Демір

8

Я знайшов ідеальну тему з цього приводу тут: https://crackstation.net/hashing-security.htm , я хотів, щоб ви отримали від цього користь, ось також вихідний код, який також забезпечував запобігання проти часової атаки.

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

Ви даєте нам рішення без жодного використання без використання
Майкл

6

Зазвичай я використовую SHA1 і сіль з ідентифікатором користувача (або якоюсь іншою специфічною для користувача інформацією), а іноді додатково використовую постійну сіль (тому у мене є 2 частини до солі).

SHA1 зараз також вважається дещо порушеним, але в значно меншій мірі, ніж MD5. Використовуючи сіль (будь-яку сіль), ви перешкоджаєте використанню загальної таблиці веселки для нападу на ваші хеши (деякі люди навіть мали успіх у використанні Google як своєрідної таблиці веселки, шукаючи хеш). Зловмисник міг би генерувати таблицю веселки за допомогою вашої солі, тому для цього слід включати сіль, орієнтовану на користувача. Таким чином, їм доведеться генерувати райдужну таблицю для кожного запису у вашій системі, а не лише одну для всієї вашої системи! З таким типом засолювання навіть MD5 гідно захищений.


2
Постійна сіль - це не чудова ідея ... напевно, це не фатальний недолік, але це зайво послаблює схему.
frankodwyer

MD5 і SHA1 швидко, тому це поганий діарея.
CodesInChaos

4

SHA1 і солі повинно вистачити (звичайно, залежно від того, чи кодуєте ви щось для Fort Knox або систему входу в ваш список покупок) на осяжне майбутнє. Якщо SHA1 недостатньо хороший для вас, використовуйте SHA256 .

Ідея солі полягає в тому, щоб викинути результати хешування з балансу, так би мовити. Відомо, наприклад, що MD5-хеш порожнього рядка є d41d8cd98f00b204e9800998ecf8427e. Отже, якщо хтось із достатньою пам'яттю побачив би цей хеш і знав, що це хеш порожньої рядки. Але якщо рядок засолена (скажімо, з рядком " MY_PERSONAL_SALT"), хеш для "порожньої рядки" (тобто " MY_PERSONAL_SALT") стає aeac2612626724592271634fb14d3ea6, отже, не очевидним для зворотного відстеження. Що я намагаюся сказати, що краще використовувати будь-яку сіль, ніж не. Тому не надто важливо знати, яку сіль вживати.

Насправді є веб-сайти, які роблять саме це - ви можете подати на нього (md5) хеш, і він виплескує відомий непростий текст, який генерує саме цей хеш. Якщо ви отримаєте доступ до бази даних, що зберігає звичайні md5-хеші, вам було б тривіально ввести хеш для адміністратора такої служби та увійти. Але, якби паролі були сольовими, така послуга стане неефективна.

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


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

1
подвійне хешування не зменшує простір результату. ітераційне хешуваннявання є загальним контролем проти словника та жорстоких атак (це уповільнює їх набагато більше, ніж уповільнює перевірку пароля).
frankodwyer

2
@frankodwyer: так, це погано. sha1(sha1($foo))ефективно зменшує вихідний простір, оскільки будь-яке зіткнення внутрішньої функції автоматично стане зіткненням зовнішньої. Деградація лінійна, але все одно викликає занепокоєння. У ітераційні методи хешування годувати дані назад в на кожному раунді, наприклад $hash = sha1(sha1($salt . $password) . $salt). Але це все ще не добре ... Дотримуйтесь PBKDF2 або Bcrypt ...
ircmaxell

-7

Ок у фіци, нам потрібна сіль, сіль повинна бути унікальною, тому нехай генерує її

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

також нам потрібен хеш, я використовую sha512, це найкраще і він знаходиться в php

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

тому тепер ми можемо використовувати ці функції для створення безпечного пароля

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

тепер нам потрібно зберегти в базі даних наше значення змінної $ hash_psw та змінну $ salt

і для авторизації ми будемо використовувати ті ж кроки ...

це найкращий спосіб зберегти паролі наших клієнтів ...

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


4
Це питання стосувалося хешів для паролів. 1 виконання sha512(навіть якщо солоне) широко вважається недостатньо хорошим для захисту паролем. (також, що RNG не є криптографічно захищеним, тому використовувати його для генерації пароля ризиковано).
luiscubal

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

добре. мій код не захищений. тож дайте мені знати, чому ви використовуєте у своїх алгоритмах ony sha256 ??? Я знаю, що sha512 - це найкраще, чому б не використовувати його ???
shalvasoft

1
@shalvasoft sha512 досить хороший для хешування загальних цілей, але для захисту паролем потрібні хеші з дуже специфічними властивостями (наприклад, "повільний" - це дуже добре , наприклад, і sha512 досить швидкий). Деякі люди використовували sha512 як будівельний блок для створення функцій хешування паролів, але сьогодні рекомендованим підходом є "використовувати bcrypt і слідкувати за скріптом".
luiscubal
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.