Comments 19
Хэш вообще не предназначен для защиты от MITM атак. Его главное назначение - защита от утечек паролей из серверной базы данных. И поэтому хэшированием занимается всегда сервер.
При передаче пароля в открытом виде есть одна проблема:
Если пароль передается в открытом виде то на вашем сервере он может утечь в лог файл.
Поскольку пользователи любят повторно использовать пароли- зная пароль можно его использовать для взлома других аккаунтов пользователя.
Если вы передаете хеш пароля- использовать пароль для взлома других аккаунтов не получиться.
Если ваша логика «у меня tls соединение и нечего заморачиваться с передачей пароля в виде хеша» то следующий логический шаг: почему бы не хранить пароль на стороне сервера в открытом виде? И зачем его вообще хешировать»?
При передаче пароля в открытом виде есть одна проблема:
TLS достаточно надёжно защищает передаваемые данные между клиентом и сервером. Это подтверждено большим количеством исследований и проверено временем. Так что пароль передаётся в зашифрованном виде, а не в открытом.
Если приложение пишет пароль (или хеш пароля) в логи, то это почти наверняка не единственная и не самая большая проблема с таким-то подходом к безопасности.
Верно. Именно по этой причине пароль предварительно солят перед тем как прогнать его через хеш функцию. Бывает ещё и перчат.
Согласен. Но теперь вам нужно как-то защититься от слива базы, что происходит несравнимо чаще, чем перехват пароля/хеша в полёте. Будете хранить в базе хеш от хеша?
И как вы можете гарантировать что пароль в лог файл не утечет?
Особенно если учесть что nginx у вас может использоваться как tls terminator, а после него все на чистом http взаимодействовать …
И как вы можете гарантировать что пароль в лог файл не утечет?
Проводить обучение разработчиков, админов и прочих причастных основам информационной безопасности, где объясняется, что логгирование пароля - плохо и чревато.
Особенно если учесть что nginx у вас может использоваться как tls terminator, а после него все на чистом http взаимодействовать …
Значит необходимо объяснить разработчику, что не стоит передавать пароль в query string, так как nginx по умолчанию записывает его в лог. Либо объяснить админу, что в nginx есть возможность логгировать урл без query string.
Этот механизм защищает от утечек, так как перехваченные данные бесполезны без динамической соли.
Можно сделать еще шаг вперед и наконец-то использовать схему с нулевой передачей знаний.
Нет вообще-то автор прав. Но здесь нюанс.
Кто сказал, что сервер будет использовать прямо хеш, который клиент прислал для сравнения? Это он не обязан делать вовсе. Правильной алгоритм, это когда сервер считает что клиент передает ему пароль и он ее солит, перчит и хеширует, а потом сравнивает с хешами в БД.
А клиент пусть делает что хочет – хочет хеширует, хочет не хеширует. Небольшой плюс хеширования на клиенте, это в том, что даже если кто и перехватит хеш, он пароль так и не узнает, а пользователь может использовать ту же пароль на многих ресурсах.
Если проект требует безопасной передачи пароля, не нужно хэшировать его на клиенте
Вы точно уверены, что достаточно компетентны для раздачи таких советов? Так-то протоколов с парольной аутентификацией больше одного, и некоторые из них специально созданы для работы в недоверенной среде (наиболее известен из них Kerberos).
Я прекрасно понимаю, что есть разные методы передачи пароля, но в данном случае из предисловия, сравнивался метод хэширования пароля на клиентской части, и сравнение с хэшем что лежит в базе и передачи пароля на прямую и проверка его на сервере, где сервер солит пароль и хэширует и сравнивает с тем что есть у него.
Вы сравнили два "перпендикулярных" алгоритма, решающих совершенно разные задачи. И, соответственно, никак не могущих заменять друг друга.
Ну и просто хэширование на сервере не годится, т.к. оно не обеспечивает невозможность сервера выдать себя за клиента на других ресурсах. Почитайте хоть про тот же SCRAM – зачем такую схему выдумали и что она обеспечивает.
в статье описывается прямо база. С одной стороны, любой более менее грамотный инженер - знает где использовать TLS, когда хэшировать пароли и тд. С другой стороны, в статье нет явных изъянов и логических ошибок, поэтому она хороша с образовательной точки зрения для тех кто вообще не в курсе как работает безопасность в интернете.
Но вот введение бы переписать, как-то слишком издалека зашли с частным примером, может быть чуть-чуть более абстракто и более обще сделать. Я зашёл поставить минус за введение, а прочитал - статья на самом деле хорошая и пишу коментарий позитивный
Спасибо, в следующий раз учту. А статья да, задумывалась как раз для тех кто не знает что такое TLS, и как работает базовая безопасность в вебе
[...] преподаватели из моего института начали приставать ко мне с вопросами о "безопасной" передаче пароля
Не стоит так высокомерно отзываться о преподавателях, даже если они действительно бегают за вами и умоляют захешировать пароли (в чём я лично сомневаюсь). Иначе зачем вы у них учитесь?
Пример механизма защиты с солью:
В вашем протоколе (по крайней мере, в том виде, в котором вы его описали) есть фатальный недостаток. Если злоумышленник каким-либо способом получит базу данных с хешированными паролями, он сразу же, безо всякого брутфорса и радужных таблиц, сможет авторизоваться от имени любого пользователя системы.
Если я правильно понимаю, вы предлагаете следующую схему (иллюстрация вольным псевдокодом):
server:
# Генерируем «динамическую» соль.
dsalt = gen_random_salt()
session.dsalt = dsalt
send(dsalt)
client:
dsalt = recv()
# А тут уже соль «статическая», но разная для разных пользователей.
h = hash(kdf(password, salt, parameters), dsalt)
send(username, h)
server:
(username, h) = recv()
dsalt = session.dsalt
kdfSavedValue = db.getKdfValue(username)
hExpected = hash(kdfSavedValue, dsalt)
if h == hExpected:
allowAccess()
else:
denyAccess()
Здесь hash
— некоторая стойкая хеш-функция с солью, kdf
— функция формирования ключа с солью и параметрами (вы называете этот этап «хеширует свой пароль, как это делает сервер»).
Обратите внимание, что в этой схеме для вычисления hExpected
не требуются ни соль, ни параметры KDF-функции, поскольку расчёт фактически перенесён с сервера на клиента, а проверяется уже готовый результат. А значит, если у злоумышленника есть слитая база с готовыми результатами, ему достаточно просто вычислить хеш и всё:
server:
dsalt = gen_random_salt()
session.dsalt = dsalt
send(dsalt)
hacker:
dsalt = recv()
username = "some_username"
kdfSavedValue = leakedDb.getKdfValue(username)
h = hash(kdfSavedValue, dsalt)
send(username, h)
Что это за преподаватели такие или скорее всего вы не понимали, что они имеют ввиду. Разумеется, пароли передаются от того клиента, который у пользователя на компьютере, к вашему серверу как шифрованные пароли, а не как хэши. А вот уже на сервере они сравниваются с хранимыми хэшами. Возможно, ваши преподаватели имели ввиду клиента системы аутентификации, который работает на сервере. Пароли на сервере хранятся не как пароли, а как хэши для того, чтобы пароли нельзя было украсть - в случае компрометации сервера украденные хэши не помогут злоумышленнику, потому что хэш по определению такая штука, из которой невозможно восстановить пароль. Так это устроено:)
Насчет того, что в бд хранится хэш, а не пароль, я прекрасно понимаю, так-как сливы базы из-за sql инъекций с нынешними библиотеками маловероятны, но не равны нулю.
Насчет-же преподавателей. Была целая дискуссия между мной и преподавательницей, которая вела у нас проектирование ПО, поэтому я отчетливо запомнил её доводы и предложения. Конечно я могу согласиться с доводами о том что пароль просто так передавать не безопасно по обычному http или при SSL 3.0 и 2.0, TLS 1.1 и 1.0, так как они являются устаревшими
Передача пароля по интернету: что безопаснее — хэширование или TLS?