Управление паролями

Хранение паролей в web-приложении

Существует много примеров и материалов, в которых показано как хранить пароли в базе данных.

Часто описанные методы некачественные и подвержены взлому. В сети есть много учебных примеров, которые показывают, как сделать это неверно.

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

Очень распространенная ошибка это быстрые хэши. Например, MD5 — очень быстрый алгоритм хэширования, впрочем как и все SHA алгоритмы. Например, на NVIDIA GeForce 8800 можна генерировать 200 миллионов MD5 хэшей в секунду. Из этого следует, что использование быстрых алгоритмов хеширования, даже с примесью «соли» не эффективно. Обычным перебором можно сравнительно быстро подобрать хеш, а соответственно и пароль пользователя. По этому систему с хранением паролей в виде md5(«password») — можно считать открытой для злоумышленника.

Например, на сервере для вычисления одного хэша используя алгоритм md5, в среднем, требуется 10мксек. Пароль хранится в базе данных, как хеш от введенного значения пользователя(md5(«password»)). Злоумышленник каким то образом получил базу логинов с хешами паролей и пытается расшифровать их. Алгоритм расшифровки самый простой — перебор. Понятно что для вычисления тысячи хешей требуется 10мксек*1000 = 10мсек, для миллиона 10мксек*1000000 = 1сек и т.д. Из этого следует, что чем быстрее алгоритм хеширования, тем быстрее злоумышленник подберет больше количество паролей за меньший промежуток времени. Из вышесказанного сановится ясным, что чем медленее алгоритм вычисления хеш функции, тем надежнее.

Blowfish — криптографический алгоритм, реализующий блочное симметричное шифрование. Потребляет сравнительно большое количество вычислительных ресурсов и в настоящее время считается довольно не плохим алгоримом для шифрования паролей. В PHP реализция доступна простым вызовом crypt(). Подобор весового параметра производится таким образом, что бы атака перебором была достаточно медленная, а вычисление хеша для пользователя незаметным по времени. 200-300 мсек на продакшн сервере вполне достаточно для этого.

Для более стойкого хеша добавляют соль. Соль — слово, фраза, рандомное значение температуры, динамическое изминение чего либо, которое добавляется произвольно для формирования конечного хеша. Например, md5($password . md5($salt)). Из каждого пароля должен формироваться хеш с уникальной солью. Цель добавлнения соли — увеличения размера словаря для атаки типа перебор по словарю или для радужных таблиц. Соль, которая используется вместе с Blowfish, не объязательно должна быть криптографическо стойкой случайной строкой. Достаточно использовать соль с псевдослучайных чисел, этого достаточно для предотвращения подбора пароля по радужным таблицам.

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

Метод деления

Метод деления
весьма прост – используется остаток от деления на M:

h(K) = K mod M

Надо тщательно
выбирать эту константу. Если взять ее равной 100, а ключом будет случить год
рождения, то распределение будет очень неравномерным для ряда задач (идентификация
игроков юношеской бейсбольной лиги, например). Более того, при четной константе
значение функции будет четным при четном K и нечетным —
при нечетном, что приведет к нежелательному результату. Еще хуже обстоят дела,
если M – это степень счисления компьютера, поскольку при
этом результат будет зависеть только от нескольких цифр ключа справа. Точно
также можно показать, что M не должно быть кратно трем,
поскольку при буквенных ключах два из них, отличающиеся только перестановкой
букв, могут давать числовые значения с разностью, кратной трем (см. , стр.
552). Приведенные рассуждения приводят к мысли, что лучше использовать простое
число. В большинстве случаев подобный выбор вполне удовлетворителен.

Другой пример –
ключ, являющийся символьной строкой С++. Хеш-функция отображает эту строку в
целое число посредством суммирования первого и последнего символов и последующего
вычисления остатка от деления на 101 (размер таблицы). Эта хеш-функция приводит
к коллизии при одинаковых первом и последнем символах строки. Например, строки
«start» и «slant» будут отображаться в индекс 29. Так же ведет себя
хеш-функция, суммирующая все символы строки. Строки «bad» и «dab» преобразуются
в один и тот же индекс. Лучшие результаты дает хеш-функция, производящая
перемешивание битов в символах.

На практике, метод
деления – самый распространенный .

Метод умножения (мультипликативный)

Для мультипликативного хеширования
используется следующая формула:

h(K) =

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

Если константа С
выбрана верно, то можно добиться очень хороших результатов, однако, этот выбор
сложно сделать. Дональд Кнут (см. , стр. 553) отмечает, что умножение может
иногда выполняться быстрее деления. 

Мультипликативный
метод хорошо использует то, что реальные файлы неслучайны. Например, часто
множества ключей представляют собой арифметические прогрессии, когда в файле
содержатся ключи {K, K + d, K + 2d, …, K + td}. Например, рассмотрим имена типа {PART1, PART2, …, PARTN}.
Мультипликативный метод преобразует арифметическую прогрессию в приближенно
арифметическую прогрессию h(K), h(K + d), h(K + 2d),… различных
хеш-значений, уменьшая число коллизий по сравнению со случайной ситуацией.
Впрочем, справедливости ради надо заметить, что метод деления обладает тем же
свойством.

Частным случаем
выбора константы является значение золотого сечения φ = (√5 — 1)/2
≈ 0,6180339887. Если взять последовательность {φ}, {2φ}, {3φ},…
где оператор { } возвращает дробную часть аргумента, то на отрезке она
будет распределена очень равномерно. Другими словами, каждое новое значение
будет попадать в наибольший интервал. Это явление было впервые замечено Я.
Одерфельдом (J. Oderfeld) и доказано
С. Сверчковски (S. Świerczkowski)
(см. ). В доказательстве играют важную роль числа Фибоначчи. Применительно к
хешированию это значит, что если в качестве константы С выбрать золотое
сечение, то функция будет достаточно хорошо рассеивать ключи вида {PART1, PART2, …, PARTN}. Такое
хеширование называется хешированием Фибоначчи. Впрочем, существует ряд ключей
(когда изменение происходит не в последней позиции), когда хеширование
Фибоначчи оказывается не самым оптимальным .

2 ответа

Лучший ответ

Создайте столбец в своей пользовательской таблице и и

Регистрация пользователя

1) Получите данные или от пользователя в вашей регистрационной форме.

2) Создайте Hash and Salt для ввода пароля с помощью метода ниже.

3) Затем сохранили это и с записью пользователя в базе данных.

Логин пользователя

1) Получите ввод или от пользователя в вашей форме входа.

2) В получить пользователя по имени пользователя из базы данных.

3) Передайте сохраненные и функции ниже.

4) Затем войдите в систему, подтвердив свой пароль.

Ссылка: Эффективное хеширование паролей

12

er-sho
19 Июн 2019 в 19:34

Вы должны хранить соль, прежде чем добавлять ее к паролю и хешировать.

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

Таким образом, ваша пользовательская таблица должна иметь как минимум эти 3 столбца: имя пользователя, hashedpassword, соль

более подробное объяснение Функция хеширования является детерминированной, но не обратимой, поэтому, когда пользователь впервые создает свой пароль:

  • вы генерируете соль
  • вы соединяете пароль и соль
  • Вы хэшируете полученную строку конкатенации пароля и соли
  • вы экономите и хэш и соль

Итак, у вас есть: hashedpassword = hashingfunction (пароль + соль)

Когда вы пытаетесь войти:

  • вы получаете логин и пароль в качестве ввода
  • с помощью логина вы можете получить хэш и соль в базе
  • у вас уже есть функция хеширования
  • так что вы можете обрабатывать хеш-функцию (password_entered_by_user + salt)
  • Вы сравниваете результат с hashedpassword и регистрируете пользователя, если он совпадает

Наличие соли рядом с хешированным паролем не делает его менее безопасным: целью соли является предотвращение использования радужная таблица

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

Теперь, поскольку хеш-функция необратима, злоумышленник может лишь попытаться угадать пароль и создать словарь с помощью:

Пример:

Если хеш (guessed_password) находится в вашей базе данных, он знает, что пароль для этого (этих) пользователей — guessed_password.

Он может создать словарь с миллиардами guessed_passwords, и, поскольку многие пользователи не используют действительно надежный пароль, очень вероятно, что он сможет найти в своем словаре большое количество хешей ваших пользователей. Поэтому, если он генерирует хеши для «lola80» и «lola79», и это пароли 2 ваших пользователей, он знает, что это знает.

Теперь, если вы добавите случайную соль для каждого введенного пароля, для каждой соли он должен создать полный словарь, так как он должен сделать:

Для пользователя A с солью ’09 ç @ p $ ‘он должен создать полный словарь, где каждое слово заканчивается на ’09 ç @ p $’

Теперь, если он хочет угадать пароль пользователя B, связанный с солью ‘Yuè45gh’, он должен сгенерировать другой словарь, где каждое слово оканчивается на ‘Yuè45gh’

В основном это замедляет процесс угадывания ваших пользовательских паролей по коэффициенту your_number_of_users.

3

Maxime
3 Сен 2018 в 12:56

Пример регистрации пользователя с проверкой пароля

Python

import hashlib
import os

users = {} # Простое демо хранилище

# Add a user
username = ‘Brent’ # Имя пользователя
password = ‘mypassword’ # Пароль пользователя

salt = os.urandom(32) # Новая соль для данного пользователя
key = hashlib.pbkdf2_hmac(‘sha256’, password.encode(‘utf-8’), salt, 100000)
users = { # Хранение ключа и соли
‘salt’: salt,
‘key’: key
}

# Попытка проверки 1 (неправильный пароль)
username = ‘Brent’
password = ‘notmypassword’

salt = users # Получение соли
key = users # Получение правильного ключа
new_key = hashlib.pbkdf2_hmac(‘sha256’, password.encode(‘utf-8’), salt, 100000)

assert key != new_key # Ключи не совпадают, следовательно, пароли не совпадают

# Попытка проверки 2 (правильный пароль)
username = ‘Brent’
password = ‘mypassword’

salt = users
key = users
new_key = hashlib.pbkdf2_hmac(‘sha256’, password.encode(‘utf-8’), salt, 100000)

assert key == new_key # Ключи совпадают, следовательно, и пароли совпадают

# Добавление нового пользователя
username = ‘Jarrod’
password = ‘my$ecur3p@$$w0rd’

salt = os.urandom(32) # Новая соль для данного пользователя
key = hashlib.pbkdf2_hmac(‘sha256’, password.encode(‘utf-8’), salt, 100000)
users = {
‘salt’: salt,
‘key’: key
}

# Проверяем правильно ли введен пароль
username = ‘Jarrod’
password = ‘my$ecur3p@$$w0rd’

salt = users
key = users
new_key = hashlib.pbkdf2_hmac(‘sha256’, password.encode(‘utf-8’), salt, 100000)

assert key == new_key # Ключи совпадают, поэтому совпадают пароли и у этого пользователя

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

importhashlib

importos

users={}# Простое демо хранилище

 
# Add a user

username=’Brent’# Имя пользователя

password=’mypassword’# Пароль пользователя

salt=os.urandom(32)# Новая соль для данного пользователя

key=hashlib.pbkdf2_hmac(‘sha256’,password.encode(‘utf-8’),salt,100000)

usersusername={# Хранение ключа и соли

‘salt’salt,

‘key’key

}
 
# Попытка проверки 1 (неправильный пароль)

username=’Brent’

password=’notmypassword’

salt=usersusername’salt’# Получение соли

key=usersusername’key’# Получение правильного ключа

new_key=hashlib.pbkdf2_hmac(‘sha256’,password.encode(‘utf-8’),salt,100000)

assertkey!=new_key# Ключи не совпадают, следовательно, пароли не совпадают

 
# Попытка проверки 2 (правильный пароль)

username=’Brent’

password=’mypassword’

salt=usersusername’salt’

key=usersusername’key’

new_key=hashlib.pbkdf2_hmac(‘sha256’,password.encode(‘utf-8’),salt,100000)

assertkey==new_key# Ключи совпадают, следовательно, и пароли совпадают

 
# Добавление нового пользователя

username=’Jarrod’

password=’my$ecur3p@$$w0rd’

salt=os.urandom(32)# Новая соль для данного пользователя

key=hashlib.pbkdf2_hmac(‘sha256’,password.encode(‘utf-8’),salt,100000)

usersusername={

‘salt’salt,

‘key’key

}
 
# Проверяем правильно ли введен пароль

username=’Jarrod’

password=’my$ecur3p@$$w0rd’

salt=usersusername’salt’

key=usersusername’key’

new_key=hashlib.pbkdf2_hmac(‘sha256’,password.encode(‘utf-8’),salt,100000)

assertkey==new_key# Ключи совпадают, поэтому совпадают пароли и у этого пользователя

Хранение хеша и соли

Из указанных выше фрагментов нужно сохранить соль и ключ. Для хранения можно использовать методы JSON, SQL, CSV и даже простой текстовый файл. Убедитесь, что пароль нигде не сохранен, ведь в этом состоит главная цель — избежать необходимость сохранения действующего пароля в исходном виде.

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

Python

import os
import hashlib

# Пример генерации
salt = os.urandom(32)
key = hashlib.pbkdf2_hmac(‘sha256’, ‘mypassword’.encode(‘utf-8’), salt, 100000)

# Хранение как
storage = salt + key

# Получение значений обратно
salt_from_storage = storage # 32 является длиной соли
key_from_storage = storage

1
2
3
4
5
6
7
8
9
10
11
12
13

importos

importhashlib

 
# Пример генерации

salt=os.urandom(32)

key=hashlib.pbkdf2_hmac(‘sha256′,’mypassword’.encode(‘utf-8’),salt,100000)

 
# Хранение как

storage=salt+key

 
# Получение значений обратно

salt_from_storage=storage32# 32 является длиной соли

key_from_storage=storage32

Если можно использовать два места (в большинстве случаев так и есть), используйте. Это значительно облегчает процесс.

Словарные атаки и брутфорс

Вот самый простой способ взломать хеш. Берем комбинацию, которая может оказаться паролем, хешируем ее и сравниваем с хешем, который хотим расшифровать. И так до тех пор, пока не будет найдено совпадение.

Существует несколько вариантов реализовать описанный подход. Самые часто используемые: словарная атака (Dictionary Attack) и брутфорс (“метод грубой силы”, Brute Force).

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

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

Плохая новость: предотвратить эти атаки никак не получится.

Хорошая новость: эффективность этих атак можно свести к минимуму, если организовать правильное управление паролями.

Хеширование паролей с pbkdf2_hmac

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

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

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

является реализацией функции получения ключа PBKDF2, использующей HMAC в качестве псевдослучайной функции. можно найти в библиотеке hashlib (которая поставляется с Python) и находится в Python 3.4 и выше. принимает пять параметров:

  • : алгоритм хеш дайджеста для HMAC;
  • : пароль, превращенный в ключ;
  • : случайно сгенерированная соль;
  • : итерации в вычислении (чем больше, тем длиннее вычисления);
  • : длина ключа вывода (не обязательно).

Встроенные в PHP криптографические функции хеширования

В PHP5.5 и новее

В PHP5.5 сделали стандартный набор функций для работы с паролями, среди которых есть:

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

До PHP5.5

Функции хеширования:

Чтобы сгенерировать соль, необходим надежный (непредсказуемый) криптографический генератор случайных чисел. В качестве него можно использовать:

  • на linux/mac можно читать случайные данные из

Библиотека https://github.com/paragonie/random_compat умеет выбирать подходящую функцию из имеющихся в наличии

Обратите внимание, что функции rand() и mt_rand() не являются криптографически надеждными, так как они используют относительно простой алгоритм и, имея несколько сгенерированных чисел, можно предсказать следующие

Хэширование Паролей С Помощью Spring Security

Хотя Java изначально поддерживает алгоритмы хэширования PBKDF2 и SHA, она не поддерживает алгоритмы BCrypt и SCrypt.

К счастью для нас, Spring Security поставляется с поддержкой всех этих рекомендуемых алгоритмов через интерфейс PasswordEncoder :

  • MessageDigestPasswordEncoder дает нам MD5 и SHA-512
  • Pbkdf2PasswordEncoder дает нам PBKDF2
  • BCryptPasswordEncoder дает нам BCrypt, и
  • Шифратор паролей SCrypt дает нам скрипт

Кодеры паролей для PBKDF2, BCrypt и SCrypt поставляются с поддержкой настройки желаемой силы хэша пароля.

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

Обратимое шифрование на PHP 5 библиотекой MCrypt

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

На подавляющем большинстве хостингов данная библиотека сразу же идет вместе с php. Но если вы администрируете свой сервер и данной библиотеки почему-то вдруг не оказалось в составе php, вы всегда можете ее доустановить командой apt-get install php5-mcrypt для Debian-подобных систем (в т.ч. Mint, Ubuntu) или yum install php-mcrypt для RedHat-подобных систем (в т.ч. Fedora, openSUSE, CentOS) или любым другим способом, который вам нравится (через dpkg, rpm, yast и т.д.).

Затем в папке /etc находите папку php, содержащую ini-файлы расширений, загружаемых php по-умолчанию. Посмотреть путь до этой папки можно в php.ini в разделе «Dynamic Extensions». Это может быть папка /etc/php или /etc/php5/mods-available/ или как у меня на сервере /etc/php.d (вообщем, зависит от настроек php). В этой папке должен присутствовать файл mcrypt.ini. Если его там нет, тогда создайте его с таким содержимым:

; Enable mcrypt extension module
extension=mcrypt.so

После этого можно включить расширение командой php5enmod mcrypt, а затем перезапустить сервер /etc/init.d/apache2 restart для Debian-систем или service httpd restart для RedHat систем. Разумеется, все описанные действия выполняются с правами root-а.

Итак, теперь приведу примеры 2-х способов шифрования по ключу, которые я нашел для себя в интернете.

Льготы

Чтобы понять разницу между взломом одного пароля и их набора, рассмотрим один файл паролей, содержащий сотни имен пользователей и хешированных паролей. Без соли злоумышленник может вычислить хэш (попытка ), а затем проверить, появляется ли этот хеш где-нибудь в файле. Вероятность совпадения, то есть взлома одного из паролей с помощью этой попытки, увеличивается с увеличением количества паролей в файле. Если присутствуют соли, злоумышленник должен будет вычислить хэш (соль , попытка ), сравнить с записью A, затем хэш (соль , попытка ), сравнить с записью B и скоро. Это предотвращает «повторное использование» хэшей при попытках взлома нескольких паролей.

Соли также борются с использованием хеш-таблиц и радужные столы для взлома паролей. Хеш-таблица — это большой список предварительно вычисленных хешей для часто используемых паролей. Для файла паролей без солей злоумышленник может просмотреть каждую запись и найти хешированный пароль в хеш-таблице или радужной таблице. Если поиск выполняется значительно быстрее, чем хэш-функция (что часто бывает), это значительно ускорит взлом файла. Однако, если файл паролей соленый, то хеш-таблица или радужная таблица должна содержать предварительно хешированный «соль. Пароль». Если соль достаточно длинная и достаточно случайная, это маловероятно. Пароли без соли, выбранные людьми, как правило, уязвимы для словарных атак, поскольку они должны быть как короткими, так и достаточно значимыми, чтобы их можно было запомнить. Даже небольшой словарь (или его хешированный эквивалент, хеш-таблица) значительно помогает взломать наиболее часто используемые пароли. Поскольку люди не должны запоминать соли, они могут сделать размер радужной таблицы, необходимой для успешной атаки, чрезмерно большим, не обременяя пользователей.

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

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

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

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

2-й способ. Очень надежное обратимое шифрование по шестандцатиричному ключу.

Внимание! Ключ должен быть шестандцатиричным (символы 0123456789ABCDEF) длиной 32 или 64 символа

define('ENCRYPTION_KEY', 'e3f080b6edfcf6fff70654021c7c2e43');

$txt = 'Тестируем обратимое шифрование на php';
$encrypted = mc_encrypt($txt, ENCRYPTION_KEY);
echo $encrypted.'<br>';
$decrypted = mc_decrypt($encrypted, ENCRYPTION_KEY);
echo $decrypted;

// Encrypt Function
function mc_encrypt($encrypt, $key) {
  $encrypt = serialize($encrypt);
  $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), MCRYPT_DEV_URANDOM);
  $key = pack('H*', $key);
  $mac = hash_hmac('sha256', $encrypt, substr(bin2hex($key), -32));
  $passcrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $encrypt.$mac, MCRYPT_MODE_CBC, $iv);
  $encoded = base64_encode($passcrypt).'|'.base64_encode($iv);
  return $encoded;
}

// Decrypt Function
function mc_decrypt($decrypt, $key) {
  $decrypt = explode('|', $decrypt.'|');
  $decoded = base64_decode($decrypt);
  $iv = base64_decode($decrypt);
  if(strlen($iv)!==mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC)){ return false; }
  $key = pack('H*', $key);
  $decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $decoded, MCRYPT_MODE_CBC, $iv));
  $mac = substr($decrypted, -64);
  $decrypted = substr($decrypted, 0, -64);
  $calcmac = hash_hmac('sha256', $decrypted, substr(bin2hex($key), -32));
  if($calcmac!==$mac){ return false; }
  $decrypted = unserialize($decrypted);
  return $decrypted;
}

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

Расширяемое хеширование (extendible hashing)

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

Вместо бинарного
дерева расширяемое хеширование предусматривает список, элементы которого
ссылаются на блоки. Сами же элементы адресуются по некоторому количеству i
 битов псевдоключа (см. рис). При поиске берется  i
битов псевдоключа и через список (directory)
находится адрес искомого блока. Добавление элементов производится сложнее.
Сначала выполняется процедура, аналогичная поиску. Если блок неполон,
добавляется запись в него и в базу данных. Если блок заполнен, он разбивается
на два, записи перераспределяются по описанному выше алгоритму. В этом случае
возможно увеличение числа бит, необходимых для адресации. В этом случае размер
списка удваивается и каждому вновь созданному элементу присваивается указатель,
который содержит его родитель. Таким образом, возможна ситуация, когда
несколько элементов показывают на один и тот же блок. Следует заметить, что за
одну операцию вставки пересчитываются значения не более, чем одного блока.
Удаление производится по такому же алгоритму, только наоборот. Блоки,
соответственно, могут быть склеены, а список – уменьшен  в два раза.

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

Создание соли для Blowfish алгоритма

/**
 * Generate a random salt in the crypt(3) standard Blowfish format.
 *
 * @param int $cost Cost parameter from 4 to 31.
 *
 * @throws Exception on invalid cost parameter.
 * @return string A Blowfish hash salt for use in PHP's crypt()
 */
function blowfishSalt($cost = 13)
{
    if (!is_numeric($cost) || $cost < 4 || $cost > 31) {
        throw new Exception("cost parameter must be between 4 and 31");
    }
    $rand = array();
    for ($i = 0; $i < 8; $i += 1) {
        $rand[] = pack('S', mt_rand(0, 0xffff));
    }
    $rand[] = substr(microtime(), 2, 6);
    $rand = sha1(implode('', $rand), true);
    $salt = '$2a$' . sprintf('%02d', $cost) . '$';
    $salt .= strtr(substr(base64_encode($rand), 0, 22), array('+' => '.'));
    return $salt;
}
Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: