Шифрование / хеширование паролей в виде обычного текста в базе данных

Я унаследовал веб-приложение, которое, как я только что обнаружил, хранит более 300 000 имен пользователей / паролей в виде обычного текста в базе данных SQL Server. Я понимаю, что это очень плохая вещь ™.

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

Любая помощь приветствуется.

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

Я должен просто:

  1. Сделайте резервную копию БД
  2. Обновить логин / обновить код пароля
  3. В нерабочее время просмотрите все записи в таблице пользователей, хешируя пароль и заменяя каждую из них.
  4. Протестируйте, чтобы убедиться, что пользователи по-прежнему могут входить в систему / обновлять пароли

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


person Jonathan S.    schedule 13.11.2008    source источник
comment
Очень плохая вещь (тм) :)   -  person xan    schedule 13.11.2008
comment
Не думаю, что вы правильно ответили на свой вопрос. Вы хотите знать, как получить данные из реляционной базы данных? Это было бы отборное заявление.   -  person Glenn    schedule 13.11.2008
comment
Я знаю, как получать записи, это скорее процедурный вопрос ... Извините, если это было неясно.   -  person Jonathan S.    schedule 13.11.2008
comment
У вас есть база данных пользователей Reddit? ;-)   -  person John Topley    schedule 13.11.2008
comment
Возможный дубликат безопасного хеширования пароля   -  person Gilles 'SO- stop being evil'    schedule 31.12.2015
comment
@Gilles - Я не уверен, что этот вопрос семилетней давности с более чем 34000 просмотров является копией вопроса шестилетней давности с менее 5000 просмотров, но, видимо, вы так думаете. Я согласен с тем, что я бы не стал задавать этот новый вопрос по SO сегодня, но он был задан до того, как появились все другие сайты Stack Exchange, связанные с программированием. Сам вопрос больше касается процесса перехода от обычного текста к более безопасным паролям, а не конкретной реализации методов шифрования / хеширования.   -  person Jonathan S.    schedule 01.01.2016
comment
@JonathanS. То, что мы позволяем дубликатам оставаться на несколько лет, не означает, что мы должны держать их открытыми, когда мы их найдем. И я не понимаю, какое значение имеет существование других сайтов SE.   -  person Gilles 'SO- stop being evil'    schedule 01.01.2016
comment
Кроме того, поскольку вы все еще здесь, я предлагаю заменить принятый ответ на хороший, а не на тот, который утверждает, что пароли «зашифрованы» или что MD5 - достойный выбор для хэша пароля. stackoverflow.com/a/287883 и stackoverflow. com / a / 287738 - лучшие ответы, поскольку они допускают, что хэш пароля должен быть соленым и медленным.   -  person Gilles 'SO- stop being evil'    schedule 01.01.2016
comment
@Gilles - Я упомянул другие сайты SE, чтобы повторить, что это был скорее вопрос о процессе / процедуре, который я, вероятно, задал бы на сайте programmers.stackexchange.com, если бы он существовал, когда я первоначально спросил. Я до сих пор не верю, что это дубликат, поскольку я не спрашивал, какой алгоритм хеширования следует использовать. Текущий принятый ответ был лучшим ответом на тот момент, когда фактически обсуждался процесс перехода от простых текстовых паролей к более безопасной реализации.   -  person Jonathan S.    schedule 01.01.2016


Ответы (16)


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

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

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

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

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

При обработке пароля пользователя учитывайте, где происходит хеширование. В моем случае хэш был рассчитан PHP-кодом, запущенным на веб-сервере, но пароль был передан на страницу с пользовательской машины в виде открытого текста! Это было нормально в среде, в которой я работал, так как в любом случае это было внутри системы https (сеть uni). Но в реальном мире я предполагаю, что вы захотите хешировать пароль до того, как он покинет пользовательскую систему, используя javascript и т. Д., А затем передать хеш на свой сайт.

person xan    schedule 13.11.2008
comment
Спасибо, хотя я не люблю хранить пароли, они существуют уже много лет ... Система отправляет несколько писем, содержащих пароли, поэтому мне придется их просмотреть, прежде чем принимать решение об использовании хеша. - person Jonathan S.; 13.11.2008
comment
Что произойдет, если у них отключен javascript? - person Malfist; 13.11.2008
comment
Вы не можете хешировать пароль на машине пользователя. Хеширование должно выполняться доверенной системой. (В противном случае любой, кто украл копию таблицы паролей, может просто послать вам хеш; хеш стал паролем.) Но, да, для этого требуется безопасный транспорт, такой как HTTPS, от пользователя. - person erickson; 13.11.2008
comment
@Malfist: Это быстро превращается в историческую проблему. Очень и очень немногие отключают js. Однако в этом случае я бы отправил нехешированный проход на сервер и уложил его в код на стороне сервера. Это был бы просто менее идеальный запасной вариант. - person Lucas Oman; 13.11.2008
comment
@erickson: для тех, кто особенно параноик, вы можете сохранить проход с двойным хешированием в БД и принять проход с одним хешем от клиента. - person Lucas Oman; 13.11.2008
comment
Либо хэш, либо нет. Хеширование на клиенте бессмысленно. Модель угрозы, на которую вы обращаетесь с помощью хэша, - это раскрытие базы данных паролей. Если это не проблема, не хешируйте вообще. В противном случае вы не сможете пройти аутентификацию, используя хэш, созданный пользователем (или считанный из украденной копии базы данных). - person erickson; 13.11.2008
comment
Это может быть сверхпараноидально, я просто упомянул то, к чему в то время не обратился должным образом. Как я уже сказал, у меня нет реального активного опыта в этой области, но это заслуживает внимания. - person xan; 14.11.2008

ИЗМЕНИТЬ (2016 г.): используйте Argon2, scrypt, bcrypt или PBKDF2 в указанном порядке предпочтения. Используйте настолько большой коэффициент замедления, насколько это возможно в вашей ситуации. Используйте проверенную существующую реализацию. Убедитесь, что вы используете подходящую соль (хотя библиотеки, которые вы используете, должны позаботиться об этом за вас).


При хешировании паролей используйте НЕ ИСПОЛЬЗУЙТЕ ОБЫЧНЫЙ MD5.

Используйте PBKDF2, что в основном означает использование случайной соли для предотвращения радужная таблица атак и повторения (повторного хеширования) достаточного количества раз, чтобы замедлить хеширование - не настолько, чтобы ваш приложение занимает слишком много времени, но достаточно, чтобы злоумышленник, взявший большое количество разных паролей, заметит

Из документа:

  • Выполните итерации не менее 1000 раз, желательно больше - рассчитайте свою реализацию, чтобы увидеть, сколько итераций возможно для вас.
  • 8 байтов (64 бита) соли достаточно, и случайное значение не обязательно должно быть безопасным (соль не зашифрована, мы не боимся, что кто-то ее угадает).
  • Хороший способ применить соль при хешировании - использовать HMAC с вашим любимым алгоритмом хеширования, используя пароль в качестве ключа HMAC и соль в качестве текста для хеширования (см. этот раздел документа).

Пример реализации на Python с использованием SHA-256 в качестве безопасного хеша:

РЕДАКТИРОВАТЬ: как упоминал Эли Коллинз, это не реализация PBKDF2. Вам следует предпочесть реализации, соответствующие стандарту, например PassLib.

from hashlib import sha256
from hmac import HMAC
import random

def random_bytes(num_bytes):
  return "".join(chr(random.randrange(256)) for i in xrange(num_bytes))

def pbkdf_sha256(password, salt, iterations):
  result = password
  for i in xrange(iterations):
    result = HMAC(result, salt, sha256).digest() # use HMAC to apply the salt
  return result

NUM_ITERATIONS = 5000
def hash_password(plain_password):
  salt = random_bytes(8) # 64 bits

  hashed_password = pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)

  # return the salt and hashed password, encoded in base64 and split with ","
  return salt.encode("base64").strip() + "," + hashed_password.encode("base64").strip()

def check_password(saved_password_entry, plain_password):
  salt, hashed_password = saved_password_entry.split(",")
  salt = salt.decode("base64")
  hashed_password = hashed_password.decode("base64")

  return hashed_password == pbkdf_sha256(plain_password, salt, NUM_ITERATIONS)

password_entry = hash_password("mysecret")
print password_entry # will print, for example: 8Y1ZO8Y1pi4=,r7Acg5iRiZ/x4QwFLhPMjASESxesoIcdJRSDkqWYfaA=
check_password(password_entry, "mysecret") # returns True
person orip    schedule 13.11.2008
comment
Я всегда понимал, что хеширование хеша - это не то, что вам следует делать, поскольку вероятность столкновения хешей увеличивается с каждой итерацией. Но может ли этот хеш (соль + хеш) обойти это? В конце концов, персонажей не так уж и много ... - person Henrik Paul; 14.11.2008
comment
Вы правы, повторное хеширование может уменьшить пространство поиска (соль не помогает), но это не имеет отношения к криптографии на основе паролей. Чтобы достичь 256-битного пространства поиска этого хэша, вам понадобится полностью случайный пароль длиной 40 символов из всех доступных символов клавиатуры (log2 (94 ^ 40)). - person orip; 15.11.2008
comment
Люди должны знать, что этот код НЕ реализует алгоритм PBKDF2; скорее это нестандартная вариация старой функции PBKDF1, модифицированная для использования PRF (в данном случае HMAC-SHA256). См. rfc2898 для эталонной реализации обоих файлов kdf. Хотя этот алгоритм, вероятно, небезопасен, он несовместим по байтам ни с PBKDF1, ни с PBKDF2, и его точное поведение не подвергалось такой же проверке безопасности - меня беспокоит тот факт, что он применяет HMAC к фиксированной соли и изменяет пароль вместо этого - это может ослабить HMAC. - person Eli Collins; 04.06.2011
comment
@Eli: Не совсем не согласен, поскольку PBKDF2 создает ключи произвольной длины, а этот код - нет. Конечно, это не имеет значения в схеме защиты паролем. Но ‹a href=tools.ietf.org/html/rfc2898# Приложение-B.1.1 ›текст в RFC, на который вы связались ‹/a›, явно упоминает использование пароля в качестве ключа HMAC и соли в качестве текста HMAC, что - намеренно - то, что делает этот пример кода. - person orip; 04.06.2011
comment
@orip: Криптография - это не то, где достаточно близко обычно является хорошей идеей; особенно, если люди ошибочно принимают это за реализацию PBKDF2, только чтобы позже узнать, что вывод не соответствует существующему коду / данным. Верно, если бы ошибка соли / пароля была исправлена, это больше соответствовало бы приложению, но это только описывает, как использовать HMAC в PBKDF2; не так, как работает PBKDf2. Помимо исключения части переменной-keylen, наиболее важной проблемой является то, что в приведенном выше коде полностью отсутствует часть XOR функции F () в PBKDF2, что является центральным элементом его устойчивости к прообразу. - person Eli Collins; 05.06.2011
comment
Просто добавлю - для большинства обсуждений алгоритмов отдельные реализации могут отличаться, если они достигают желаемого эффекта. Но PBKDf2 - это тщательно разработанный алгоритм с тестовыми векторами, определяющими точное поведение; и это в проблемном пространстве, где небольшие изменения могут означать серьезное снижение безопасности. В большинстве других случаев я бы не подумал, что об этом стоит даже упоминать :) - person Eli Collins; 05.06.2011

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

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

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

Атаки с предварительным вычислением предотвращаются с помощью «криптографической соли». Это некоторые данные, которые хешируются с паролем. Это не обязательно должно быть секретом, просто оно должно быть непредсказуемым для данного пароля. Для каждого значения соли злоумышленнику потребуется новый словарь. Если вы используете один байт соли, злоумышленнику потребуется 256 копий словаря, каждая из которых сгенерирована с другой солью. Сначала он использовал соль для поиска правильного словаря, а затем использовал хеш-вывод для поиска подходящего пароля. Но что, если добавить 4 байта? Теперь ему нужно 4 миллиарда экземпляров словаря. Использование достаточно большой соли исключает словарную атаку. На практике от 8 до 16 байтов данных от генератора случайных чисел криптографического качества являются хорошей солью.

Если предварительное вычисление исключено из таблицы, злоумышленник вычисляет хэш при каждой попытке. Сколько времени потребуется на поиск пароля, теперь полностью зависит от того, сколько времени потребуется на хеширование кандидата. Это время увеличивается за счет итерации хеш-функции. Число итераций обычно является параметром функции вывода ключа; сегодня многие мобильные устройства используют от 10 000 до 20 000 итераций, в то время как сервер может использовать 100 000 и более. (В алгоритме bcrypt используется термин «фактор стоимости», который является логарифмической мерой необходимого времени.)

person erickson    schedule 13.11.2008
comment
Насколько предполагается, что генерация хэша будет медленной - это зависит от его использования. Для хранения паролей это желаемое качество. Для аутентификации сообщений это может быть не так (особенно, если аутентифицируемые сообщения являются сетевыми пакетами). - person Michael Burr; 14.11.2008
comment
Хорошая точка зрения; медлительность важна для защиты от офлайн-атак. В сетевом протоколе человек-посередине, вероятно, не успеет обнаружить коллизию даже с очень быстрым хешем, если он не сломан. - person erickson; 14.11.2008
comment
Хорошо сформулированное объяснение шифрования паролей и терминов, спасибо. - person JYelton; 15.04.2010

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

Что касается шифрования ваших паролей:

  • использовать соль
  • использовать алгоритм хеширования, предназначенный для паролей (т. е. - он медленный)

См. Статью Томаса Птачека «Достаточно с радужными таблицами: что нужно знать о схемах безопасных паролей» для некоторых Детали.

person Michael Burr    schedule 13.11.2008

Думаю, вам следует сделать следующее:

  1. Создайте новый столбец HASHED_PASSWORD или что-то подобное.
  2. Измените свой код, чтобы он проверял оба столбца.
  3. Постепенно переносите пароли из нехешированной таблицы в хешированную. Например, когда пользователь входит в систему, автоматически перенесите его пароль в хешированный столбец и удалите нехешированную версию. Все вновь зарегистрированные пользователи будут иметь хешированные пароли.
  4. Через несколько часов вы можете запустить скрипт, который переносит n пользователей за раз.
  5. Когда у вас больше не останется нехешированных паролей, вы можете удалить столбец старого пароля (возможно, вы не сможете этого сделать, это зависит от используемой базы данных). Также вы можете удалить код для обработки старых паролей.
  6. Готово!
person Tamas Czinege    schedule 13.11.2008

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

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

Мы назвали это Fairly Secure Hashed Passwords или сокращенно FSHP. Реализовал его на Python, Ruby, PHP5 и передал в общественное достояние. Доступно для употребления, разветвления, флейма или плевания на GitHub по адресу http://github.com/bdd/fshp

FSHP - это реализация хеширования паролей с итеративным хешированием.

Принцип конструкции аналогичен спецификации PBKDF1 в RFC 2898 (также известной как PKCS # 5: Спецификация криптографии на основе пароля, версия 2.0.) FSHP позволяет выбирать длину соли, количество итераций и базовую криптографическую хеш-функцию из SHA-1 и SHA-2 (256, 384, 512). Самоопределяющийся мета-префикс в начале каждого вывода делает его переносимым, позволяя потребителю выбирать свой собственный базовый уровень безопасности хранилища паролей.

БЕЗОПАСНОСТЬ:

По умолчанию FSHP1 использует 8-байтовые соли с 4096 итерациями хеширования SHA-256. - 8-байтовая соль делает атаки радужной таблицы непрактичными, умножая требуемое пространство на 2 ^ 64. - 4096 итераций делают атаки методом грубой силы довольно дорогими. - На момент выпуска этой версии не было известных атак на SHA-256 для обнаружения коллизий с вычислительными затратами менее 2 ^ 128 операций.

ВНЕДРЕНИЯ:

  • Python: протестировано с 2.3.5 (с hashlib), 2.5.1, 2.6.1
  • Ruby: протестировано с 1.8.6
  • PHP5: протестировано с 5.2.6

Приглашаем всех желающих создать недостающие языковые реализации или усовершенствовать существующие.

ОСНОВНЫЕ ОПЕРАЦИИ (с Python):

>>> fsh = fshp.crypt('OrpheanBeholderScryDoubt')
>>> print fsh
{FSHP1|8|4096}GVSUFDAjdh0vBosn1GUhzGLHP7BmkbCZVH/3TQqGIjADXpc+6NCg3g==
>>> fshp.validate('OrpheanBeholderScryDoubt', fsh)
True

НАСТРОЙКА КРИПТА:

Давайте ослабим нашу схему хеширования паролей. - Уменьшите длину соли с 8 по умолчанию до 2. - Уменьшите количество итераций по умолчанию 4096 до 10. - Выберите FSHP0 с SHA-1 в качестве базового алгоритма хеширования.

>>> fsh = fshp.crypt('ExecuteOrder66', saltlen=2, rounds=10, variant=0)
>>> print fsh
{FSHP0|2|10}Nge7yRT/vueEGVFPIxcDjiaHQGFQaQ==
person Berk D. Demir    schedule 02.01.2009
comment
Это круто! Хотя было бы неплохо не указывать вариант как магическое число. - person orip; 12.01.2009
comment
на самом деле это больше, чем карта алгоритмов. на момент выпуска этого выпуска все варианты являются реализациями PBKDF1 и отличаются только алгоритмом хеширования (0: SHA1, 1: SHA256, 2: SHA384, 3: SHA512), но для прямой совместимости я выбрал его как целое число. так что это не волшебное число, но на вкус оно похоже. ты прав. - person Berk D. Demir; 17.01.2009
comment
Я хочу сохранить FSHP как жизнеспособный вариант и обновлять его по мере того, как время требует безопасности. Возможно, варианты 4, 5 и 6 будут PBKDF2 с алгоритмами SHA256 384 512. Конечно, это пример. :) - person Berk D. Demir; 17.01.2009

Как упоминали другие, вы не хотите расшифровывать, если можете. Стандартная передовая практика - это шифрование с использованием одностороннего хеша, а затем, когда пользователь входит в систему, хеш-пароль для сравнения.

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

person Cory Foy    schedule 13.11.2008

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

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

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

person Mihai Limbășan    schedule 13.11.2008
comment
Соль не нужно хранить в секрете, и хранить ее в секрете обременительно. - person erickson; 13.11.2008
comment
Кроме того, для ясности - соль должна быть разной и случайной для каждого экземпляра. Не выбирается заранее и не используется для всех хешей. - person Michael Burr; 13.11.2008
comment
Майк, конечно, в принципе прав, однако не всегда возможно менять соль каждый раз (в зависимости от специфики приложения), и в этом случае соль нужно держать в секрете. - person Mihai Limbășan; 14.11.2008

  • Зашифруйте, используя что-то вроде MD5, закодируйте его как шестнадцатеричную строку
  • Вам нужна соль; в вашем случае имя пользователя может использоваться в качестве соли (оно должно быть уникальным, имя пользователя должно быть самым уникальным доступным значением ;-)
  • используйте поле старого пароля для хранения MD5, но пометьте MD5 (например, «MD5: 687A878 ....»), чтобы старый (простой текст) и новый (MD5) пароли могли сосуществовать
  • измените процедуру входа в систему, чтобы проверить MD5, если есть MD5, и простой пароль в противном случае
  • измените функции «сменить пароль» и «новый пользователь» для создания только паролей MD5
  • теперь вы можете запустить пакетное задание преобразования, которое может занять столько времени, сколько необходимо.
  • после того, как преобразование было выполнено, удалите устаревшую поддержку
person mfx    schedule 13.11.2008
comment
Также принято использовать случайную соль для каждого пользователя и хранить ее вместе с хешированным паролем. - person Michael Haren; 13.11.2008
comment
Что-то, что неизвестно пользователю, сделало бы более безопасную соль. Возможно, внутренний идентификатор пользователя или, как предложил Майкл, специально созданное солевое значение. Если вы используете общедоступную уникальную соль, такую ​​как имя пользователя, вам, вероятно, также следует использовать постоянную соль просто для хорошей меры. - person rmeador; 13.11.2008
comment
Насколько я понимаю, цель соления - предотвратить словарные атаки (предварительное вычисление хэшей популярных паролей и сравнение с ними пользователей). Соль всегда видна, это не секрет. Так почему бы не использовать имя пользователя, ведь оно уже известно и будет уникальным? - person mfx; 13.11.2008
comment
Имя пользователя - неплохая соль, если рассматривать единую систему. Но, вероятно, для злоумышленника, такого как репрессивное правительство, было бы полезно создать словари для наиболее распространенных имен пользователей, чтобы повысить их шансы взлома нескольких сайтов. Лучше выбирать и хранить случайную соль. - person erickson; 13.11.2008

Шаг 1. Добавьте зашифрованное поле в базу данных

Шаг 2: Измените код так, чтобы при изменении пароля обновлялись оба поля, но при входе в систему по-прежнему использовалось старое поле.

Шаг 3: Запустите сценарий, чтобы заполнить все новые поля.

Шаг 4. Измените код, чтобы при входе в систему использовалось новое поле, а при изменении паролей не обновлялось старое поле.

Шаг 5: Удалите незашифрованные пароли из базы данных.

Это должно позволить вам выполнить переключение без прерывания работы конечного пользователя.

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

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

person Kevin    schedule 14.11.2008
comment
Хорошее замечание о том, что Шаг 2 необходим на ранней стадии процесса. Я тоже разделяю ваше удовольствие от поля фиктивного пароля :) - person Kristen; 19.02.2009

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

Вы можете использовать симметричное шифрование, которое имеет свои недостатки с точки зрения безопасности. (Если ваш сервер скомпрометирован, симметричный ключ шифрования также может быть скомпрометирован).

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

person davidcl    schedule 13.11.2008
comment
Неспособность персонала найти пароль пользователя - это особенность, а не недостаток. Поддержка восстановления пароля - это не компромисс, а сдача. - person erickson; 13.11.2008
comment
Я думаю, что это, к сожалению, абсолютистская позиция. Это действительно зависит от значения безопасности информации, защищенной этим паролем. - person davidcl; 13.11.2008
comment
Это также зависит от размера и надежности рассматриваемого персонала. Поиск пароля имеет гораздо больше смысла в небольшой организации, чем в большой. - person davidcl; 13.11.2008
comment
Вы никогда не знаете, что защищает данный пароль; ожидайте, что пользователи будут повторно использовать пароли для своего банка в вашем игрушечном веб-приложении. Даже если ваш персонал заслуживает доверия (даже если это только ВЫ), вы не можете исключить возможность доступа внешнего злоумышленника к вашей базе паролей. - person erickson; 14.11.2008
comment
Если у персонала есть законная потребность в доступе к учетной записи другого пользователя, эта возможность должна быть встроена в систему, и персоналу не нужно будет входить в систему как пользователь. И предполагаемая потребность в системе «восстановления пароля» может быть заменена системой «сброса пароля». - person Michael Burr; 14.11.2008

Я не эксперт по безопасности, но думаю, что текущая рекомендация - использовать bcrypt / blowfish или вариант SHA-2, а не MD5 / SHA1.

Возможно, вам нужно подумать и о полном аудите безопасности.

person Gene T    schedule 13.11.2008

MD5 и SHA1 показали некоторую слабость (два слова могут привести к одному и тому же хешу), поэтому для хеширования пароля рекомендуется использовать SHA256-SHA512 / итерационные хеши.

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

  1. Не используйте MD5 / SHA1
  2. Создайте хорошую случайную соль (во многих криптографических библиотеках есть генератор соли)
  3. Итеративный алгоритм хеширования, рекомендованный orip
  4. Убедитесь, что пароли не передаются в виде обычного текста по сети.
person Kudos2u2    schedule 14.11.2008

Я хотел бы предложить одно улучшение отличного примера Python, опубликованного Orip. Я бы переопределил функцию random_bytes следующим образом:

def random_bytes(num_bytes):
    return os.urandom(num_bytes)

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

person Sergio    schedule 22.04.2009

Для хеширования пароля вы можете использовать функцию HashBytes. Возвращает varbinary, поэтому вам нужно будет создать новый столбец, а затем удалить старый varchar.

Нравится

ALTER TABLE users ADD COLUMN hashedPassword varbinary(max);
ALTER TABLE users ADD COLUMN salt char(10);
--Generate random salts and update the column, after that
UPDATE users SET hashedPassword = HashBytes('SHA1',salt + '|' + password);

Затем вы изменяете код для проверки пароля, используя такой запрос, как

SELECT count(*) from users WHERE hashedPassword = 
HashBytes('SHA1',salt + '|' + <password>)

где ‹password> - это значение, введенное пользователем.

person Vinko Vrsalovic    schedule 13.11.2008

хэшировать их с помощью md5. это то, что обычно делают с паролями.

person Mladen Prajdic    schedule 13.11.2008
comment
md5 и sha-1 оказались сломанными и не должны использоваться - person Gavin Miller; 13.11.2008
comment
Проблема с MD5 и SHA1 для хеширования паролей не в том, что они «сломаны», а в том, что они хешируются слишком быстро: securityfocus.com/blogs/262 - person Michael Burr; 13.11.2008
comment
@Mike - Нет, они действительно сломаны. Доказано, что коллизии могут возникать с помощью любого алгоритма: schneier.com/ блог / архивы / 2005/06 / more_md5_collis.html schneier .com / blog / archives / 2005/02 / sha1_broken.html - person Gavin Miller; 13.11.2008
comment
Эти коллизии на самом деле не снижают безопасность схемы паролей, особенно с учетом того, что в ней будет использоваться соль. - person Marcin; 13.11.2008