О данной статье я задумался ещё год назад, когда преподаватели из моего института начали приставать ко мне с вопросами о "безопасной" передаче пароля, но руки дошли только сейчас.
Суть дилеммы состоит в непонимании работы сертификации серверов и защищённых сетей как со стороны преподавателей, так и с моей стороны. Ведь, создавая сайты, я по стандарту устанавливаю SSL-сертификаты к доменам, настраиваю их автопродление, переадресацию с HTTP на HTTPS и забываю о них. Моей основной задачей становится написание сервера с защитой от разного рода уязвимостей.
Согласно логике преподавателей, мой проект на клиентской части должен хэшировать пароль и передавать его на сервер, где он будет сравниваться с уже хранимым хэшем. Однако возникает очевидный вопрос: "А почему злоумышленник не может перехватить хэш и использовать его для аутентификации?" Преподаватели не смогли дать внятного ответа, утверждая, что так "безопаснее". На самом деле такая схема противоречит самой концепции безопасности: читабельный пароль просто заменяется на хэш, который становится уязвимым к атаке Pass-the-Hash. Я же настаивал на важности SSL-сертификатов и использования TLS-протоколов.
Как работает криптография в интернете?
Многие замечали, что браузеры иногда предупреждают о небезопасном подключении к сайтам с HTTPS.

Это означает, что сертификат либо является самоподписанным (что не гарантирует его безопасность), либо выдан центром сертификации, которому браузер не доверяет.
Что такое SSL-сертификат и зачем нужен HTTPS?
Буква "S" в "HTTPS" означает, что сайт использует SSL-сертификат. Сертификат содержит:
Приватный и публичный ключи;
Дату выдачи и срок действия;
Кому и кем он был выдан.

Публичный ключ необходим для установления защищённого соединения. В основе этой технологии лежит асимметричное шифрование, где используется пара ключей:
Публичный ключ (его можно показывать всем);
Приватный ключ (хранится в секрете).
Эти ключи математически связаны так, что данные, зашифрованные одним из них, могут быть расшифрованы только вторым.
Таким образом, клиент использует публичный ключ сервера для зашифровки данных, а сервер расшифровывает их приватным ключом. При этом злоумышленник, даже перехватив зашифрованные данные, не сможет их расшифровать без приватного ключа.
Алгоритм Диффи — Хеллмана: объяснение на примере красок
Далее в ход вступает алгоритм Диффи — Хеллмана. Он позволяет двум сторонам создать общий секретный ключ даже в присутствии наблюдателя.

Как это работает?
Клиент и сервер договариваются об общем "цвете" (публичном числе).
Каждая сторона добавляет свой секретный "цвет" (секретное число) и отправляет модифицированное значение.
В результате обе стороны получают общий "секретный цвет" (ключ), но злоумышленник, наблюдающий за процессом, не сможет его вычислить.
MITM-атака и защита от неё
Одним из главных рисков при передаче данных является атака "человек посередине" (MITM). В такой атаке злоумышленник подменяет публичный ключ сервера своим и перехватывает зашифрованные данные.
Как защищает TLS:
Использование сертификатов от доверенных центров сертификации (CA) предотвращает подмену ключей.
Протокол HSTS (HTTP Strict Transport Security) запрещает использование HTTP, принудительно активируя HTTPS.
Современные браузеры проверяют цифровую подпись сертификата и предупреждают пользователя о проблемах безопасности.
Проверяем безопасность соединения с помощью Wireshark
Чтобы убедиться, что данные передаются в зашифрованном виде, я использовал Wireshark.
Для фильтрации нужных пакетов: ip.host == 81.90.182.13, где 81.90.182.13 — это IP-адрес сервера моего проекта.

На скриншоте можно увидеть несколько строк с информацией о соединении:
"Client Hello" – инициация TLS-соединения;
"Server Hello" – подтверждение сервером и выбор алгоритма шифрования;
"Change Cipher Spec" – обмен сессионными ключами;
"Application Data" – зашифрованные GET- и POST-запросы.
GET данные:


Из данных скриншотов видно, что отправленные клиентом данные являются полностью зашифрованными. Для наглядности, можно так же посмотреть на незашифрованный пакет данных, который я отправлял, тестируя работу TCP протокола в C#.
Не зашифрованные данные:

Из данного скриншота можно спокойно прочесть передаваемый набор данных. В первом же случае, данные так же передавались на латинице, что не затруднило бы их прочтение, через данную программу.
Почему клиентское хэширование – плохая идея?
Хэширование паролей на клиенте не защищает от атак Pass-the-Hash, при которых злоумышленник перехватывает передаваемый хэш и использует его для входа. В отличие от пароля, сервер не отличает скомпрометированный хэш от оригинального.
Простой подход:
Пароль передаётся в зашифрованном виде через HTTPS.
Сервер хэширует его с солью (bcrypt, Argon2, PBKDF2).
Хранимые хэши невозможно использовать напрямую для аутентификации.
Ситуация: злоумышленник симулирует передачу данных
Если злоумышленник полностью симулирует передачу данных, подделав запросы, безопасность никак не гарантируется. В таких случаях необходимо использовать механизмы защиты, например, временные токены (nonce) или механизмы двухфакторной аутентификации.
Ситуация: злоумышленник получил ключ шифрования
Если злоумышленник смог получить ключ шифрования, он сможет расшифровать переданные данные. Чтобы защититься от этого, можно использовать соль.
Пример механизма защиты с солью:
Сервер отправляет пользователю случайную соль перед аутентификацией.
Пользователь хэширует свой пароль, как это делает сервер.
Затем он добавляет полученную соль к хэшу и снова хэширует.
Отправляет полученное значение на сервер.
Сервер выполняет ту же операцию со своим хранимым хэшем и сравнивает результаты.
Этот механизм защищает от утечек, так как перехваченные данные бесполезны без динамической соли.
Итог
Как видно, передача пароля через HTTPS действительно безопасна, так как данные шифруются и недоступны для перехвата.
В отличие от клиентского хэширования, которое не защищает от атаки "Pass-the-Hash", SSL/TLS обеспечивает: Конфиденциальность (перехваченные данные бесполезны без ключа); Целостность (защита от подмены данных); Аутентификацию (проверка подлинности сервера).
Если проект требует безопасной передачи пароля, не нужно хэшировать его на клиенте – используйте SSL/TLS, шифруйте данные и храните пароли с хэшированием уже на сервере.
Лично я в своем проекте, передаю открытый пароль по защищенным сетям, сравнивая его с хэшем на сервер, и обязательно инициализирую 2FA аутентификацию, которая предотвращает доступ злоумышленникам, даже если те получили исходный пароль.