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

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

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

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

редактировать Возможно, я упустил кое-что важное.

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

спасибо.

8 ответов


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


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

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

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

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

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

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

источник: Википедия: заголовок 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. клиент боковой скрипт объединяет учетные данные, метку времени и соль (хэшируется из аналоговых данных, например. движения мыши, события нажатия клавиши), шифрует его с помощью открытого ключа.
  5. отправляет полученный хэш.
  6. сервер расшифровывает хэш -
  7. проверяет, достаточно ли недавняя метка времени (позволяет короткое 5-10-секундное окно). Отклоняет логин, если метка времени слишком старая.
  8. сохраняет хэш в течение 20 секунд. Отклоняет тот же хэш для входа в систему во время этого интервал.
  9. аутентификацию пользователя.

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

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

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

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

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


Я бы использовал серверную и клиентскую систему обмена ключами Диффи-Хеллмана с 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/