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

Среди прочего рассмотрим авторизацию. До версии 15 алгоритм по умолчанию был md5. Он довольно прост: нужно сцепить пользователя и пароль, посчитать md5, приклеить соль, взять md5 еще раз, а затем привести к hex-строке:

message = hex(md5(md5(user+password) + salt))

Эта авторизация занимает одно сообщение сервера и одно клиента. Вычисления клиента при этом простые: два md5-хэша.

С версии 15 авторизация по умолчанию называется scram. Она происходит в несколько шагов, примерно так:

  • сервер говорит: начинаем авторизацию scram, доступны варианты sha-256 и sha-256-plus (о них позже);
  • клиент загадывает случайный массив байтов и отправляет серверу;
  • сервер возвращает особую крипту и число шагов (по умолчанию 4096);
  • клиент выполняет цикл из 4096 итераций, где на пароль накладывается XOR-ом байтовый массив и вычисляется отпечаток hmac sha265; эта крипта отправляется серверу;
  • сервер отправляет финальную сигнатуру. Клиент проверяет ее и если что не так, кидает исключение.

Вся эта котовасия нужна вот зачем:

  • клиент считает не пару md5-хэшей, а множество XOR- и hmac-операций. Это крайне осложняет брутфорс;
  • сделать реверс 4096 операций — задача нереальная в отличие от md5;
  • scram допускает защиту от человека посередине (разберем чуть позже).

Итого, чтобы авторизоваться, клиент вычисляет хэши в цикле. Это гораздо дольше обычного md5. Поэтому со scram новое соединение обходится еще дольше, чем раньше.

Что касается защиты от MITM, то scram предлагает интересное решение. Клиенту сообщают, какие подвиды авторизации доступны (sha-256 и sha-256-plus), и он может выбирать. Метод sha-256-plus называется связыванием каналов. Он работает так: если мы соединяется по SSL с TLS, то первоначальная крипта, которую загадывает клиент, берется из т.н. peer-сертификата. Это первый сертификат в цепочке TLS, и его особенность в том, что он общий для сервера и клиента. Все вычисления отталкиваются от него, и это гарантирует, что между клиентом и сервером нет посредника.

В самом деле: если такой посредник есть, у него открыты два соединения: с клиентом и сервером, и он перекладывает пакеты между ними. Однако peer-сертификаты у клиента и сервера будут разные. В результате вычисления не сойдутся, и авторизация не пройдет.

Так что scram, хоть и замедляет авторизацию, делает ее безопасней и учитывает много нетривиальных штук.

Посмотреть реализацию scram на Джаве можно тут.