Как отправить пароль безопасно через HTTP?


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

Итак, вопрос в том, как правильно защитить пользователя и его пароль от третьей стороны, которая может подслушивать данные связи?

Я знаю, что HTTPS является решением проблемы, но есть ли способ обеспечить хотя бы некоторый уровень безопасности с помощью стандартного HTTP протокол (почтовый запрос)? (возможно, используя javascript в некотором роде)

EDIT Возможно, я упустил некоторые важные вещи.

то, о чем я говорил, было страницей - это страница входа в PHP, которая, конечно же, отправляется пользователю в HTTP GET request в виде HTML-файла. Между сервером и клиентом нет соединения (@Jeremy Powel), поэтому я не могу создать такой протокол квитирования. И я хочу, чтобы весь процесс был прозрачным для пользователя - он хочет отправить пароль, не шифрование.

спасибо.

8 97

8 ответов:

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

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

сертификаты TSL/SSL в наши дни довольно дешевы. На самом деле, если вы не хотите тратить деньги вообще есть бесплатный letsencrypt.org - автоматизированный центр сертификации.

Вы можете пойти на один шаг дальше и использовать caddyserver.com который вызывает letsencrypt в фоновом режиме.

теперь, как только мы убрали HTTPS с дороги...

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

  • имя пользователя и пароль объединяются в строку, разделенные двоеточие, например: username: password
  • результирующая строка кодируется с помощью RFC2045-MIME вариант Base64, за исключением не ограничиваясь 76 char / line.
  • метод авторизации и Пробел, т. е. "базовый", тогда поставьте перед закодированной строкой.

источник: Википедия: заголовок Authorization

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

есть несколько веские причины вы должны использовать заголовок авторизации

  1. стандартный
  2. это просто (после того, как вы узнаете, как их использовать)
  3. это позволит вам войти в систему на уровне URL, например:https://user:password@your.domain.com/login (Chrome, например, автоматически преобразует его в )

важно:
Как указал @zaph в своем комментарии ниже, отправка конфиденциальной информации в качестве запроса GET не является хорошей идеей, поскольку это будет большинство скорее всего, в конечном итоге в журналах сервера.

enter image description here

вы можете использовать схему "вызов-ответ". Скажем, клиент и сервер оба знают секрет S. Тогда сервер может быть уверен, что клиент знает пароль (не отдавая его):

  1. сервер отправляет клиенту случайное число R.
  2. клиент отправляет H (R,S) обратно на сервер (где H-криптографическая хэш-функция, например SHA-256)
  3. сервер вычисляет H (R,S) и сравнивает его с ответом клиента. Если они совпадают, сервер знает клиент знает пароль.

Edit:

здесь есть проблема со свежестью R и тем фактом, что HTTP не имеет состояния. Это может быть обработано, если сервер создаст секрет, назовите его Q, что только сервер знает. Тогда протокол выглядит так:

  1. сервер генерирует случайное число R. затем он отправляет клиенту H (R,Q) (который не может быть подделан клиент.)
  2. клиент отправляет R, H(R, Q) и вычисляет H(R,S) и отправляет все это обратно на сервер (где H-криптографическая хэш-функция, например SHA-256)
  3. сервер вычисляет H (R,S) и сравнивает его с ответом клиента. Затем он берет R и вычисляет (снова) H(R,Q). Если клиентская версия H(R,Q) и H (R,S) соответствует повторному вычислению сервера, сервер считает, что клиент аутентифицирован.

отметить, так как H (R,Q) не может быть подделан клиентом, H (R,Q) действует как cookie (и поэтому может быть реализован фактически как cookie).

Другой Редактировать:

предыдущее редактирование протокола неверно,так как любой, кто наблюдал H(R, Q), похоже, может воспроизвести его с правильным хэшем. Сервер должен помнить, какие R больше не являются свежими. Я CW'ING этот ответ, так что вы, ребята, можете отредактировать это и выработать что-то хорошее.

Если ваш веб-хост позволяет это, или вам нужно будет иметь дело с конфиденциальными данными, а затем использовать HTTPS, период. (Это часто требуется законом afaik).

в противном случае, если вы хотите сделать что-то по HTTP. Я бы сделал что-то вроде этого.

  1. сервер вставляет свой открытый ключ в страницу входа.
  2. клиент заполняет форму входа и нажимает кнопку Отправить.
  3. запрос AJAX получает текущую метку времени с сервера.
  4. клиент side script объединяет учетные данные, метку времени и соль (хэшируется из аналоговых данных, например. движения мыши, события нажатия клавиш), шифрует его с помощью открытого ключа.
  5. отправляет полученный хэш.
  6. сервер расшифровывает хэш -
  7. проверяет, достаточно ли свежа временная метка (позволяет использовать только короткое 5-10-секундное окно). Отклоняет логин, если метка времени слишком стара.
  8. сохраняет хэш в течение 20 секунд. Отклоняет тот же хэш для входа в систему во время этого интервал.
  9. аутентификацию пользователя.

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

о безопасности токена сеанса. Это немного сложнее. Но можно сделать повторное использование украденного токена сеанса немного сложнее.

  1. сервер устанавливает дополнительный файл cookie сеанса, который содержит случайную строку.
  2. браузер отправляет этот файл cookie на следующий запрос.
  3. сервер проверяет значение в файле cookie, если оно отличается, то он уничтожает сеанс, в противном случае все в порядке.
  4. сервер снова устанавливает куки с другим текстом.

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

о реализации: RSA, вероятно, самый известный алгоритм, но он довольно медленный для длинных ключей. Я не знаю, насколько быстрой будет реализация PHP или Javascript. Но, вероятно, есть более быстрые алгоритмы.

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

можно использовать SRP использовать безопасные пароли по незащищенному каналу. Преимущество заключается в том, что даже если злоумышленник обнюхивает трафик или компрометирует сервер, он не может использовать пароли на другом сервере. https://github.com/alax/jsrp - это библиотека javascript, которая поддерживает безопасные пароли через HTTP в браузере или на стороне сервера (через узел).

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

вот исходный код Java, который использует асимметричный шифр RSA (используемый PGP) для связи: http://www.hushmail.com/services/downloads/

вы можете использовать ssl для вашего хоста есть бесплатный проект для ssl, как letsencrypt https://letsencrypt.org/