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


115

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

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

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

ИЗМЕНИТЬ Возможно, я упустил некоторые важные вещи.

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

Спасибо.


1
Вы, вероятно, не сможете добиться этого без клиента, использующего криптографию, но пользователю не обязательно видеть такой процесс. Он просто вводит свой пароль, и код, генерируемый вашим PHP (например, javascript), обрабатывает все это за вас.
Джереми Пауэлл

13
Проблема, которую вы описываете, является причиной изобретения HTTPS. Если вы отправите секрет клиенту, чтобы зашифровать пароль, перехватчик сможет его перехватить и расшифровать на обратном пути.
jnoss

1
Таким образом, S в вашем предложении может быть только паролем (или любым сочетанием имени пользователя и пароля), поскольку это единственный «секрет», который есть у пользователя. Я прав? Таким образом, решение будет следующим: - Сервер предоставляет HTML-страницу со скрытым полем формы R - Пользователь вводит пароль, и перед отправкой пароля javascript вычисляет H (R, S) и отправляет его на сервер, возможно даже с использованием AJAX - сервер вычисляет H (R, S) и сравнивает его с полученным и отправляет ответ на запрос ajax, прошла ли аутентификация - JavaScript перенаправляет браузер на желаемую веб-страницу
Kornelije Petak

2
@jeremy Powell - хотя то, что вы описываете, является обычной практикой, оно также уязвимо для посредника, который может прослушать файл cookie из заголовка и выдать себя за пользователя, повторно используя файл cookie.
От

1
Для тех, кто ответит на этот вопрос в будущем: ПОСЛЕ входа в систему вам также необходимо защитить файл cookie сеанса. (Итак: использовать HTTPS действительно намного проще.)
Arjan

Ответы:


66

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


14
... и "Но я должен заплатить за сертификат SSL !!" не является обоснованной жалобой, так как в наши дни вы можете получить их за 30 долларов. Неужели защита ваших данных не стоит 30 баксов?
caf,

3
Что делать, если веб-хостинг, на который вы подписались, не поддерживает добавление сертификатов SSL?
Calmarius

89
@Calmarius - тогда вы переходите на настоящий веб-
хостинг

3
@BornToCode. Технически это означает, что вам нужен выделенный IP-адрес и вам необходимо владеть серверным оборудованием (или хотя бы VPS) для использования HTTPS. Общие веб-хосты не могут использовать HTTPS, если весь сервер не защищен сертификатом владельца хоста.
Calmarius 07

6
общие веб-хосты, безусловно, могут использовать https, используя en.wikipedia.org/wiki/Server_Name_Indication
Брайан Минтон,

39

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

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

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

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

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

  • Имя пользователя и пароль объединяются в строку, разделенную двоеточием, например: имя пользователя: пароль.
  • Результирующая строка кодируется с использованием варианта RFC2045-MIME Base64, за исключением 76 символов на строку.
  • Затем перед закодированной строкой ставится метод авторизации и пробел, то есть «Базовый».

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

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

Есть несколько веских причин, по которым вам следует использовать заголовок авторизации.

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

ВАЖНО:
как указал @zaph в своем комментарии ниже, отправка конфиденциальной информации в виде запроса GET не является хорошей идеей, поскольку она, скорее всего, попадет в журналы сервера.

введите описание изображения здесь


11
Проблема с отправкой учетных данных (пароля) в качестве параметров GET заключается в том, что пара пользователь / пароль, вероятно, попадет в журналы сервера, что не является хорошей идеей. Лучше всего отправлять учетные данные в POST.
zaph

Ах ... совсем нет. Снимок экрана, который вы видите, изменен, чтобы показать, что происходит в браузере. В тот момент, когда вы нажмете Enter, браузер преобразует ваш URL-адрес, создав Authorizationзаголовок. Просто попробуй. Журналы будут напоминать чистые. И, конечно, если вы звоните с сервера (если это сценарий, о котором вы беспокоитесь), вы, конечно, должны сгенерировать заголовок программно.
FullStackForger

Вы не можете записывать то, что не видите. username:password@urlиз браузера переводится как: url+ Authorizationзаголовок запроса. Что касается запросов GET ... ну, как я уже сказал, используйте заголовок Authroziation. Лучше.
FullStackForger 05

2
Вы не обращаетесь к сути вопроса: защите конфиденциальных данных от подслушивания злоумышленником. Цель состоит не в том, чтобы найти альтернативный и / или более стандартизованный способ передачи учетных данных, а в том, чтобы защитить их по незащищенному каналу.
Lord of the Goo

3
Следует подчеркнуть, что это решение работает только в том случае, если вы уже шифруете соединение с помощью TLS / SSL. base64 - это не шифрование.
Scot

14

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

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

Редактировать:

Здесь есть проблема со свежестью 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, чтобы вы, ребята, могли отредактировать его и придумать что-нибудь хорошее.


+1 - вам нужно будет вычислить ответ на стороне клиента с помощью javascript (или Flash / Silverlight и т. Д.)
orip

10
Не останавливает человека посередине или нападок имитации. Например через вайфай. Похоже, это даст ложное чувство безопасности, ИМО.
Том Хотин - tackline

2
Это защищает от пассивных атак, но человек посередине все еще может атаковать.
Дуглас Лидер,

7
Также требуется, чтобы сервер знал исходный пароль.
Дуглас Лидер,

3
Не изобретайте криптовалюту заново! (в производстве)
bryanph

11

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ: обратите внимание, что это не предотвращает атаки MITM, если злоумышленник настраивает свою собственную страницу с другим открытым ключом и отправляет запросы прокси на сервер. Для защиты от этого открытый ключ должен быть закреплен в локальном хранилище браузера или в приложении для обнаружения подобных уловок.

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


В этом случае действительно ли защищен пароль? Не мог бы кто-нибудь унюхать, что было отправлено, и расшифровать его с помощью открытого ключа, а затем просто обновить метку времени, когда они будут использовать это позже? Я что-то упускаю?
michaellindahl

Асимметричное шифрование @michaellindahl означает, что только закрытый ключ, который никогда не покидает сервер, может использоваться для расшифровки вещей. Открытые ключи можно использовать только для шифрования.
Дэн Пантри,

2
Компьютер между браузером и сервером может изменить открытый ключ на странице входа.
Antti

Спасибо, что поделились своими методами, я нашел все очень интересное. Временная метка, добавляемая при отправке учетных данных, является хорошей уловкой! Один вопрос по поводу использования дополнительных файлов cookie сеанса, значение которых является случайной строкой: это как токен только для следующего запроса?
Виктор

4

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


4

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


1

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

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


0

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


2
Отметьте третье предложение, о котором идет речь. (Кроме того, всегда читайте другие ответы, чтобы убедиться, что вы не добавляете менее подробный дубликат.)
Натан Тагги,

0

Здесь лучше всего использовать https (сертификаты сейчас не так уж и дороги). Однако, если http является обязательным требованием, вы можете использовать некоторую шифровку - зашифровать ее на стороне сервера и расшифровать в браузере пользователя (отправьте ключ отдельно).

Мы использовали это при реализации safevia.net - шифрование выполняется на стороне клиентов (отправителя / получателя), поэтому данные пользователей не доступны ни на уровне сети, ни на уровне сервера.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.