
Уважаемые Хаброжители! Уважаемые эксперты! Представляю на вашу оценку новую концепцию идентификации пользователей на веб-сайтах, которая, как я надеюсь, с вашей помощью станет открытым интернет-стандартом, сделав этот интернет-мир чуточку лучше. Это вариант черновика протокола беспарольной идентификации, оформленный в виде вольной статьи. И если идея, положенная в его основу, получит от вас, уважаемый читатель, положительную оценку, я продолжу публикацию его на reddit.com и rfc-editor.org. И надеюсь, мне удастся заинтересовать в его реализации разработчиков ведущих браузеров. Потому ожидаю от вас конструктивную критику.
Внимание: очень много текста.
Итак, вопрос. Возможна ли однозначная идентификация посетителей сайта без раскрытия их персональных данных и отслеживания между разными сайтами? Можно ли, решая такую задачу, вообще отказаться от самой примитивной формы авторизации по логину/паролю и использования cookie/localStorage?
С одной стороны, сайтам необходимо узнавать клиента, чтобы, например, «восстановить» его настройки, корзину продуктов, объявления, статьи и т.п. С другой, посетителям хочется оставаться максимально анонимными, не раскрывая свои персональные данные, и не давая сторонним сайтам отследить их. А последние, могут это сделать, путём обмена между собой собранными данными.
Звучит как задача сделать так, чтобы и волки были сыты, да овцы целы. Реально ли это?
Я, думаю, что до определенной степени, – реально.
Оглавление
1 Концепция беспарольной идентификации
1.1 Ключи и токены вместо логинов и паролей
1.2 Структура токена
1.3 HTTP-заголовки протокола
1.4 Как происходит идентификация клиентов сайтами?
1.4.2 Как узнать, что сайт поддерживает этот протокол?
1.5 Как происходит авторизация клиентов сайтами?
1.6 А как реализовать надежную идентификацию клиентов?
1.7 Авторизация на сайте глазами пользователя
1.8 Как происходит смена ключа сайта?
1.9 Как реализуется кросс-доменная авторизация?
1.10 Как реализовать меж-доменную идентификацию?
1.11 Мобильность учетных записей
2 Техническое описание протокола
2.0 Алгоритм формирования ключа домена
2.1 Алгоритм вычисления исходного токена
2.2 Алгоритм защиты токена при передаче
2.3 Процедура обмена солью между браузером и сервером
2.4 Правила формирования поля Context
2.5 Правила определения полей Sender и Recipient
2.6 Подробнее о значениях таблиц определения Context
2.7 Сценарии работы протокола
2.8 Обработка токенов на сервере
2.9 Меж-доменная идентификация
3 Рекомендации по безопасности
3.1 Защита ключевой информации от НСД
3.2 О паролях в качестве ключей доменов
3.3 Риски потери/компрометации ключей и их минимизация
4 Атаки на схему авторизации
4.1 Трекинг пользователя
4.2 Атака вида XSS
4.3 Атака вида СSRF
4.4 Трекинг с использованием схемы SSO
4.5 Компрометация ключа для SSO
4.6 Компрометация токена при передаче
4.7 Взлом сайта и компрометация токенов
Заключение
А что не так с паролями?
Да всё не так. Их можно потерять. Их могут угнать. Их надо запоминать. Да и вообще, почему я обязан заполнять какую-то форму регистрации и придумывать очередной пароль, чтобы посмотреть погоду или скачать этот файл? Наконец, паролей чуть менее, чем много. Сколько вы любите сайтов, столько у вас и паролей. А потому, многие реально используют один пароль на все сайты. Кое кто использует хитрый алгоритм их запоминания. Или менеджер паролей. Или, тупо, – блокнот. Или предпочитает кросс-доменную авторизацию: авторизуешься однократно на одном сайте, и всё! Да не всё. Это, если сайт поддерживает её.
Все эти подходы имеют недостатки.
Использовать один пароль на разных сайтах – моветон. Что знают двое – знает и свинья. Не все сайты (даже крупные и авторитетные) честно выполняют правила безопасности по хранению ваших паролей. Некоторые сайты хранят пароли в отрытом виде, а другие думают, то хранение хэшей паролей уже достаточно их защищает. Как результат, утечки паролей и других персональных данных клиентов случаются регулярно.
С менеджером паролей уже лучше. Правда никто не гарантирует вам, что он не сливает ваши пароли куда-то. Да и поди найди менеджер, который может синхронизировать ваши учётки на всех устройствах (домашний нетбук, телефон, рабочий комп). Не исключаю, что такой существует.
Но в любом случае, сама идея: сначала зарегистрируйся на нашем сайте (при этом сообщи email, mobile, сдай кровь на анализы), потом сам придумай/запомни свой логин и пароль и будь добр их как-то помни, да храни в тайне – подход, я скажу вам, так себе. И его не решит ни один менеджер паролей. Зато решает
.
Вот только незадача: если потеряешь пароль от SSO-сайта и забудешь, или его у тебя угонят… Ты разом теряешь доступ от всех своих сайтов или добровольно отдаешь его непонятно кому и не понятно с какими намерениями. Не храните все яйца в одной корзине!
И ещё не факт, что SSO-сайт надёжен. Или не хранит ваши пароли в открытом виде. Или не сливает вообще их добровольно, плюс предоставляет возможность другим отслеживать вас между сайтами. Ну вы поняли.
Поэтому: логин + пароль = зло. А всё зло в мире должно быть выпилено всерьез и надолго. И cookie тоже. Вместе с его сессионными крокодилами PHPSESSIONID, JSESSIONID, и их аналогами.
И что же делать?
Для начала необходимо рассмотреть типовые ситуации, из которых будет ясно: для чего сайты хотят запомнить своих клиентов и так ли это им на самом деле необходимо?
- Персональный блог «Васи Пупкина», в котором, например, разрешены комментарии. Регистрация нужна лишь для того, чтобы защититься от ботов, проводить голосования без накруток, подсчитывать «лайки» и другие «мяу-мяу», назначать рейтинг комментаторам. Т.е. здесь функционал отслеживания нужен исключительно сайту, и лишь в малой степени – пользователю (если он дорожит своим рейтингом «комментатора» на этом сайте).
- Сайты соц.сетей и другие интернет-говорильни (аська, skype – туда же). Регистрация нужна для реализации именованного (авторского) контента, идентификации посетителей друг другом. Т.е. здесь функционал идентификации нужен в большей степени самим пользователям. Хотя сайты соц.сетей первые в списке «грешников», собирающих о посетителях максимально полную информацию и запоминающими вас в серьез и надолго. Так что ещё не известно, кому больше нужна идентификация.
- Корпоративный сайт с закрытым контентом. Регистрация или авторизация здесь нужны в основном для ограничения доступа к контенту. Всякие: онлайн школы, библиотеки, частные непубличные сайты, и прочее. Здесь функционал авторизации нужен в большей степени сайту. Открытых форм регистраций, как правило, нет. Учетные данные раздаются по другим каналам.
- Интернет-магазин и другая подобная площадка по продаже предметов, услуг или контента. Сюда же отнесу и сайты подачи платных/бесплатных объявлений. Регистрация, в основном, нужна, чтобы хранить историю заказов клиента, и чтобы он мог отслеживать их актуальный статус, хранить свои предпочтения (избранное); чтобы формировать клиенту персональные предложения на основе истории покупок и предпочтений. Здесь функционал идентификации нужен в равной степени как самому клиенту, так и магазину. Но больше, конечно же, магазину. Чтобы впаривать, впаривать и впаривать.
- Всякие личные кабинеты пользователей сервисов интернет-услуг: электронная почта, госуслуги, сбербанк-онлайн, мегафон-онлайн, кабинеты провайдеров, CMS от хостеров, и т.п. Здесь в правильной и надежной идентификации заинтересован в первую очередь сам пользователь. Ведь он управляет значимой для себя информацией, имеющей в некоторых ситуациях юридические и финансовые последствия. Тут анонимностью не пахнет. Она здесь вредна.
- Роутеры, консоли управления, web-версии управления чем-либо в домашней или корпоративной сети.
Понятно, что в разных ситуациях, могут быть разные риски. В одних случаях, неправильная идентификация, потеря аутентификационных данных или даже кража/подделка их, не приведет к каким-либо значимым последствиям как для сайта, так и для пользователя. В других, просто будет неприятно (потерял карму на Хабре – «беда-то какая...») или приведет к неудобству (не могу зайти под собой в Юлу, посмотреть свои объявления; профукал доступ к своим проектам на github, – ладно заведу новую учётку, форкну проекты). В третьих – может повлечь юридические и финансовые последствия. Поэтому, надо полагать, предлагаемая схема авторизации не «серебренная пуля» на все случаи, тем более «в голом виде». Там где проводится управление чувствительной информацией стоит использовать другие способы идентификации и аутентификации или их комбинации (двухфакторная авторизация, криптография на ассиметричных ключах, 3D-secure, eToken, OTP-Token и т.п.).
Ну хорошо. Какое ваше ТЗ?
Что предлагает новый протокол?
С точки зрения конечного пользователя:
- Сайт должен запоминать и узнавать посетителя без какого-либо ввода данных со стороны пользователя; сайт должен узнавать вас как в пределах сессии, так и между разными сессиями. Никаких cookie, паролей и регистраций. При этом разные сайты не должны получать возможность взаимно однозначно идентифицировать одного и того же посетителя, получая возможность отслеживать его активность на этих и других сайтах. Т.е. сайты не должны получить возможность агрегирования информации по своим посетителям.
- Пользователь должен получить возможность «забыть любой сайт» в любое время; и сайт забудет пользователя. Должна быть возможность предоставления прав сайту запомнить клиента по инициативе клиента (без навязчивых popup). Пользователь должен получить возможность безопасной миграции своей виртуальной личности между разными устройствами и браузерами (если ему это нужно), чтобы иметь единую авторизацию на любимых сайтах.
Понятно. А какие бонусы должны получить с этого разработчики сайтов?
- Более простая процедура идентификации: нет необходимости создавать в тысячный раз очередную форму логина, логаута, регистрации, изменения и восстановления пароля. Достаточно активировать модуль поддержки протокола под ваш любимый framework, реализованный на базе стандарта.
- Дизайнеру нет необходимости рисовать форму логина и думать, куда бы её спрятать на маленьком мобильном экране. Протокол делает формы ненужными вообще. Ну разве что форму регистрации. Куда же без них то. Увы.
Наконец:
- Протокол аутентификации должен быть единым и стандартизированным; проверенным экспертами по безопасности; одобрен и рекомендован комитетами по стандартизации веб-стандартов. Как результат, должна быть исключена возможность допуска классических ошибок веб-мастерами при разработке стандартных форм логина/логаута, смены/восстановления пароля (передача паролей в открытом виде, неправильное применение хеширования, хранение в базе паролей или «незасоленных» хешей, угон паролей пользователей при взломе сайта).
- Авторизация должна быть в определенной степени надежна (защищена от подделки, неправомерного доступа, с гарантированной аутентификацией); не создавать новых уязвимостей на веб-страницах и в браузерах; по возможности снизить риски известных сетевых атак «из коробки». Ну или по крайней мере, существенное уменьшение рисков успешного их проведения.
Отталкиваясь от указанных требований, перейдем к самому интересному: проектированию нового протокола.
1 Концепция беспарольной идентификации
1.1 Ключи и токены вместо логинов и паролей
Для каждого домена, включая дочерние, браузер клиента генерирует случайным образом уникальный 256-битный ключ
. Этот ключ никогда не передается. Остается постоянным в пределах сессии пользователя. При каждой новой сессии создается новый ключ.
На основе ключа
браузер по специальному алгоритму генерирует 256-битный* токен
для идентификации пользователя конкретным доменом. Идентификационный токен
пользователя (далее просто – токен) служит заменой сессионных cookie, подобных PHPSESSIONID и JSESSIONID.
Ключ
может быть «зафиксирован» пользователем. Фиксация ключа позволит пользователю оставаться авторизованным на сайте не ограниченно долго в разных сессиях браузера и возвращать ранее имевшуюся авторизацию. Это аналог функции «запомнить меня».
При отмене фиксации, браузер «забудет» этот ключ и снова начнет формировать случайный ключ для данного домена при каждой новой сессии (начиная с текущей), что является аналогом «выхода» пользователя из сайта. Выход мгновенный, не требующий перезагрузки страницы.
Пользователь может создать для домена постоянный ключ. Постоянный ключ, как и зафиксированный, позволит пользователю возвращать ранее имевшуюся авторизацию. Фактически этот ключ становится заменой связи «логин-пароль».
Пользователь получает возможность управлять моментами, когда браузер для домена будет использовать постоянный ключ, а когда – случайный. Это аналог функции «логин / логаут». Концепция представлена на скриншотах ниже.
Способы формирования постоянных ключей доменов обеспечивают мобильность учетных записей пользователя между разными устройствам. Протоколом определяются следующие:
- формирование ключа домена на базе мастер-ключа пользователя
- формирование индивидуально ключа домена на базе биологического датчика случайных чисел
- импортирование существующих ключей из ключевого файла с другого устройства
1.2 Структура токена
Токен представляет собой 256-битную структуру, представляемую в виде шестнадцатеричной строки:
| 84bc3da1b3e33a18e8d5e1bdd7a18d7a | 166d77ac1b46a1ec38aa35ab7e628ab5 |
| идентификационная часть | аутентификационная часть |
Идентификационная часть токена (старшие 128 бит) аналогична логину. По этой последовательности бит сервер может однозначно идентифицировать пользователя.
Аутентификационная часть токена (младшие 128 бит) аналогична паролю. Эта последовательность бит помогает серверу валидировать токен.
Правила валидации токена описаны ниже.
1.3 HTTP-заголовки протокола
Заголовки, используемые клиентом:
CSI-Token:
- при авторизации на постоянном ключе,
- при регистрации постоянного ключа,
- при изменении постоянного ключа.
1.4 Как происходит идентификация клиентов сайтами?

1.4.2 Как узнать, что сайт поддерживает этот протокол?



Формирование нового ключа не приводит к его автоматическому использованию.
1.5 Как происходит авторизация клиентов сайтами?
Разработчикам важно понимать: анкета не обязательно нужна большинству сайтов. Избегайте принуждения посетителей к обязательной регистрации. В большинстве типовых ситуаций вы можете осуществить бизнес-процесс без сбора ПДн посетителей.

1.6 А как реализовать надежную идентификацию клиентов?
1.7 Авторизация на сайте глазами пользователя

На иллюстрации
Вначале мы бродим по сайту, смотрим товары. Затем решаем сохранить в избранном понравившийся товар, чтобы в дальнейшем, может быть, купить его здесь. Чтобы сайт запоминал нас, мы фиксируем ключ. Добавляем товар в избранное. А затем закрываем вкладку. Через несколько дней, вернувшись на сайт, видим, что в избранном лежат наши товары. Сайт узнал нас. Делаем покупки.

На иллюстрации
Входит на сайт. Создает постоянный ключ. Активирует его. Сайт переводит пользователя на форму регистрации.
Пользователь заполняет поля формы регистрации, нажимает «Зарегистрировать меня». Сайт пускает пользователя в закрытый раздел.

На иллюстрации
Входит на сайт. Видит, что есть постоянный ключ. Активирует его, делая «Вход». Сайт узнает пользователя, подгружая профиль.

На иллюстрации
Входит на сайт с другого устройства. Создает постоянный ключ сайта на базе мастер-ключа. Активирует его. Сайт узнает пользователя (демонстрируется его профиль).

На иллюстрации
Входит на сайт. Активирует постоянный ключ. Сайт узнает пользователя и предлагает продолжить аутентификацию. Пользователь нажимает продолжить; вводит код из СМС. Сайт авторизует пользователя.


Вы можете управлять ключами в менеджере ключей: поменять постоянный ключ, экспортировать постоянный ключ в файл, импортировать из файла с другого устройства. Настроить «автовыход» после закрытия вкладки или браузера. Задать время действия фиксированного ключа.
1.8 Как происходит смена ключа сайта?

1.9 Как реализуется кросс-доменная авторизация?

На иллюстрации
Приведет пример данного алгоритма при регистрации на сайте www.youtube.com с использованием кросс-доменной авторизации через accounts.google.com.
Уязвимость: После такой авторизации, сайты S1, S2, S3, … (где вы авторизовались через Google) смогут узнавать вас (по назначенному вам идентификатору от Google), и, как следствие, отслеживать вашу деятельность.
Вариант защиты: не работать одновременно на сайтах, если вы регистрировались через SSO одного и того же поставщика. По возможности, делать логаут из сервера авторизации сразу же после завершения авторизации («автовыход» для домена).
1.10 Как реализовать меж-доменную идентификацию?
Перенос через физическое отчуждаемое устройство

Плюсы: можно использовать случайный 256-биные ключи; высокая безопасность за счёт использования двухфакторной аутентификации; высочайший уровень защиты от прямого НСД.Минусы: зависимость от устройств; требует финансовых затрат; низкая мобильность; необходимость резервирования карт и, как следствие, синхронизации данных между ними; уязвимость к клавиатурным шпионам сохраняется.
Синхронизация через онлайн-сервис
Плюсы:высокая мобильность учетных данных; независимость от устройства и браузера; нужен всего один единственный пароль (хотя от пароля не ушли, но уже лучше).Недостатки:менее безопасно, чем хранение ключей на отчуждаемом носителе. Фактически безопасность ключей основана на стойкости пароля к подбору.
2 Техническое описание протокола
2.0 Алгоритм формирования ключа домена
- на базе генератора случайных чисел (желательно биологического)
- на базе 256-битного мастер ключа
Компрометация или добровольное разглашение ключа домена не приводит к компрометации исходного мастер-ключа.
На заметку
В первоначальной версии протокола рассматривался вариант генерации ключей домена на базе пароля пользователя, как обеспечивающий мобильность пользователей, и защищающий от компрометации пароля при взломе сайта. Но в главе «3 Рекомендации по безопасности» будут даны пояснения, почему от такой схемы было принято решение отказаться.
2.1 Алгоритм вычисления исходного токена
- Sender – доменное имя инициатора запроса (им может быть страница с iframe или скрипт с чужого домена, выполняющий fetch),
- Recipient – доменное имя получателя (куда отправляется запрос),
- Context – контекст выполнения запроса,
- Protection – случайная последовательность 32-х байт (256-бит), если Context пуст; иначе пусто
Валидный токен получается, когда Context не пуст. Для правильной идентификации на целевом сайте необходимо, чтобы выполнялось условие Sender = Recipient = Context.
2.2 Алгоритм защиты токена при передаче
2.3 Процедура обмена солью между браузером и сервером
| Браузер | Сервер |
|---|---|
| Первичный запрос (инициализация сессии пользователя) | |
| Браузер отправляет токен как есть.В запросе отсутствует CSI-Salt. | Сервер впервые видит такой токен. между прочим Сервер может и не впервые видеть такой токен. А браузер его считать незарегистрированным. Это может произойти при пересоздании ключа на базе мастер-ключа на другом устройстве. Поэтому такая ситуация тоже должна учитываться. Воспринимает его как есть (считает его незащищенным). Использует этот токен как идентификатор сессии. Генерирует свою соль Ssalt. Возвращает её в ответе в заголовке CSI-Salt. |
| Второй запрос | |
| Генерирует соль Сsalt. Браузер соединяет[3] свою соль и соль сервера. Браузер отправляет запрос, передавая защищенный совместной солью токен.Посылает CSI-Salt. | Сервер получает запрос и извлекает CSI-Salt клиента. Сервер соединяет соль браузера со своей и использует для проверки токена. Если валидация токена успешна, предоставляет пользователю контент в соответствии с его правами. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. |
| Последующие запросы | |
| Браузер отправляет запрос, передавая защищенный совместной солью токен.В запросе отсутствует CSI-Salt. | Сервер получает запрос и проверяет его токен. Если валидация токена успешна, предоставляет пользователю контент в соответствии с его правами. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. |
| Через некоторое[2] время работы | |
| Генерирует новую соль Сsalt. Соединяет новую соль с солью сервера. Отправляет запрос, передавая защищенный новой совместной солью токен.Посылает CSI-Salt. | Сервер получает запрос и извлекает новую CSI-Salt клиента. Сервер соединяет соль браузера со своей и использует для проверки токена. Если валидация токена успешна, предоставляет пользователю контент в соответствии с его правами. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. |
| Браузер | Сервер |
|---|---|
| Первичный запрос (инициализация сессии пользователя) | |
| Генерирует соль Сsalt.Посылает CSI-Salt. Передает токен в защищенном виде. | Сервер получает запрос и извлекает CSI-Salt клиента. Читает защищенный токен. Находит полный токен клиента в своей базе (использует для поиска первые 128-бит полученного в запросе токена). Т.к. это первичный запрос, сервер не посылал соль клиенту, то валидация токена на данном этапе производится только солью клиента. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. Если валидация токена успешна, предоставляет пользователю контент в соответствии с его правами. Генерирует свою соль Ssalt. Возвращает её в ответе в заголовке CSI-Salt. |
| Последующие запросы | |
| Браузер соединяет свою соль и соль сервера. Браузер отправляет запрос, передавая защищенный совместной солью токен.В запросе отсутствует CSI-Salt. | Сервер получает запрос и проверяет его токен. Если валидация токена успешна, предоставляет пользователю контент в соответствии с его правами. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. |
| Через некоторое[2] время работы | |
| Генерирует новую соль Сsalt. Браузер соединяет новую соль с солью сервера. Браузер отправляет запрос, передавая защищенный новой совместной солью токен.Посылает CSI-Salt. | Сервер получает запрос и извлекает новую CSI-Salt клиента. Сервер соединяет соль браузера со своей и использует для проверки токена. Если валидация токена успешна, предоставляет пользователю контента в соответствии с его правами. При ошибках проверки возвращает клиенту заголовок CSI-Token-Action: invalid. Выдавать контент или возвращать пустой ответ: зависит от сервера. |
[2] Время, через которое делается изменение CSI-Salt определяется браузерами самостоятельно. Это может происходить после серии запросов, после таймаута, после определенного числа запроса. Единственное ограничение – использование одного и того же CSI-Salt в разных сессиях запрещено.
[3] Имеется в виду конкатенация 16-ричного представления 128-битных чисел. Первым всегда берется соль клиента, вторым соль сервера: Сsalt || Ssalt. Если у браузера нет соли сервера – он хэширует токен своей солью, передавая её в заголовке. Если у сервера нет соли клиента, то он должен полагать, что токен передается незащищенным.
2.4 Правила формирования поля Context
Дисклеймер о правилах
Правила формирования этого поля довольно запутаны. Вполне допускаю вариант, что где-то допустил ошибку. Такие правила нужны для защиты от возможных атак на предлагаемую схему авторизации.
Чтобы лучше разобраться в возможных сценариях атак, введем несколько определений. И прошу прощения за введение терминов, которые могут отличаться от официальных.