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

в 13:24, , рубрики: информационная безопасность, Сетевые технологии, метки:

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

Данный пост будет только предложением в системе авторизации на основе сокетов и пока не может претендовать на реализацию. Хотя я уверен, что подобную вещь уже где-то воплотили, давно до меня, но поразмыслить сообществу над данной темой думаю будет интересно.

Итак, у нас есть ряд задач, которые нужно исполнить:

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

Данные и условия задачи

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

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

1. Механизм автоматической авторизации

Клиенту предоставляется форма авторизации, он вводит свои данные в нее и после нажатия кнопки «Авторизироваться» приложение вытягивает данные логина и пароля. Логин оставляем открытым — это не критическая информация. С паролем начинаем творить небольшие чудеса:

  1. Хэшируем пароль, чтоб вирус не смог увидеть чистый пользовательский пароль.
  2. Хэш пароля нужно зашифровать по ключу и сохранить в постоянное хранилище на клиенте. Это делается с целью возможности его повторного использования. Если оставить открытый хэш, то вирус, украв этот хэш, сможет провести авторизацию на сервере, не зная основного пароля. В качестве ключа лучше всего будет взять какую-то системную информацию с компьютера, к примеру mac-адрес сетевухи, производственные номера железа или что-то другое, что может являться постоянным ключом для расшифровки. Это не даст 100% безопасности в случае проникновения вируса, но усложнит работу взломщику.
  3. При автоматической авторизации зашифрованный хэш будет расшифровываться и солиться некоторыми данными.

Основные проблемы

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

2. Безопасная авторизация

Итак, у нас есть хэш пароля. Дальше нам нужно произвести подсол этого самого пароля. В связи с тем, что приложение у нас еще и сетевое, то в качестве соли мы будем использовать:

  • Хэш пароля
  • Внешний IP пользователя
  • Временная метка, для подсола пароля
  • Логин (не обязательно)

Внешний IP

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

var socket = require('net').createConnection(80, 'google.com'); // Но лучше направить на наш сервер, так будет надежнее
var outsideCleintIP = socket.address().address;

Одноразовый пароль с текущим временем

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

Мы убиваем сразу 2х зайцев: рассинхронизацию времени и перехват хэша.

Серверная расшифровка

Теперь немного о работе на сервере. Когда к нам приходит хэш, мы должны будем составить такой же идентичный хэш. У нас есть хэш самого пароля (хранится в БД). У нас есть временное окно для авторизации, у нас есть айпишник подключаемого пользователя. Мы можем без проблем составить такой же хэш и провести авторизацию.

Основные проблемы

У злоумышленника будет всего лишь 30 секунд на авторизацию по этому хэшу и из-за того, что мы подсолили наш хэш айпишником, он обязательно должен отправить этот хэш с того же внешнего IP адреса, что очень сильно усложняет ему работу, если он не находится в той же сети с жертвой. Если вор сидит в другом месте и не может выйти в инет с того же айпишника, то ему становится нереально авторизироваться в системе.

Тут у меня уже вопрос к знающим. Может ли злоумышленник перехватить управление потоком связи на себя, чтобы при этом сервер не заметил подмены клиента?

3. Механизм смены пароля

Хоть данное действие и происходит редко, но есть шанс, что новый пароль будет перехвачен именно через его смену. Я долго осматривал данный участок и не смог придумать ничего лучше, чем воспользоваться SSL/TSL соединением для защиты хэша нового пароля.

Можно попробовать сделать механизм смены пароля по СМС. Клиент будет присылать СМС-сообщение на какой-то указанный номер с новым паролем. Если система требует серьезной защиты, то данный механизм можно и использовать.

Основные проблемы

Если не использовать SSL/TSL то новый хэш злоумышленник может и умыкнуть, но воспользовавшись передачей пароля через другие источники связи.

4. Регистрация

Тут такая же проблема, как и со сменной пароля. Нужно как-то передать хэш на сервер, чтоб его не умыкнул злоумышленник.
Можно передать клиенту через СМС/Почту его пароль, который он сможет сменить, основываясь на безопасной смене пароля, или мы снова можем использовать SSL/TSL для защиты.

Основные проблемы

Мы опять уперлись в проблему передачи пароля на сервер, есть только 2 варианта спасения. Это либо шифрованный канал связи, либо альтернативный маршрут передачи пароля на сервер.

Реализация передачи пароля должна происходить в зависимости от сложности задачи. Как известно, если это сложно сломать и результат не будет стоить тех денег, его ломать не будут.

Насущные проблемы

Люди будут упоминать такие вещи как прокси, динамические IP и другие вещи. Сейчас мы разберем их.

1) Динамические IP
Как известно, если IP изменяется, то нарушается соединение с сервером. Оно просто сбрасывается. Нужно снова повторять процедуру авторизации. Вполне реально сделать повторное подключение не заметным для пользователя, реализовав на клиенте повторное подключение и повторно выяснить внешний IP. Так мы будем уверены в том, что клиент сможет без препятствий соединиться с сервером по новой.

2) Прокси
К счастью, прокси никак не смогут нарушить нормальную работу клиента. Если клиент будет пользоваться открытыми проксями, то он подвергает себя опасности перехвата авторизации и будет сам себе злым Буратино.

Хотелось бы, чтоб пользователи хабра добавили сюда еще свои вопросы или проблемы, которые могут возникнуть.

Только для

Данный алгоритм имеет право на жизнь только в системах, где авторизация с сервером происходит по сокетам/вебсокетам. Я еще не смог понять, как можно применить данный алгоритм авторизации к http запросам, потому что мы упираемся в ограничения самого протокола, мы не можем производить общение клиент->сервер->клиент->сервер. Последний узел уже не работает из-за спецификации протокола (хотя может я и не прав).

Продолжение статьи

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

Всем спасибо, жду конструктивной критики и замечаний.

Автор: Zerstoren

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js