Как стать автором
Обновить

Комментарии 109

а серьезный security чувак — это который щас в Бангалоре офис разработки LinkedIn открыл — ну успехов им, чо.
Жаль что даже такие крупные конторы задумываются о безопасности только после таких вот инцидентов. Почему бы сразу было не «посолить»
Потому что делятся на два типа
Ну, что сказать. Эти случаи и подтолкнули меня заменить наш SHA1 + статичная соль => SHA512 + рандомная соль для каждого юзера
Как реализуется рандомная соль? Я понимаю что генерится случайное число (набор символов) которое добавляется к паролю, но куда оно потом записывается — в базу или какой-то левый файлик? Ведь по сути нужно хранить все соли для всех пользователей что бы они смогли логиниться.
НЛО прилетело и опубликовало эту надпись здесь
Тогда от нее столько же пользы как и от статичной соли — достаточно понять алгоритм (аля статическую соль) и дело в шляпе. Все же думаю соль должна быть именно рандомной, никак не завязанной на данные пользователя которые лежат в базе (которую могут спереть). Но вот как с ней тогда работать — это мне и интересно.
Можно ведь не хранить в базе саму соль, можно придумать какой-то алгоритм.
Например — 3 символа почты юзера+три буквы логина+статичная соль
Если у взломщика не будет доступа к сорсам то думаю поломать будет сложно
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Насколько я понимаю как раз польза есть. Если соль статичная для всех юзеров, то достаточно сгенерить одну радужную таблицу и прогнать через нее все хеши. Если соль разная для каждого пользователя, то злоумышленнику придется генерить для каждого свою таблицу.
Опять же рандомная соль или нет (например, на основе логина) разницы нет, потому как соль обычно хранят в той же базе, в той же таблице рядом с хешем.
А если соль составная по алгоритму, который без исходников не получить. Насколько сложнее будет осуществить взлом?
Нельзя надеяться на алгоритм в коде. Могут взломать сервер, украсть ноут разработчика и т.д. Тем более что если утекла база, то большая вероятность того, что и исходники ушли. Помогает только соль и правильно выбранный (медленный) алгоритм хеширования.
Люди, какие исходники? Дизасемлер никто не отменял.
Дизассемблерить пхп или руби? Это, конечно, сильно.
Извините, я забыл что авторизация нужна только в проектах на php и руби. А вы зачем подписаны на хаб java?
В данном случае идет разговор про веб-приложения. Да и ту же jav'у вы тоже будете дизассемблировать?
Нельзя-ли цитату, которая позволила вам думать о веб приложении?
Понятно… Сложно бороться против устоявшихся стереотипов.
Тут надо мыслить как хорошие доктора:
— всегда предполагаем более сложный диагноз.
Теперь вроде понятнее, то есть проблема не в факте возможности подбора хешей, а в скорости их подбора. То есть рандомная соль работает просто как тормоз для брутфорса. Интересно.
любая идея по алгоритмической защите паролей сводится именно к замедлению полного перебора. Нужно исходить из предположения, что злоумышленник знает алгоритм и закодированное сообщение (хэш в нашем случае).
Об этом должны знать все, кто пишет код авторизации. К сожалению, мой опыт говорит, что это не так :(
Можно хранить в базе рядом с хэшем пароля. Массовый брутфорс будет невозможен, только каждый отдельно брутфорсить., одинаковые хэши будут только случайными коллизиями (если соль уникальна у каждого).
Если у злоумышленника будут все хеши и соли в том числе, то сложность будет только в понимании алгоритма, а как уже всем прожужжали уши, безопасность основанная на закрытости алгоритма — очень фиговая безопасность.
Такой бред вообще. Соль не решает проблемы подбора отдельного пароля. Она мешает подобрать сразу все пароли брутфорсом (или используя радужную таблицу, не важно).
Так расскажите что решает, весь топик пестирит комментариями про «то не решает», «это не решает», а что решает никто так и не сказал.=)
Обычная соль решает проблему коротких паролей и совпадающих хэшей одинаковых паролей на разных сайтах. Индивидуальная соль дополнительно решает проблему совпадающих хэшей одинаковых паролей на одном сайте. Проблему брутфорса в целом решает длина хэша (читай — уменьшение вероятностей коллизий) и сложность алгоритма (читай — необходимые для брутфорса ресурсы).
Это логично и понятно, я думал может есть какое-то элегантное решение, зная которое, народ не принимает это.
Решает только стойкий пароль. Соль, тип хеширования, свой алгоритм предназначены для того, чтобы увеличить время брутфорса.
НЛО прилетело и опубликовало эту надпись здесь
И стоит увести эти самые два ключа, как безопасность всей системы летит к чертям?
НЛО прилетело и опубликовало эту надпись здесь
Ну соль для каждого пользователя и вводится как раз на тот случай, чтобы даже имея полный доступ ко всему, настоящие пароли пользователей было получить невозможно, ну или, по крайней мере, очень сложно.
НЛО прилетело и опубликовало эту надпись здесь
Есть ещё угроза компрометации пользовательских паролей. Далеко не все используют разные пароли на разных сервисах, поэтому даже имея root-доступ к серверу (то есть получив доступ ко всем пользовательским данным на нашем сервере) злоумышленник не должен получить (легко) пароли пользователей.
а как насчёт How To Safely Store A Password (http://codahale.com/how-to-safely-store-a-password/)?
Такое же мнение, bcrypt больше подходит для этих целей. SHA1 и SHA512 слишком быстрые алгоритмы.
Сколько хэшей HMAC SHA512 вы посчитаете в секунду? Какова вероятность получить коллизию из пароля и соли длиной 10 спец- и неспецсимволов? Какова практическая польза от радужниых таблиц для паролей с собственной солью для каждого юзера?
а теперь давайте поразмышляем о простом пароле, типа 12345 — согласно вашей идее его безопасность будет обеспечена ТОЛЬКО солью. У вас какого размера соль в проектах?
У нас правила сложных паролей, для начала. А соль у меня 10 символов, тоже несловарная.
Кстати, польза от радужных таблиц для паролей с собственной солью для каждого юзера никакая, я это понимаю. Но я и не говорил, что радужные таблицы помогут.
На сегодняшний день ваш способ хранения паролей относительно безопасный. Однако я обращаю внимание, что сейчас ведутся исследования SHA-3, потому что SHA-2 (включает SHA-512) алгоритмически похож на SHA-1, в котором нашли коллизии. Это не значит, что Бкрипт лучше, но судя по всему Блоуфиш лучше исследован, что даёт надежду.
А ведь вроде как айтишный сайт :)
Любой сайт пишут айтишники) Но почему-то не везде есть соль.
Соли, хеши… Ну ладно маленькие стартапы, но большой компании-то какие проблемы сделать отдельный внутренний сервис для валидации пароля, доступ к которому будет только через простой API, не позволяющий получить доступ к базе данных?
Ну, сделали, допустим. И что мешает увести уже эту выделенную базу? Никакого радикального улучшения безопасности это не даст.
Помешает то, что не должно быть технической возможности это сделать :) Например, API к сервису принимает имя пользователя и пароль, и возвращает флаг 0/1 говорящий, правильный пароль или нет. Каким образом через такой API можно увести всю базу? (естественно, доступа к базе данных не через этот API нет, разве что физический доступ но это уже другой вопрос)
Если есть API, есть и хост сайта. Какой-то мелкий огрех в настройке сервера — и базы утекли.
Не, ну если рассчитывать на то, что база данных в любой момент может оказаться доступной кому попало, то конечно…
Если есть возможность сделать неутекаемую базу, то зачем городить API для аутентификации, а не перенести туда всю базу?
База подразумевает доступ к данным, проверка пароля — не обязательно. Это разные API, и при непосредственном доступе к данным риск очевидно больше.
API аутентфикации возвращает false/true в ответ на id пользователя и пароль (а скорее токен аутентификации). В чём качественная разница от API, например, банка, возвращающего содержание транзакции по её id? Если мы сумели надёжно защитить от компрометации данные аутентификации, то почему бы также не защитить данные предметной области?
Я не очень понимаю ваших аргументов, поэтому попробую ещё раз объяснить, на примере линкедин — можете указать, где я неправ?

Почему у них утекла база? Наверняка где-нибудь в одном из скриптов на сайте профейлили инъекцию или что-нибудь в это роде. Почему это позволило получить всю базу данных? Потому что есть возможность прочитать всю базу из любого скрипта. В случае, если такой возможности нет, а можно только для данного «токена аутентификации» получить результат да/нет, базу слить так просто не получится. Налицо качественная разница, не? :)
Так я и предлагаю вынести всю базу за API, чтобы ни у одного скрипта не было возможности её всю прочитать, раз уж мы умеем делать API не подверженное инъекциям и т. п.
Дык это только для аутентификации не нужно всю базу читать, а для других действий может и нужно. Чем меньше ответственность, тем проще сделать надёжно, не очень понимаю зачем всю базу пытаться спрятать а не только важную информацию.
Потому что вся база важная? А уязвимость системы определяется самым слабым звеном?

Вам будет легче если деньги с вашего счёта выведут не аутентифицируясь вами, а получив root-доступ к базе со счетами и транзакциями? Максимум чем вам будет легче от наличия API аутентификации — ваш пароль не используют для аутентификации в другом сервисе, где он у вас такой же.
Финансы — это отдельный вопрос. Мои рассуждения всё же относились к «простым» сайтам, где не так много существенно важной информации. Но и в общем, подход тот же — выделить из сложной системы простые компоненты, которые можно тщательно проверить. Произвольный доступ к базе данных с финансовыми транзакциями нормальные люди давать не будут. А тщательно проверить всё-всё-всё никаких денег не хватит.
Возьмём хабр. E-mail пользователя существенная информация? Его личная переписка с другими пользователями? Имхо, существенная, за её разглашение руководство хабра формально может нести ответственность вплоть до уголовной.

Есть ли смысл выделять профиль и т. п. в отдельное внешнее API с экранированием SQL запросов? Может легче просто экранировать все запросы?
Если дело только в экранировании запросов, то возможно легче, да. Но вот, например, у меня есть мегабайт сорцов, написанных разными людьми. Можно ли легко проверить, что все запросы там экранированы? Вопрос опять же сводится к простому API, которое будет гарантировать «экранированность», и это API отделяет «безопасную» часть системы от обычной.
Я бы расставил приоритеты данным по важности и разделял на уровни в зависимости от приоритета. Количество уровней, конечно, зависит от проекта, но не иметь ни одного такого уровня и поиметь возможность залезть в базу данных непосредственно из поля ввода данных — это жесть. Ну я думаю мы друг друга поняли, вон у хабра уже ширина кончилась :)
Не думаю, что уводили через API. Как правило, уводят через баги, либо в самом API, либо в окружающей среде.
Поэтому я и говорю про отдельный внутренний сервис. Его легко проверить, т.к. у него очень ограниченная ответственность, и после проверки заморозить и не трогать больше.
Уводят потому, что доступ к базе данных есть у любого скрипта. Вот и получается, что любая ошибка в любом скрипте огромного сайта приводит к уязвимостям. Когда скрипты не имеют прямого доступа к бд с паролями, проблемы и нет.
Вообще в этом есть логика
НЛО прилетело и опубликовало эту надпись здесь
ага, профессионала… индуса)
Видимо «проффесионалы по ИТ-безопастности» так увлеклись кулинарией, что забыли посолить…
На мой взгляд очевидным «дополнительным уровнем безопасности» было бы сменить еще и сам алгоритм на более медленный.
bcrypt + соль = здоровый сон
настоящий bcrypt включает в себя генерацию соли, так что не солите солёное, пожалуйста.
А как же радужные таблицы? Он же не может генерировать разный хеш для одного пароля.
в бкрипте, если я правильно понял прочитанное, соль является результатом вычисления сложной функции (причем вычислительная сложность функции регулируется). Где-то в алгоритме используется и генератор псевдослучайных чисел. Я не профессионал в области криптографии, лучше почитайте сами, если сомневаетесь.
Да я и не сомневаюсь. Я знаю, что алгоритм требует соль как аргумент. Если интересно почитайте вику ru.wikipedia.org/wiki/Bcrypt
Бкрипт — это алгоритм шифрования, результатом которого является хешь. Он по определению не может быть рандомным и при одинаковых входных аргументах, должен возвращать одинаковый хеш.
Бкрипт — это алгоритм шифрования

Нет.

результатом которого является хешь

Тоже нет. Выходом BCrypt является длинная строка вида $A$BB$SaltCyphertext, где A — версия алгоритма (2), BB — log2 от количества раундов шифрования Blowfish, а Salt и Cypertext — двоичная соль и двоичный хэш в представлении base64.
>> Бкрипт — это алгоритм шифрования
>Нет.

Наскольо я знаю, хешированием называют необратимое шифрование. Если это не так поправьте.

>>Бкрипт — это алгоритм шифрования, результатом которого является хешь
>Тоже нет…
Про функцию вы правы, но я говорил об алгоритме.
Исходник py-bcrypt лучше всяких слов:
def gensalt(log_rounds = 12):
        """Generate a random text salt for use with hashpw(). "log_rounds"
        defines the complexity of the hashing, increasing the cost as
        2**log_rounds."""
        return encode_salt(os.urandom(16), min(max(log_rounds, 4), 31))

Где encode_salt просто переводит псевдослучайную последовательность 16 байтов в base64 и возвращает строку вида $2$log_rounds$base64(salt). Ничего сложного тут нет.
Или вы имели ввиду, что алгоритм требует наличие соли как аргумент и сам пароль солить не нужно?
товарищ ~Local уже написал выше: применять bcrypt можно для 2 целей:
1) создание хэша. В этом случае на вход даётся пароль и сложность (число). Результат — строка с айди алгоритма, сложностью, солью (сгенерированной алгоритмом самостоятельно, без вас) и хэш.
2 проверка: хэш получен из пароля. На вход даётся сгенерированная в 1) строка и пароль открытым текстом.
Ну вот как-то так примерно.
Подчеркну еще раз: я говорю об алгоритме, а не о конечной реализации этого алгоритма в виде функции, библиотеке или класса.
bcrypt не требует соли для создания хэша пароля. Однако на выходе кроме хэша пароля возвращается также сгенерированная соль.
Я устал повторять, что вы путаете библиотеку с алгоритмом
Вы говорите о реализации на каком-то конкретном языке программирования, в виде конечной библиотеке, которая сама генерирует соль и передает ее хеширующей функции bcrypt.
Господа, извиняюсь, если кого-то запутал своим комментарием. Я действительно рассматривал конкретную реализацию py-bcrypt, которая среди прочих реализаций порождает ложную идею, что «соль является результатом вычисления сложной функции».

hashed = bcrypt.hashpw(password, bcrypt.gensalt(12)) # сложность подаётся на вход функции, генерирующей соль

Поскольку соль обязательна для Blowfish, многие реализации BCrypt (py-bcrypt, JFBCrypt (objective c), jBCrypt (java), bcrypt.net) предлагают собственную функцию типа gensalt для генерации соли, зависящей от сложности (на самом деле не очень зависящей). Но везде gensalt нужно вызвать самому, кроме bcrypt-ruby, где вообще момент генерации соли скрыт.

Остаётся реализация на PHP, которой нет. Но если есть поддержка BlowFish, BCrypt достаточно просто реализовать самому. Только если отклониться от формата $Version$LogRounds$base64(SaltHash), ни одна библиотека не сможет работать с ним. Тут заканчивается алгоритм и начинается реализация.
Реализация на PHP есть — php.net/manual/ru/function.crypt.php
Пример из мануала:
$hash = crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$');


второй аргумент функции — параметры хеширования, в где $ является разделителем этих параметров:
1. 2а — версия алгоритма;
2. 07 — кол-во раундов;
3. соль.
НЛО прилетело и опубликовало эту надпись здесь
Там SHA1 кэши были.
Хэши, наверное.
За ошибки проектирования/кодирования не сажают, особенно если требования государства по КЗИ выполнены — ведь тогда надо сажать тех, кто эти требования узаконил.
НЛО прилетело и опубликовало эту надпись здесь
Ответственность за разглашение, например, ваших персональных данных или, скажем, банковской тайны есть у начальства программистов: это их работа не допускать разгильдяйства.

Программист несёт ответственность (уголовную) только за создание заведомо вредоносного кода. Можно ли считать, допустим, передачу GET-параметров в SQL СУБД без экранирования и/или фильтрации вредоносным кодом — вопрос открытый. По идее можно попробовать инкриминировать преступное легкомыслие («этот урл никто не должен знать, потому не буду фильтровать») или преступную небрежность (называет себя программистом, но про sql-инъекции не слышал). Но «компьютерные» статьи УК не предусматривают ответственность за такие деяния совершенные по неосторожности, только умысел (прямой — «оставлю для себя лазейку», — или косвенный — «мало платят — фиг буду фильтровать, пускай кто-нить сломает») должен быть.
НЛО прилетело и опубликовало эту надпись здесь
Фирму-владельца могут заставить выплатить компенсации. Может даже наказать руководителей могут. Наказать конкретных кодеров или админов — уволить разве что за несоответствие.
Интервью с Thomas Ptacek (English) вполне внятно рассказывает, что защищаться надо не сложностью соли, а усложнением генерации каждой проверки. Т.е. как тут уже упоминали — вместо быстрых алгоритмов Md5\Sha1\Sha-512 надо использовать Bcrypt? потому что это алгоритм для хэширования паролей, а не произвольных данных ( все предыдущие) — т.е. он умышленно сделан не мгновенным.

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

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

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

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

Что можно сделать сейчас со своими несоленными БД. Многие почему-то думают, что пока не получите plain-password — пересолить невозможно. На самом деле все банально, берем существующий хэш, дописываем к нему user-specific соль (пусть будет логин) и шифруем BCrypt. Добавляем префикс bcrypt<результат> и пишем в базу. Т.к. это процесс «небыстрый» на миллионах пользователей, можно временно в функции проверки пароля сделать банальное ветвление — если полученный из бд результат начинается с bcrypt — используем новый алгоритм при проверке, если нет — старый несоленный. Это позволит работать всем пользователям пока вы будете перешифровывать базу паролей.

Собственно все ;)
Только не надо вручную солить при использовании BCrypt, в алгоритме уже заложена засолка urandom-случайной солью нужной битности.
Сам пароль не нужно солить. Но генерировать соль всё равно необходимо самому. Аргумент принимает три параметра:
1. Шифруемая строка;
2. Соль;
3. Кол-во итераций.
*Алгоритм принимает три параметра.
мне неясно, какой именно алгоритм? Можно рассматривать bcrypt как blowfish(), которому передаётся специальная соль, которая нигде не хранится, а вычисляется перед вызовом blowfish() — ну это упрощённо.
А можно рассматривать bcrypt в целом — ну тогда на вход даётся шифруемая строка, соль и сложность (а количество итераций будет два в степени сложность).
Большинство реализаций bcrypt создают соль сами на основе какого-то источника псевдослучайных чисел — urandom(), time() и др.
Я и говорю об алгоритме bcrypt в целом, не углубляясь в конкретные реализации в виде библиотек упрощающих работу с bcrypt. Я об этом битый час пишу.
На мой взгляд, судить об алгоритме, исходя из опыта использования конкретной библиотеке на питоне — не правильно. И, например, на Java и PHP реализация такова, что передавать соль нужно в виде параметра.
Из справки PHP по функции crypt():
salt
An optional salt string to base the hashing on. If not provided, the behaviour is defined by the algorithm implementation and can lead to unexpected results.
И зачем же Вам в Вашем приложении нужен код, который приводит к непредсказуемому результату?!
Господин local видимо путает библиотеку bcrypt, использующую этот алгоритм, с самим алгоритмом bcrypt, который по определению должен возвращать одинаковый хеш при равных условиях (одинаковых входных данных). Библиотеки же упрощают работу программиста, беря на себя роль как создание хеша, так и генерацию соли для создания хеша.
На php, если указать соль короче 22 символов или не указать совсем, то она будет дополнена знаками доллара. Из любопытства проверил :)
crypt() и bcrypt — это разные вещи. Надо понимать, что для получения bcrypt надо в crypt() передать в поле «соль» строку из 3 параметров, включая результат преобразования Eksblowfish(соль) — и вот в этом вычислении Eksblowfish() лежит солидная доля замедления.
Складывается впечатление, что большинство спорщиков (кроме Lockal) вообще не потрудилось почитать о том, что же такое bcrypt на самом деле. Ну вот вы хотя бы открывали статью в вики про bcrypt?
Видимо,, так и придется заниматься копипастом:

bcrypt(cost, salt, key, input)
state EksBlowfishSetup(cost, salt, key)
ctext input
repeat (64)
ctext EncryptECB(state, ctext) // шифрование стандартным Blowfish в режиме ECB
return Concatenate(cost, salt, ctext)

Может вы другую статью читали? В bcrypt, как мы видим, нужно передавать cost, slot и шифруемый текст.
P.s. Пишу с пада и что-то не нашел как отформатировать код. Буду признателен, если кто подскажет тег на такой случай.
а я предыдущий комент в этой ветке не вам писал, а Kolonist. Он там написал именно о crypt().
Пока я писал, Вам уже вместо меня ответили. Собственно, я примерно то же самое написал — в bcrypt надо явно задавать соль, равно как и в функции crypt(), когда мы вычисляем с ее помощью bcrypt-хэш.
«большинство спорщиков» !== «Kolonist»
так, ладно. Я где-то чего-то (кого-то?) недопонял, но никого не хотел обидеть. Понятно, что вы, RubtsovAV, в вопросе разобрались. Kolonist тоже.
Да не в обиде дело, я лишь хотел донести свою мысль.
Согласен, возникла некоторая путаница. В справке, которую я цитировал, говорится об отсутствии параметра $salt вообще, а без него функция crypt() по алгоритму bcrypt работать не будет.

Тем не менее, как заметил пользователь RubtsovAV, если соль не задавать (не параметр функции crypt(), а именно соль в строке $2a$cost$salt), то по-умолчанию будет использоваться строка, состоящая из знаков $. Так что не указывать соль, как предлагает Lockal, нельзя.

Ну вот вы хотя бы открывали статью в вики про bcrypt?
Хотя бы открывал. И там ничего не сказано о том, что bcrypt сам генерирует соль. Напротив, там указан такой формат вызова функции:

bcrypt(cost, salt, key, input), где input, при использовании стандартной функции crypt() в различных ОС равен константе «OrpheanBeholderScryDoubt».

Как видим, параметр salt очень даже присутствует.
Я немного выбьюсь из общего профессионального обсуждения — а мне вот показалось, что я сейчас наведу на ссылочку под словом «хороший», а там будет ссылочка куда-нибудь сюда.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации