Передача пароля пользователя для REST api
Я разрабатываю REST API, и у меня есть некоторые проблемы с точки зрения безопасности для аутентификации пользователя. Для аутентификации я не хочу, чтобы пароль отправлялся по сети в виде обычного текста.
чтобы обойти эту проблему, я мог бы отправить хэш SHA-256 пароля (с именем пользователя как соль), поэтому пароль никогда не отправляется в обычном тексте. В моей базе данных я буду хранить следующие хэши: SHA256 (пароль + соль) , и я буду сравнивать, если оба хэша спичка.
проблема с этой опцией заключается в том, что у меня будет хэш, вычисленный с помощью быстрого хэш-алгоритма, и соль не случайна.
в области безопасности рекомендуется использовать алгоритм медленной подписи со случайной солью (например, bcrypt).
медленный алгоритм не проблема, я мог бы использовать bcrypt на стороне клиента, но для соли я не знаю, что делать:
- Bcrypt нужна соль с определенным размером, поэтому я не могу поместить имя пользователя
- если я использую случайную соль, как клиент узнает значение этой соли перед вычислением хэша пароля?
поэтому я вижу 3 варианта, но ни один из них не sastisfying:
- Я отправляю пароль в виде обычного текста (я использую SSL), и я храню bcrypt в db => все еще уязвим для человека в середине
- Я использую SHA256 и отправляю хэш, где соль-это имя пользователя (все еще используя SSL) => хэш в БД меньше безопасный
- Я использую bcrypt, и у меня есть двухэтапный процесс: я прошу соль для данного пользователя, а затем отправляю хэш этого пользователя (все еще используя ssl)=>, пытаясь войти в систему с другим именем пользователя, я могу получить его соль, а не awesome
У кого-нибудь есть лучшее решение или некоторые советы?
4 ответов
есть несколько преимуществ в подходе хэширования на стороне клиента. Один из них-сервер никогда не получает реальных паролей, поэтому, если сервер каким-либо образом скомпрометирован, он все равно не получит реального пароля. Другой, он может облегчить нагрузку на сервер, если вы планируете использовать медленное хеширование.
однако хэширование паролей предназначено для защиты вас в случае нарушения базы данных и кражи хэшей. Это означает, что если кто-то получит хэшированные пароли, они все еще могут олицетворять пользователей, отправляя хэш. Подразумевается, что даже если вы хэш на стороне клиента, вам еще нужно повторно хэш на сервере.
другой потенциальный недостаток заключается в том, что это может отчуждать часть ваших юзербары, которые не имеют JavaScript включен.
для решения ваших пунктов:
Bcrypt нужна соль с определенным размером, поэтому я не могу поместить имя пользователя
Не используйте имя пользователя как соль. Соли должны быть уникальными, а имя пользователя (и его производные), безусловно, не является уникальным. Под уникальным я имею в виду не только уникальный сервер, но и уникальный везде. Использовать вместо криптографический код.
Если я использую случайную соль, как клиент узнает значение этой соли перед вычислением хэша пароля?
просто попросите сервер отправить соль (nonce) заранее. Вы могли бы сделать это и на клиенте, но Насколько я знаю, Javascript не имеет CSPRNG, и вам все равно нужно отправить nonce обратно на сервер.
Я отправляю пароль в виде обычного текста (я использую SSL), и я храню bcrypt в db => все еще уязвим для человека в середине
SSL был разработан, чтобы предотвратить человек в середине атаки. Если он не сломан, это не будет проблемой.
Я использую SHA256 и отправляю хэш, где соль-это имя пользователя (все еще использование SSL) = > хэш в БД менее безопасен
не использовать имя пользователя в качестве соли. И, как я уже сказал, Вы должны хэшировать на стороне сервера независимо от того, сделали ли вы это на стороне клиента.
Я использую bcrypt, и у меня есть двухэтапный процесс: я прошу соль для данного пользователя, а затем отправляю хэш этого пользователя (все еще используя ssl)=>, пытаясь войти в систему с другим именем пользователя, я могу получить его соль, а не удивительный
Не действительно удивительным.
Я думаю, вы могли бы объединить / запутать несколько вопросов здесь:
- Если вы храните хэш (пароль + имя пользователя) на сервере, а аутентификация включает отправку хэша(пароль + имя пользователя), вы на самом деле не достигли ничего лучше, чем просто хранить пароль на сервере. Цель долгосрочного хранения хэшей заключается в том, что если у вас есть нарушение данных (т. е. злоумышленник получает доступ к базе данных), они все равно не могут создать правильное значение для аутентификации. Но если вы делаете простое сравнение, это еще вопрос.
- правильное использование хэширования + соления: (1) сервер хранит кортежи(соль, хэш (пароль + Соль); (2) пользователь отправляет (заявленный пароль); (3) сервер вычисляет хэш (заявленный пароль + Соль); (4) если хэш(заявленный пароль + соль) == хэш (пароль + соль), то они аутентичны. Таким образом, даже если злоумышленник получает доступ к базе данных, они не могут создать утвержденный пароль, который является хэшем (утвержденный пароль + соль) действительный.
- отправка пароля открытого текста через SSL не "в чистом виде". Комментарий @NullUserException, если злоумышленник не нарушил SSL. Только сервер сможет получить значение пароля (при условии, что открытый ключ сервера действителен, что является целой "другой историей").
надеюсь, что это помогает!
- сделайте константу соли, скажем, сделайте ее хэшем имени пользователя. Так что
hash_val = HASH(HASH('username') + 'password')
хранится на стороне сервера. - для аутентификации ваш сервер отправляет одноразовое случайное значение, т. е.:
nonce = HASH(RAND())
- ваш клиент вычисляет следующее на основе входных учетных данных
client_hash = HASH( nonce + HASH(HASH('username') + 'password'))
и отправляет его обратно на сервер. - сервер выполняет ту же операцию, сравнивает полученные хэши и отбрасывает nonce.
таким образом хэш отправленный по проводу используется только один раз, и вы защищены от "воспроизведения" и атак MITM.
кроме того, посмотрите на что-то вроде PBKDF для хранения паролей, а не только хэшей, это делает таблицы bruteforcing и rainbow совершенно непрактичными. вот реализация PHP, которую я использую, так как она еще не в PHP.
Если возможно, создайте ключ API и секретный ключ (имя пользователя/пароль API, очевидно, уникальный для каждого пользователя) для использования API. Вы должны дать возможность в интерфейсе вашего сайта активировать / деактивировать доступ к API, а также возможность повторно генерировать ключ API и секретный ключ. Здесь, на этом интерфейсе пользователи увидят API / секретный ключ API.