image

Уважаемые Хаброжители! Уважаемые эксперты! Представляю на вашу оценку новую концепцию идентификации пользователей на веб-сайтах, которая, как я надеюсь, с вашей помощью станет открытым интернет-стандартом, сделав этот интернет-мир чуточку лучше. Это вариант черновика протокола беспарольной идентификации, оформленный в виде вольной статьи. И если идея, положенная в его основу, получит от вас, уважаемый читатель, положительную оценку, я продолжу публикацию его на 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-сайта и забудешь, или его у тебя угонят… Ты разом теряешь доступ от всех своих сайтов или добровольно отдаешь его непонятно кому и не понятно с какими намерениями. Не храните все яйца в одной корзине!
И ещё не факт, что SSO-сайт надёжен. Или не хранит ваши пароли в открытом виде. Или не сливает вообще их добровольно, плюс предоставляет возможность другим отслеживать вас между сайтами. Ну вы поняли.
Поэтому: логин + пароль = зло. А всё зло в мире должно быть выпилено всерьез и надолго. И cookie тоже. Вместе с его сессионными крокодилами PHPSESSIONID, JSESSIONID, и их аналогами.

И что же делать?
Для начала необходимо рассмотреть типовые ситуации, из которых будет ясно: для чего сайты хотят запомнить своих клиентов и так ли это им на самом деле необходимо?
  1. Персональный блог «Васи Пупкина», в котором, например, разрешены комментарии. Регистрация нужна лишь для того, чтобы защититься от ботов, проводить голосования без накруток, подсчитывать «лайки» и другие «мяу-мяу», назначать рейтинг комментаторам. Т.е. здесь функционал отслеживания нужен исключительно сайту, и лишь в малой степени – пользователю (если он дорожит своим рейтингом «комментатора» на этом сайте).
  2. Сайты соц.сетей и другие интернет-говорильни (аська, skype – туда же). Регистрация нужна для реализации именованного (авторского) контента, идентификации посетителей друг другом. Т.е. здесь функционал идентификации нужен в большей степени самим пользователям. Хотя сайты соц.сетей первые в списке «грешников», собирающих о посетителях максимально полную информацию и запоминающими вас в серьез и надолго. Так что ещё не известно, кому больше нужна идентификация.
  3. Корпоративный сайт с закрытым контентом. Регистрация или авторизация здесь нужны в основном для ограничения доступа к контенту. Всякие: онлайн школы, библиотеки, частные непубличные сайты, и прочее. Здесь функционал авторизации нужен в большей степени сайту. Открытых форм регистраций, как правило, нет. Учетные данные раздаются по другим каналам.
  4. Интернет-магазин и другая подобная площадка по продаже предметов, услуг или контента. Сюда же отнесу и сайты подачи платных/бесплатных объявлений. Регистрация, в основном, нужна, чтобы хранить историю заказов клиента, и чтобы он мог отслеживать их актуальный статус, хранить свои предпочтения (избранное); чтобы формировать клиенту персональные предложения на основе истории покупок и предпочтений. Здесь функционал идентификации нужен в равной степени как самому клиенту, так и магазину. Но больше, конечно же, магазину. Чтобы впаривать, впаривать и впаривать.
  5. Всякие личные кабинеты пользователей сервисов интернет-услуг: электронная почта, госуслуги, сбербанк-онлайн, мегафон-онлайн, кабинеты провайдеров, CMS от хостеров, и т.п. Здесь в правильной и надежной идентификации заинтересован в первую очередь сам пользователь. Ведь он управляет значимой для себя информацией, имеющей в некоторых ситуациях юридические и финансовые последствия. Тут анонимностью не пахнет. Она здесь вредна.
  6. Роутеры, консоли управления, web-версии управления чем-либо в домашней или корпоративной сети.


Понятно, что в разных ситуациях, могут быть разные риски. В одних случаях, неправильная идентификация, потеря аутентификационных данных или даже кража/подделка их, не приведет к каким-либо значимым последствиям как для сайта, так и для пользователя. В других, просто будет неприятно (потерял карму на Хабре – «беда-то какая...») или приведет к неудобству (не могу зайти под собой в Юлу, посмотреть свои объявления; профукал доступ к своим проектам на github, – ладно заведу новую учётку, форкну проекты). В третьих – может повлечь юридические и финансовые последствия. Поэтому, надо полагать, предлагаемая схема авторизации не «серебренная пуля» на все случаи, тем более «в голом виде». Там где проводится управление чувствительной информацией стоит использовать другие способы идентификации и аутентификации или их комбинации (двухфакторная авторизация, криптография на ассиметричных ключах, 3D-secure, eToken, OTP-Token и т.п.).

Ну хорошо. Какое ваше ТЗ?

Что предлагает новый протокол?
С точки зрения конечного пользователя:
  1. Сайт должен запоминать и узнавать посетителя без какого-либо ввода данных со стороны пользователя; сайт должен узнавать вас как в пределах сессии, так и между разными сессиями. Никаких cookie, паролей и регистраций. При этом разные сайты не должны получать возможность взаимно однозначно идентифицировать одного и того же посетителя, получая возможность отслеживать его активность на этих и других сайтах. Т.е. сайты не должны получить возможность агрегирования информации по своим посетителям.
  2. Пользователь должен получить возможность «забыть любой сайт» в любое время; и сайт забудет пользователя. Должна быть возможность предоставления прав сайту запомнить клиента по инициативе клиента (без навязчивых popup). Пользователь должен получить возможность безопасной миграции своей виртуальной личности между разными устройствами и браузерами (если ему это нужно), чтобы иметь единую авторизацию на любимых сайтах.


Понятно. А какие бонусы должны получить с этого разработчики сайтов?
  1. Более простая процедура идентификации: нет необходимости создавать в тысячный раз очередную форму логина, логаута, регистрации, изменения и восстановления пароля. Достаточно активировать модуль поддержки протокола под ваш любимый framework, реализованный на базе стандарта.
  2. Дизайнеру нет необходимости рисовать форму логина и думать, куда бы её спрятать на маленьком мобильном экране. Протокол делает формы ненужными вообще. Ну разве что форму регистрации. Куда же без них то. Увы.


Наконец:
  1. Протокол аутентификации должен быть единым и стандартизированным; проверенным экспертами по безопасности; одобрен и рекомендован комитетами по стандартизации веб-стандартов. Как результат, должна быть исключена возможность допуска классических ошибок веб-мастерами при разработке стандартных форм логина/логаута, смены/восстановления пароля (передача паролей в открытом виде, неправильное применение хеширования, хранение в базе паролей или «незасоленных» хешей, угон паролей пользователей при взломе сайта).
  2. Авторизация должна быть в определенной степени надежна (защищена от подделки, неправомерного доступа, с гарантированной аутентификацией); не создавать новых уязвимостей на веб-страницах и в браузерах; по возможности снизить риски известных сетевых атак «из коробки». Ну или по крайней мере, существенное уменьшение рисков успешного их проведения.


Отталкиваясь от указанных требований, перейдем к самому интересному: проектированию нового протокола.


1 Концепция беспарольной идентификации



1.1 Ключи и токены вместо логинов и паролей


Для каждого домена, включая дочерние, браузер клиента генерирует случайным образом уникальный 256-битный ключ $K$. Этот ключ никогда не передается. Остается постоянным в пределах сессии пользователя. При каждой новой сессии создается новый ключ.
На основе ключа $K$ браузер по специальному алгоритму генерирует 256-битный* токен $T$ для идентификации пользователя конкретным доменом. Идентификационный токен $T$ пользователя (далее просто – токен) служит заменой сессионных cookie, подобных PHPSESSIONID и JSESSIONID.
Ключ $K$ может быть «зафиксирован» пользователем. Фиксация ключа позволит пользователю оставаться авторизованным на сайте не ограниченно долго в разных сессиях браузера и возвращать ранее имевшуюся авторизацию. Это аналог функции «запомнить меня».
При отмене фиксации, браузер «забудет» этот ключ и снова начнет формировать случайный ключ для данного домена при каждой новой сессии (начиная с текущей), что является аналогом «выхода» пользователя из сайта. Выход мгновенный, не требующий перезагрузки страницы.
Пользователь может создать для домена постоянный ключ. Постоянный ключ, как и зафиксированный, позволит пользователю возвращать ранее имевшуюся авторизацию. Фактически этот ключ становится заменой связи «логин-пароль».
Пользователь получает возможность управлять моментами, когда браузер для домена будет использовать постоянный ключ, а когда – случайный. Это аналог функции «логин / логаут». Концепция представлена на скриншотах ниже.
Способы формирования постоянных ключей доменов обеспечивают мобильность учетных записей пользователя между разными устройствам. Протоколом определяются следующие:
  • формирование ключа домена на базе мастер-ключа пользователя
  • формирование индивидуально ключа домена на базе биологического датчика случайных чисел
  • импортирование существующих ключей из ключевого файла с другого устройства


1.2 Структура токена


Токен представляет собой 256-битную структуру, представляемую в виде шестнадцатеричной строки:
84bc3da1b3e33a18e8d5e1bdd7a18d7a 166d77ac1b46a1ec38aa35ab7e628ab5
идентификационная часть аутентификационная часть

Идентификационная часть токена (старшие 128 бит) аналогична логину. По этой последовательности бит сервер может однозначно идентифицировать пользователя.
Аутентификационная часть токена (младшие 128 бит) аналогична паролю. Эта последовательность бит помогает серверу валидировать токен.
Правила валидации токена описаны ниже.

1.3 HTTP-заголовки протокола


Заголовки, используемые клиентом:

CSI-Token: <Token> используется для отправки токена серверу
CSI-Token: <Token1>; Changed-To <Token2> используется для изменения текущего токена:
  • при авторизации на постоянном ключе,
  • при регистрации постоянного ключа,
  • при изменении постоянного ключа.

CSI-Token: <Token> Permanent используется при фиксации текущего случайного ключа пользователем.
CSI-Token: <Token> Logout используется для досрочного завершения текущей сессии.

Заголовки, используемые сервером:
CSI-Support: yes указывает клиенту, что сервер поддерживает протокол авторизации CSI.
CSI-Token-Action: success используется для уведомления браузера о принятии нового токена пользователя (ключ Change-To).
CSI-Token-Action: abort отменяет процедуру смены токенов (откат к предыдущему токену).
CSI-Token-Action: registration сообщает браузеру, что новый токен пользователя всё ещё находится в процессе регистрации.
CSI-Token-Action: invalid ошибка верификации токена на стороне сервера.

Наконец,
CSI-Salt посылается и браузером, и сервером при обмене «солью», используемой для защиты токена (аутентификационной части). Подробнее смотрите ниже.

1.4 Как происходит идентификация клиентов сайтами?


Сайт может использовать токен для идентификации посетителя сайта. При этом схема генерации токенов и их 256-битная разрядность гарантирует уникальность токенов для каждой пары: пользователь-домен. Другой домен будет видеть уже другой токен пользователя. Даже если исполняется в контексте целевого сайта (через IFRAME, IMG, LINK, SCRIPT). Кроме того, специальный алгоритм генерации токенов защищает пользователей от атак XSS, СSRF и делает невозможным трекинг пользователя без его ведома. Но при этом оставляет возможным технологию SSO с его разрешения и меж-доменную идентификацию.
Токен передается в HTTP-заголовке CSI-Token при каждом запросе к любому ресурсу домена (страница, документ, изображение, скрипт, стиль, шрифт, файл, ajax-запрос, ...):

Токен вычисляется заново при каждом HTTP(S)-запросе: страница, картинка, ajax-запрос.
В целях оптимизации вычислений, допускается кэширование токенов браузером, но только на время действия сессии и только в случае неизменности условий выполнения запроса.
Как уже было отмечено выше, токен может служить заменой сессионных cookie, подобных PHPSESSIONID и JSESSIONID. С той лишь разницей, если раньше сайт генерировал посетителю идентификатор, чтобы отслеживать конкретного пользователя между его разными запросами (ведь на сайт одновременно приходят тысячи запросов от разных пользователей), то теперь эту функцию выполняет сам клиент.
Такая идентификация вполне достаточна для того, чтобы позволить совершать покупки в интернет-магазине, давать объявления на соответствующих площадках, писать на форумах, в социальных сетях, статьи на Википедии или Хабре.
Да, пользователь остается для сайта анонимным. Но это может быть «знакомый» сайту аноним. И сервер может сохранить токен такого пользователя на своей стороне, вместе с его данными (личный кабинет с покупками, предпочтениями, кармой, плюшками, лайками и другими бонусами). Но только сохранить при условии завершения какого-либо бизнес-процесса: покупки, подачи объявления, и т.п. Условия определяет сам сайт.
Как видно, протокол максимально прост для сайтов, которым нет необходимости регистрировать вас прежде, чем дать возможность совершить какие-либо действия. А вот тем, кому это необходимо, придется чуть сложнее. Но об этом ниже.

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


Сайт должен передавать http-заголовок CSI-Support: yes в секции Response Headers своего ответа:

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

Щелчок по ключу, например, позволит создать ключ для домена www.youtube.com:

Формирование нового ключа не приводит к его автоматическому использованию.

Постоянный ключ начинает использоваться только при его активации пользователем.

1.5 Как происходит авторизация клиентов сайтами?


Важно понимать, что токен ещё не делает пользователя авторизованным на конкретном сайте, – только узнаваемым. Но, как уже было ранее сказано, для него вы пока – просто узнаваемый «аноним».
Если сайту необходимо связать ваш токен с вами лично, регистрации на таком сайте, увы, не избежать. Но в предлагаемом протоколе это делается чуть проще.
Разработчикам важно понимать: анкета не обязательно нужна большинству сайтов. Избегайте принуждения посетителей к обязательной регистрации. В большинстве типовых ситуаций вы можете осуществить бизнес-процесс без сбора ПДн посетителей.

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

Вам, конечно же, придется предварительно создать постоянный ключ для сайта. Но это вопрос пары кликов мышкой.
И, наверняка, вас попросят подтвердить свой телефон или почтовый адрес. Но это уже зависит от сайта.
После успешной авторизации сервер, посредством специального HTTP-заголовка CSI-Token-Action сообщит браузеру, что он принял новый ключ. Более подробно в главе II.

1.6 А как реализовать надежную идентификацию клиентов?


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

1.7 Авторизация на сайте глазами пользователя


Браузер уведомляет пользователя, что сайт поддерживает авторизацию CSI, через иконку замка в адресной строке. Если вы совершаете на сайте некоторые действия, вы можете попросить сайт запомнить вас. С этого момента сервер будет узнавать пользователя даже между разными сессиями:

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

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

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

А когда пользователь имеет постоянный ключ для сайта и этот ключ там зарегистрирован, то процесс входа существенно упрощается:

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

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

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

Для сайтов с двух-факторной авторизацией «узнавание» может выглядеть так:

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

Выход осуществляется ещё проще. Нажимаете в браузере «Выйти» и всё:

Браузер посылает сайту запрос (на любую его страницу) с методом HEAD, в котором передает заголовок CSI-Token <>; Logout.

Сервер, видя такой заголовок, делает Logout. Если это был фиксированный ключ, то сайт удаляет всю информацию о пользователе (более такой ключ никогда не появится). Если это был постоянный ключ, просто разрывает сессию.
Любая дальнейшая активность сайта превращает пользователя в неизвестного сайту анонима: перезагрузка страницы, попытка сделать ajax-запрос, скачать файл и т.п. – браузер будет посылать токен, сформированный уже на базе случайного ключа.
Вы можете управлять ключами в менеджере ключей: поменять постоянный ключ, экспортировать постоянный ключ в файл, импортировать из файла с другого устройства. Настроить «автовыход» после закрытия вкладки или браузера. Задать время действия фиксированного ключа.


1.8 Как происходит смена ключа сайта?


Замена постоянного ключа сайта технически происходит также, как и переход со случайного ключа на постоянный. Более подробнее это описано в главе II.
В случае смены постоянного ключа сайта, браузер уведомляет сайт о соответствующем изменении токена, посылая в каждом последующем запросе заголовок CSI-Token с ключом Changed-To:

Сайт должен корректно обработать такой запрос. И, если данный токен пользователя сохранен в его базе, должен сделать соответствующую замену. При этом сайт должен ответить браузеру об успешном изменении токена на своей стороне. Делает он это в заголовке ответа (Response Headers) параметром: CSI-Token-Action: success, с указанием примененного токена.
Сайт имеет право отвергнуть попытку изменения токена (например, если такого токена в его базе не было или он их вообще их не сохраняет) параметром CSI-Token-Action: aborted.
До тех пор, пока браузер не получит заголовок CSI-Token-Action, он в каждый запрос к сайту в заголовок CSI-Token будет добавлять ключ Changed-To.
Это аналог «смены пароля» пользователя.

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


Классическая кросс-доменная авторизация по технологии SSO имеет для пользователя много плюсов. Вам нет необходимости помнить кучу паролей от кучи сайтов. Нет необходимости в регистрации и заполнении муторных форм. Некоторые сервера авторизации спрашивают какие права предоставить сайту, запросившему SSO.
Но есть и недостатки. Вы в зависимости от поставщика SSO. Если не работает сервер SSO, на целевой сайт вы не попадете. Если вы теряете пароль или у вас угоняют вашу учётку – вы разом теряете доступ от всех сайтов.
Для веб-разработчиков всё чуть сложнее. С начала необходимо зарегистрировать свой сайт на сервере авторизации, получить ключи, научиться работать с протоколом (SAML, OAuth и т.п.) и соответствующими библиотеками, следить, чтобы не истёк срок ключа, чтобы сервер авторизации не заблокировал ваш сайт по своим разумениям и т.п. Это плата за то, что вам нет необходимости хранить у себя учетные записи пользователей, делать формы регистрации, логина и т.п. Правда увеличивает стоимость сопровождения (в виде починки внезапных отказов). Опять же, если сервер внезапно недоступен сайту, то увы.
Данная схема авторизации делает SSO чуть более безопасной, а авторизацию для всех участников более простой. Про безопасность будет сказано ниже в разделе «Компрометация ключа для SSO».

Пусть вы заходите на сайт S, поддерживающем SSO от Google. Пусть у вас есть учётная запись на Google. Чтобы авторизоваться, вы нажимаете ссылку «Войти через Google», которая откроет вкладку авторизации Google. Браузер сообщит вам, что вы имеете ключ для Google. А Google сообщит, какие права запрашивает S.
Если вы согласны, нажмете «Войти» в менеджере ключей. Страница перезагрузится. Уже Google получит свой валидный токен, узнает и авторизует вас. И меж-серверным запросом сообщит сайту S информацию о вашей учетной записи в соответствии с запрошенными полями.
Перезагруженная страница будет содержать кнопку «Далее», возвращающая вас на целевой сайт.

На иллюстрации
Приведет пример данного алгоритма при регистрации на сайте www.youtube.com с использованием кросс-доменной авторизации через accounts.google.com.

Сайт S может принять решение сохранить данные о вас в своей БД или нет. Этот вопрос выходит за рамки предлагаемой схемы авторизации. Но далее, где мы будем рассматривать риски утраты ключа для SSO, сайту рекомендуется сохранять токен пользователя и идентификатор от SSO на своей стороне, а пользователю рекомендует создавать постоянный ключ для S.
Уязвимость: После такой авторизации, сайты S1, S2, S3, … (где вы авторизовались через Google) смогут узнавать вас (по назначенному вам идентификатору от Google), и, как следствие, отслеживать вашу деятельность.

Вариант защиты: не работать одновременно на сайтах, если вы регистрировались через SSO одного и того же поставщика. По возможности, делать логаут из сервера авторизации сразу же после завершения авторизации («автовыход» для домена).


1.10 Как реализовать меж-доменную идентификацию?


Всё это, конечно, хорошо. Пока работа осуществляется на одном браузере – всё отлично. А как быть с современными реалиями, когда у человека два мобильных телефона, один рабочий компьютер и несколько браузеров на нем, домашний компьютер, и ещё ноутбук? Плюс общий планшет жены/детей.
Придется как-то решать вопрос с переносом ключей доменов между браузерами, устройствами. А ещё решить вопрос их правильной синхронизации.
Одним из механизмов решения данной задачи является вычисление различных ключей доменов на базе общего мастер-ключа без возможности обратного восстановления мастер-ключа по известному ключу домена.
Создав при помощи мастер-ключа M персональный ключ K для домена D на одном устройстве, пользователь сможет создать тот же самый ключ K для домена D и на любом другом при помощи всё того же мастер-ключа M и единого алгоритма. Точнее это сделает не пользователь, а его браузер. При таком подходе пользователю достаточно распространить свой мастер ключ между всеми используемыми им браузерами и он разом «переносит все свои ключи» доменов. Заодно делает таким образом резервные копии.
Максимальное удобство для пользователя. Но и максимальный риск в случае компрометации мастер-ключа. Поэтому последний должен защищаться соответствующим образом. О рисках утраты или компрометации мастер-ключа, о способах минимизации таких рисков написано в главе «3 Рекомендации по безопасности».
Использование только одного мастер-ключа для генерации всех ключей для всех доменов не всегда удобный вариант. Во-первых, как быть, если вдруг ключ домена скомпрометирован и его необходимо поменять? Во-вторых, что если нужно поделиться ключом домена с другим человеком? Например, между членами семьи. Или это корпоративная учётная запись на доступ к общей почте. Как затем «забрать» свой ключ (ведь по факту он скомпрометирован)?
Поэтому генерация индивидуальных ключей доменов при помощи биологического датчика случайных чисел должна поддерживаться браузерами. Но тогда мы вновь возвращаемся к вопросу нашей мобильности и вопросам синхронизации, функций экспорта и импорта ключей в браузере, создания резервных копий.

Перенос через физическое отчуждаемое устройство


Смарт-карты и usb-токены могут вполне подойти в качестве защищенного хранилища ключевой информации (ибо для этого и создавались). Двухфакторная аутентификация защищает ключи от НСД при непосредственном доступе к устройству.
Правда для смарт-карт требуются специальные считыватели (не говоря уже про драйвера), что ограничивает их применение только рабочими станциями, оборудованными такими считывателям.
С USB-токенами чуть проще. Требуются только драйвера. Вот только такой токен в телефон не воткнешь. И хотя для мобильных телефонов существуют токены, выполненные в виде SD-карт, не сказать, что данное решение добавляет к мобильности. Попробуй вытяни карту из мобильника, да вставь в другой. И речь не о том, что это невозможно. Речь о том, что это не удобно.
А если токен поломается? Тогда все ваши ключи уйдут к «Великому Ктулху».
Так что появится соблазн при такой схеме использовать несколько устройств-дубликатов. Но тогда ещё необходимо решить вопрос с синхронизацией ключей, если у вас несколько смарт-карт.
Да и, честно говоря, не защищены такие устройства от клавиатурных шпионов. Вот если бы пин-код вводился бы с самой карты/токена. Тогда другое дело. Но я таких в природе не видел.

Плюсы: можно использовать случайный 256-биные ключи; высокая безопасность за счёт использования двухфакторной аутентификации; высочайший уровень защиты от прямого НСД.
Минусы: зависимость от устройств; требует финансовых затрат; низкая мобильность; необходимость резервирования карт и, как следствие, синхронизации данных между ними; уязвимость к клавиатурным шпионам сохраняется.

Синхронизация через онлайн-сервис


«Облачные технологии» сейчас пихаются куда только можно. Похоже они, вкупе с блокчейном, стали заменой «банано-технологиям». Естественно, возникает желание, использовать некую интернет-площадку для обмена ключевой информацией. Этакая смарт-карта «онлайн».
А что? Авторизуешься по нашей схеме анонимно на таком сайте; отправляешь туда свои ключи зашифрованные паролем; заходишь с другого устройства на этот же сайт с тем же ключом/паролем; получаешь от туда ключи; синхронизируешь изменения по дате правки. Аналогично менеджеру паролей, только это онлайн.
Вот только, никто не гарантирует, что онлайн-сервис не будет взломан или не станет сам сливать ваши, пусть и зашифрованные, ключи «куда надо». Кто будет за бесплатно реализовывать такой сервис. То-то и оно.
Хотя, конечно, пароль защищает ключи от прямого использования. Но устойчив ли ваш пароль к брут-форсу «офлайн»? Тот ещё вопрос.
Плюсы:высокая мобильность учетных данных; независимость от устройства и браузера; нужен всего один единственный пароль (хотя от пароля не ушли, но уже лучше).
Недостатки:менее безопасно, чем хранение ключей на отчуждаемом носителе. Фактически безопасность ключей основана на стойкости пароля к подбору.

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

2 Техническое описание протокола



2.0 Алгоритм формирования ключа домена


Настоящий протокол определяет только 2 способа формирования ключей домена

  • на базе генератора случайных чисел (желательно биологического)
  • на базе 256-битного мастер ключа

В последнем случае ключ домена вычисляется как:

$K=HMAC_{M_{key}} (Domain)$

где $M_{key}$ – 256-битный мастер-ключ, Domain – доменное имя, для которого делается ключ.
Здесь и далее HMACалгоритм криптографического вычисления хеша на основе 256-битной реализации хеш-функции SHA-2.
Компрометация или добровольное разглашение ключа домена не приводит к компрометации исходного мастер-ключа.

Мастер-ключ обеспечивает механизм мобильности учётных данных пользователей.
На заметку
В первоначальной версии протокола рассматривался вариант генерации ключей домена на базе пароля пользователя, как обеспечивающий мобильность пользователей, и защищающий от компрометации пароля при взломе сайта. Но в главе «3 Рекомендации по безопасности» будут даны пояснения, почему от такой схемы было принято решение отказаться.

Если ключ, созданный на базе «мастера», был скомпрометирован, либо был скомпрометирован токен, вычисленный от такого ключа (в результате взлома сайта), то ключ необходимо поменять. Поменять можно на случайный 256-битный ключ, либо сгенерировать от того же «мастера», с добавлением версии:

$K=HMAC_{Mkey} (Domain \cup Version )$

Здесь и далее символ $\cup$ будет использоваться для операции конкатенации строк (массивов байт).

2.1 Алгоритм вычисления исходного токена


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

  • Sender – доменное имя инициатора запроса (им может быть страница с iframe или скрипт с чужого домена, выполняющий fetch),
  • Recipient – доменное имя получателя (куда отправляется запрос),
  • Context – контекст выполнения запроса,
  • Protection – случайная последовательность 32-х байт (256-бит), если Context пуст; иначе пусто

Эти данные конкатенируются и подвергаются хэшированию 256-битной SHA-2 на ключе K домена-инициатора запроса:

$K=HMAC_M (Sender \cup Recipient \cup Context \cup Protection)$

Валидный токен получается, когда Context не пуст. Для правильной идентификации на целевом сайте необходимо, чтобы выполнялось условие Sender = Recipient = Context.

Поле Context вкупе с Protection используется для защиты от XSS и CSRF-атак, а также от трекинга пользователя.
Более подробные пояснения по правилам определения Sender / Recipient / Context будут даны ниже.

2.2 Алгоритм защиты токена при передаче


Исходный токен клиента передается крайне редко. Только при передаче незарегистрированного токена в момент создания сессии.
Токен считается незарегистрированным, если он: создан на базе случайного (не зафиксированного) ключа; не был принят сервером после отправки ключа Change-To или Permanent. Подробнее см. «Обработка токенов на сервере».
Браузер и сервер совместно вырабатывают пару случайных чисел, т.н. соль (Salt), при помощи которой хешируются младшие 128 бит токена. Оба обмениваются этими числами согласно протоколу. Подробнее см. «Процедура обмена солью между браузером и сервером».
Таким образом, сервер сайта видит следующий токен:

$T = Hi(T_s) \cup HMAC_{salt} ( Lo(T_s) )$

где $Hi(T_s)$ – старшие 128 бит, $Lo(T_s)$ – младшие 128 бит исходного токена, $\cup$ – конкатенация строк. При этом исходный токен $T_s$ должен быть уже известен серверу.

В идеале CSI-Salt должен меняться при каждом запросе браузера к серверу. Однако это может быть затратным требованием с точки зрения вычислительных ресурсов. Кроме того, это может «убить» возможность отправки параллельных запросов на сервер.
Поэтому допускается, в целях оптимизации расчетов, сохранение неизменным значения CSI-Salt в разных запросах, но не дольше одного сеанса. Это может быть ограничение по времени (смена CSI-Salt каждые 5 минут), либо реакция на интенсивность запросов (смена CSI-Salt через каждые 100 запросов), либо после каждой серии запросов (в момент паузы клиент-сервер), либо смешанный вариант. Здесь решение оставляется за разработчиками браузеров.
Слишком долгое удержание неизменным CSI-Salt ослабляет защиту передаваемого токена, позволяя злоумышленнику, при перехвате токена, воспользоваться им, пока легальный пользователь не выполнил Logout, и выполнить неавторизованный запрос от имени жертвы.

2.3 Процедура обмена солью между браузером и сервером


2.3.1 Токен на базе случайного или незарегистрированного[1] сервером ключа.
Браузер Сервер
Первичный запрос (инициализация сессии пользователя)
Браузер отправляет токен как есть.
В запросе отсутствует 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. Выдавать контент или возвращать пустой ответ: зависит от сервера.

2.3.2 Токен на базе зарегистрированного[1] сервером ключа.
Браузер Сервер
Первичный запрос (инициализация сессии пользователя)
Генерирует соль С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. Выдавать контент или возвращать пустой ответ: зависит от сервера.

[1] Токен считается незарегистрированным, если он: создан на базе случайного ключа; не был принят сервером после отправки ключа Change-To или Permanent ответом CSI-Token-Action: success.
[2] Время, через которое делается изменение CSI-Salt определяется браузерами самостоятельно. Это может происходить после серии запросов, после таймаута, после определенного числа запроса. Единственное ограничение – использование одного и того же CSI-Salt в разных сессиях запрещено.
[3] Имеется в виду конкатенация 16-ричного представления 128-битных чисел. Первым всегда берется соль клиента, вторым соль сервера: Сsalt || Ssalt. Если у браузера нет соли сервера – он хэширует токен своей солью, передавая её в заголовке. Если у сервера нет соли клиента, то он должен полагать, что токен передается незащищенным.


2.4 Правила формирования поля Context


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

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

Назовем ресурс внешним, если он был загружен с внешнего домена. Назовем ресурс внутренним, если он был загружен с нашего домена. Ресурсом может быть скрипт, изображение, ajax-запрос и любой другой файл.

Скрипт считается внешним, если он был загружен с внешнего домена. Скрипт, размещенный в созданном теге <script>, созданный внешним скриптом, тоже будет считаться внешним. Скрипт, располагаемый в измененном теге <script>, объявляется внешним, если изменялся внешним скриптом, или внешний скрипт присутствовал в цепочке вызовов при изменении его содержимого. Даже если при этом данный <script> изначально был на странице или был создан внутренним скриптом.

Назовем теги LINK, SCRIPT, IMG, IFAME и другие, которые требуют от браузера догрузить какой-либо ресурс, как только будут встречены парсером DOM – ресурсными тегами.

Назовем теги FORM, A, META и другие, которые могут инициировать загрузку страницы при определенных условиях (submit, click, timeout) – инициирующими тегами.

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

Тег FORM объявляется динамическим, даже если изменялся не только сам тег, но и значения всех полей INPUT, связанных с этой формой.

Назовем динамический тег собственным, если скрипт его создавший, принадлежит нашему домену, а в цепочке вызовов инструкции, породившей данный тег, не было функции, принадлежащих внешнему скрипту. В противном случае считаем такой динамический тег несобственным.

Загрузка страницы провоцируется инициирующими тегами. Инициирующий тег может быть приведен в действие непосредственно пользователем, либо активирован скриптом, через выполнение команды click (для ссылки), и submit (для формы) или через генерацию скриптом соответствующих событий onclick/onsubmit.

Также инициирующий тег может быть приведен в действие браузером. Пример такого тега – META с параметрами http-equiv=«refresh» content=«0».

Таблица P. Значения Context при разных условиях открытия страницы
Способ открытия Кто спровоцировал загрузку страницы?
Пользователь собств. JS внеш. JS браузер
тег1 Статический P1. Referrer P2. Variant3 P3. Empty P4. Inherit
Динамический Собственный P5. Inherit P6. Variant3 P7. Empty P8. Inherit
Несобственный P9. Empty PA. Empty PB. Empty PC. Empty
Непосредственно PD. Domain PE. Variant3 PF. Empty PG. Variant4

та же таблица, только изображением
изображение

Если ресурсный тег был изменен скриптом (например атрибут SRC у IMG), а затем браузером автоматически загрузился ресурс, то считаем, что загрузка контента/ресурса спровоцирована парсером, способ загрузки — тег, но статус этого тега становится «динамическим».

Таблица R. Значения Context при разных условиях загрузки контента/ресурса
Способ загрузки Кем вызвана загрузка контента?
DOM Parser собств. JS внеш. JS
тег2 Статический R1. Page
Динамический Собственный R4. Page
Несобственный R7. Empty
Непосредственно RA. Referrer RB. Page RC. Referrer

та же таблица, только изображением
изображение


[1] Инициирующий тег
[2] Ресурсный тег
[3] Inherit для своих же страниц, Empty при открытии страниц чужих доменов
[4] Inherit при редиректах сервером на свои страницы, Empty при редиректах на чужие домены или открытии страницы от внешних источников (см. разъяснения)


Пояснения к сокращениям
Referrer – значение совпадает с полем Referrer.
Page – домен вкладки (Tab) браузера от имени которой идет запрос.
Empty – пустая строка.
Domain – поле Context равно домену адресной строки
Inherit – значение Context наследуется от породившей страницы
Variant – значение Context зависит от атрибута «свой-чужой» у страницы

Пометки вида P1..PF, R1..RC будут использованы для отсылки к соответствующей ячейке таблицы при разборе конкретных ситуаций.
Обратите внимание на выделенные Referrer и Domain в первой таблице. Авторизованным на сайте вы сможете стать только, когда сами откроете сайт по прямому адресу, либо по ссылке с другого сайта, с последующей перезагрузкой страницы по вашей инициативе.


2.5 Правила определения полей Sender и Recipient


Sender – это домен страницы/скрипта/стиля, от которых идет запрос. Страница запрашивает стили, картинки, скрипты. Скрипты запрашивают контент через ajax. Стили могут подгружать другие стили. Это инициаторы запроса.

Recipient – это домен, на который реально уходит запрос.

Чтобы не осталось вопросов, рассмотрим на конкретных примерах.

Пусть есть сайт site.net. На главной странице сайта находится:
  • стиль site.net/css/common.css
  • в стилях common.css импортируется стиль fonts.google.com/fonts/Roboto.css
  • стиль Roboto.css импортирует шрифт fonts.google.com/fonts/Roboto.ttf
  • картинка, ведущая на img.site.net/picture1.jpg
  • фрейм, подгружаемый с adriver.ru/frame
  • скрипт с adm.site.net/admin.js

Пусть во фрейме (с adriver.ru) подключается:
  • стиль с adriver.ru/style.css
  • картинка с img.adriver.ru/img/01.png
  • скрипт с adriver.ru/libs.js
  • скрипт с api.adriver.ru/v1/ad.js

Значения Sender / Recipient при загрузке ресурсов парсером DOM
Загружаемый ресурс Значение Sender Значение Recipient
site.net/css/common.css site.net site.net
fonts.google.com/fonts/Roboto.css site.net fonts.google.com
fonts.google.com/fonts/Roboto.ttf fonts.google.com fonts.google.com
img.site.net/picture1.jpg site.net img.site.net
adriver.ru/frame site.net adriver.ru
adm.site.net/admin.js site.net adm.site.net
adriver.ru/style.css adriver.ru adriver.ru
img.adriver.ru/img/01.png adriver.ru img.adriver.ru
adriver.ru/libs.js adriver.ru adriver.ru
api.adriver.ru/v1/ad.js adriver.ru api.adriver.ru

Теперь рассмотрим значения Sender / Recipient при загрузке контента скриптами в процессе выполнения ajax-запросов.

Значения Sender / Recipient при загрузке контента скриптами
Выполняемый скрипт Куда идет запрос Sender Recipient
adm.site.net/admin.js site.net/api/ adm.site.net site.net
adriver.ru/libs.js adriver.ru/api/ adriver.ru adriver.ru
api.adriver.ru/v1/ad.js api.2gis.ru/… api.adriver.ru api.2gis.ru


2.6 Подробнее о значениях таблиц определения Context


Рассмотрим подробнее, какие варианты открытия страниц (вкладок в браузере) у нас имеются, и какое значение Context будет при этом получаться.

P1 – пользователь на предыдущей странице щелкнул ссылку или нажал кнопку submit на форме. Стандартный обработчик браузера событий для ссылки/формы перенаправил пользователя на эту страницу. Нормальная ситуация. Безопасный переход между страницами домена или разных доменов.

При переходе на site.net с другого домена google.com, Context будет равен предыдущему домену (google.com). И пользователь на новом домене site.net окажется неавторизованный (даже если открыта соседняя вкладка этого сайта, где пользователь авторизован).

Повторный самостоятельный переход пользователя (без содействия скриптов) по ссылке на этот же сайт приведет снова к ситуации P1, но Context будет уже равен домену site.net, т.к. по правилу Context = Referrer.

Это сделано для защиты от CSRF-атак.

P5 – пользователь на предыдущей странице нажал на ссылку, созданную/измененную скриптом, загруженным с домена предыдущей страницы; или пользователь на предыдущей странице нажал на кнопку submit формы, созданную/измененную скриптом (изменение тега FORM, включая её поля INPUT). Стандартный обработчик браузера событий для ссылки/формы перенаправил пользователя на эту страницу.

P9 – тоже, что и P5, только скрипт был внешним, или в цепочке вызовов присутствует функция из внешнего скрипта (защита от правки сторонним скриптом функций скрипта сайта).

PD – пользователь открыл страницу по прямому адресу. Безопасное открытие.
Пользователь должен открыть страницу путем ввода URL в адресной строке. Либо открыть сайт из закладок браузера.

Открытие ссылки с ярлыка рабочего стола, из другой программы, любая иная ситуация, когда ОС направляет браузеру команду открыть ссылку, должны рассматриваться, как случай PG (открытие ссылки по инициативе браузера). Даже если пользователь нажмет F5, чтобы перезагрузить страницу, это должно рассматриваться как случай PG. Только если пользователь встанет в адресную строку и нажмет Enter будет рассматриваться браузером как PD.

Это сделано для защиты CSRF-атак от других программ.

Переход по ссылке из другой программы приведет пользователя на атакуемый сайт с не валидным токеном и пустым Context, который будет сохраняться, даже если пользователь нажмет F5 (обновить страницу). Авторизоваться не получиться до тех пор, пользователь не откроет какую-нибудь ссылку на страницы сайта (ситуация P1).

Таким образом, если злоумышленник из другой программы решит подсунуть авторизованному пользователю ссылку на страницу сайта site.net, выполняющую какую либо команду, у него не выйдет это сделать так просто. Необходимо будет заставить пользователя нажать на этой странице ещё одну ссылку, потом заставить пользователя аутентифицироваться там, и только потом… Потом, уже пользователь будет, скорее всего, на другой странице сайта site.net.

P2 – на предыдущей странице для ссылки или формы, изначально размещенных на странице, собственный скрипт предыдущей страницы сгенерировал событие click/submit. В цепочке вызовов не было функций, принадлежащих внешнем скриптам. Браузер перенаправил пользователя на эту страницу.

Если новая страница принадлежит этому же домену, Context наследуется от предыдущей страницы. Если новая страница принадлежит чужому домену, Context будет пустым.

P6 – тоже самое, что P2, только ссылка/форма была создана/изменена собственным скриптом.

PA – тоже самое, что P2, только ссылка/форма была создана/изменена внешним скриптом.

PE – скрипт на предыдущей странице спровоцировал открытие этой страницы командой window.location.href или window.open(…).

Если страница site.net скриптом перенаправляет пользователя на страницу этого же домена, поле Context будет наследоваться от порождающей страницы. В этом случае Context = site.net.

Если была открыта страница ya.ru, а скрипт перевел нас на maps.ya.ru, то Context новой страницы будет уже пустым. При последующих действиях пользователя Context будет практически всегда оставаться пустым, что затруднит авторизацию пользователя на сайте.

Протокол подразумевает, что открытие одним сайтом другого – небезопасная операция. Это защищает пользователя от несанкционированного трекинга этими сайтами и от CSRF-атак.

P3 – аналогично P2, только событие click/submit было провоцировано внешним скриптом. Context становится пустым (вместо него посылается случайная последовательность байт), что защищает от трекинга пользователя сторонними сайта (баннерные сети).

P7 – аналогично P6, только ссылка/форма была создана/изменена внешним скриптом.

PB – аналогично PA, только ссылка/форма была создана/изменена внешним скриптом.

PF – аналогично PE, только провоцирующий скрипт был внешним.

P4 – страницу перезагрузил браузер в результате обработки тега <META>. Тег изначально был на странице. Легальный редирект. Context будет сохраняться от первоначальной страницы. Как в случае с PE.

P8 — страницу перезагрузил браузер в результате обработки тега <META>. Но тег был создан/изменен собственным скриптом. Это допустимо, но Context будет сохраняться от первоначальной страницы. Как в случае с PE. Выманить легальный токен пользователя таким образом не удастся.

PC – аналогично P8, только скрипт внешний. Открываемый сайт получит в качестве Context случайное число.

PG – открытие браузером ссылки по команде из ОС. Это может быть, переход вами по ссылке из другой программы, открытие ярлыка на рабочем столе. Это может быть команда, поступившая от другой программы, без вашего ведома. В этом случае источник является не доверенным, и поле Context будет оставаться пустым при любых манипуляциях пользователя.

Это сделано для защиты CSRF-атак от других программ.

Если браузер сам открывает сохраненные ранее вкладки, то Context страницы устанавливается равным значению этой страницы на момент закрытия браузера.

Кроме того, под эту категорию попадают все ситуации, когда браузер перенаправляется сервером на другую страницу (своего домена или чужого) в результате обработки HTTP-заголовка Header. Если перенаправление идет на свою же страницу, то значение Context наследуется. Если перенаправление идет на чужую – обнуляется.

Это сделано для защиты от трекинг-атак веб-серверов.

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

Чтобы пользователь «не потерял» исходную авторизацию на целевом сайте, необходимо передавать аутентификационную информацию меж-серверным запросом. Алгоритм может быть таким:

  1. пользователь создает и активирует постоянный ключ для целевого сайта;
  2. переходит с целевого сайта на SSO-сервер сам, нажимая соответствующую ссылку;
  3. активирует имеющийся постоянный ключ от SSO-сервера;
  4. SSO-сервер, получив ключ Changed-To, посылает меж-серверный запрос на целевой сайт;
  5. пользователь нажимает на странице авторизации кнопку-ссылку «Продолжить», которая возвращает его обратно на целевой сайт;
  6. чтобы выполнить правило P1, целевой сайт предлагает пользователю ещё раз нажать кнопку-ссылку, ведущую на него же (например, на стартовую страницу авторизованного участника).
  7. пользователь нажимает кнопку-ссылку, страница перезагружается, и пользователь на целевом сайте уже авторизован.

Описание алгоритма выглядит, на самом деле, сложнее, чем его реализация. А UI-имплементация может выглядеть так:

Повторный вход на целевой сайт уже не требует от пользователя SSO-авторизации. Достаточно только активировать постоянный ключ.


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

R1 – ресурс загружается браузером в результате разбора страницы (браузер встретил ресурсный тег). Значение Context при формировании запроса на получение ресурса берется из Context страницы содержащего ресурсный тег.

Например, если на сайте site.net есть фрейм adriver.ru, в котором грузится картинка с сайта img.disk.com, то при формировании HTTP-запроса к img.disk.com браузер в качестве Context возьмёт значение, которое было рассчитано для страницы site.net.

R4 – тоже, что и R1. Только ресурсный тег был создан/изменен собственным скриптом, в результате чего сработал DOM Parser браузера. Например, на странице site.net/index.html собственным скриптом site.net/require.js был вставлен другой собственный скрипт (тег <script src=…>) site.net/min.js, что вынудило браузер сформировать запрос на загрузку файла main.js. Поле Context в данном запросе будет установлено в значение, которое было рассчитано для страницы site.net.

R7 – тоже, что и R1. Но поскольку ресурсный тег был создан/изменен внешним скриптом, при запросе ресурса браузер сформирует токен на основе пустого Context и случайной 256-битной последовательности. Как результат внешний скрипт злоумышленника evil.com/drop.js, внедренный на страницу атакуемого домена site.net, пытающийся выполнить запрос на целевой сайт site.net от имени жертвы потерпит неудачу, т.к. сервер получит запрос со случайным токеном и не сможет идентифицировать отправителя запроса.

RA – загрузка контента осуществляется парсером в результате анализа другого контента. Например, файл стилей site.net/css/common.css, загружаемый для страницы site.net/index.html, импортирует файл стилей fonts.google.com/fonts/Roboto.css, что вынуждает браузер обратиться с запросом к fonts.google.com от имени Referrer = site.net/css/common.css. Значение Context будет в этом случае равно Referrer. Далее файл стилей Roboto.css импортирует шрифт Roboto.ttf, что вынуждает браузер обратиться с запросом к fonts.google.com/fonts/Roboto.ttf от имени Referrer = fonts.google.com/fonts/Roboto.css. Значение Context будет и в этом случае равно Referrer, но уже другое.

Предположим, гипотетически, что файл Roboto.css (внешний ресурс) импортирует не шрифт/стиль, а пытается провести CSRF-атаку такой инструкцией:
@import "https://site.net/api/payment?victim_params"
в надежде выполнить запрос на сайте site.net от имени авторизованного пользователя. Но проблема для злоумышленника в том, что site.net ожидает получить от пользователя токен:

$T_s^1 = HMAC_k(site.net \cup site.net \cup site.net)$


Тогда, как при таком CSRF-запросе, браузер создаст токен:

$T_s^2 = HMAC_k(fonts.google.com\cup site.net \cup fonts.google.com)$


И запрос на сайт придет уже от имени неизвестного сайту анонима, не имеющему прав доступа на совершение указанных операций.

RB – контент загружается собственным скриптом сайта. В этом случае для расчета токена запроса используется Context, равный странице, содержащей скрипт. Для скрипта site.net/1.js со страницы site.net Context будет равен Context самой страницы.
Обратите внимание, что Context самой страницы не всегда равен доменному имени страницы и зависит от того, как она была первоначально открыта.
Предположим, что сайт злоумышленника evil.com открывает страницу атакуемого сайта site.net, на которой скрипт site.net/util.js выполняет запрос с параметрами, переданными через URL страницы. Злоумышленник надеется, подсунув «свои параметры» через URL, заставить собственный скрипт site.net/util.js выполнить ajax-запрос на совершение важных действий от имени жертвы.

Предположим, что пользователь сам зашел на evil.com по прямой ссылке. Тогда Context для evil.com будет evil.com. Далее evil.com скриптом открывает site.net/api/payment?victim_params, надеясь провести атаку, но поле Context для site.net будет уже пустым (случай PE/PF). Скрипт site.net/utils.js, выполняя ajax-запрос, заставит браузер взять Context от страницы site.net. А оно у нас пустое. Но тогда site.net получит ajax-запрос с таким токеном:

$T = HMAC_{site.ru-key}(site.net \cup site.net \cup random)$


тогда как для авторизованного пользователя ожидается:

$T_s = HMAC_{site.ru-key}(site.net \cup site.net \cup site.net)$


site.net увидит неизвестный токен и не сможет идентифицировать пользователя. Защита сработала.
Кстати, говоря, из-за такой схемы провести кросс-доменную авторизацию через всплывающие окна будет нереально.
Для реализации SSO в рамках протокола, необходимо открывать новую вкладку для страницы сервера авторизации. И при этом пользователь должен сам открыть такую вкладку. Наилучший вариант – открытие пользователем соответствующей ссылки с целевого сайта.

RC – контент загружается внешним скриптом сайта. В этом случае для расчета токена запроса используется Context равный полю Referrer запроса.

Не смотря на то, что RA, RB и RC защищают от CSRF-атак, они тем не менее приводят к генерации постоянных токенов. А это позволяет реализовать кросс-доменную аутентификацию и меж-доменную идентификацию пользователя (когда нужно определить, что несколько запросов на разные сервера поступило именно вот от этого пользователя). Что может быть реализовано для предоставления ему равных полномочий на группе связанных доменов.

Если страница сайта открылась автоматически с другого сайта, вы там не сможете авторизоваться, даже если будете самостоятельно перезагружать этот сайт. Поскольку Source будет наследоваться от пустого значения. Браузер должен сигнализировать пользователю о данном факте (Source = Random):

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

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

Не поможет внешнему скрипту и трюк с созданием или изменением в DOM атакуемой страницы тега <script>. Поле Source будет оставаться пустым.

Но в тех же условиях внутренние скрипты приведут к запросам с Source, равному предыдущему его значению. И если исходная страница имела Source = Domain, всё будет хорошо. Пользователь останется авторизованным при таких запросах.

А вот со скриптами, загруженными со сторонних ресурсов (CDN), могут возникнуть, в некоторых случаях, проблемы. И это правильно, т.к. целостность кода CDN не гарантируется. Хотите не терять авторизацию пользователя – храните скрипты у себя и загружайте их со своего домена. Это что-то вроде аналога запрета использования ссылок http на https-страницах.

Опишем ситуацию, в которую может попасть разработчик. Ваш сценарий в результате действий пользователя выполняет перенаправление авторизованного пользователя на одну из страниц сайта (например, это делает форма), требующих, чтобы пользователь оставался авторизован. Ваш сценарий вызывает, например, $(form).submit() при помощи скрипта jQuery, загруженного с CDN. В этом случае браузер видит, что в стеке вызовов, инициировавших событие submit формы, присутствует функция из внешнего скрипта. Для предотвращения XSS/CSRF-атак браузер делает поле Source пустым, а к генерации токена добавляет случайные байты (случай P9). Как результат, пользователь на новой странице внезапно оказывается неавторизованным и не сможет выполнить операцию. Это может сбивать с толку разработчиков, привыкших использовать CDN.

2.7 Сценарии работы протокола


Приведем основные вероятные сценарии работы пользователя с сайтом, затрагивающие все возможные ситуации и этапы их выполнения (анонимный вход, «запомнить меня», «забыть меня», перейти на использование постоянного ключа, авторизация и выход, регистрация и двух-факторная аутентификация, экспорт/импорт ключа, замена ключа и т.п.)
1 Форум, Блог, Википедия
Пользователь Браузер Сервер сайта
1.1 Впервые входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя.
1.2 Просматривает страницы. Посылает защищенный токен от случайного ключа. Выдает публичный контент. Проверяет младшие 128-бит бит токена.
1.3 Пытается делать действия (добавление комментариев и т.п.) Посылает защищенный токен от случайного ключа. Говорит пользователю, что необходимо представиться системе. На данном этапе сайт уверен, что ключ – случайный.
1.4 Говорит браузеру, чтобы сайт запомнил его. Фиксирует текущий ключ. Посылает ключ Permanent. Токен как и ранее передается в защищенном виде. Посылает этот ключ до тех пор,  пока не получит от сервера success. Теперь сайт знает, что ключ фиксированный. Посылает CSI-Token-Action: success. Может применить технику запоминания пользователя на длительное время: либо сохраняет токен в базе, для будущего восстановления сессии с пользователем. Либо удерживает сессию в течении более длительного времени (сохраняем в файл).
1.5 Выполняет действия (добавление постов, голосования и т.п.) Посылает защищенный CSI-Token от фиксированного ключа. Фиксирует действия от этого пользователя.
1.6 Закрывает вкладку браузера. Ничего. Находится в ожидании поступления следующих запросов пользователя.
1.7 Снова заходит на сайт. Посылает защищенный фиксированный ключ. Продолжает работать с пользователем. Данные сессии берутся из БД или временного файла по токену.
1.8 Отменяет фиксацию ключа (забыть меня на этом сайте) Посылает ключ Logout Удаляет данные пользователя в БД, т.к. это был фиксированный ключ, и пользователь больше никогда его не сможет восстановить. Завершает сессию. Браузер больше никогда не пошлет такой токен.
1.9 При первом обращении к сайту после Logout. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Для сайта это уже новый пользователь. Считаем пользователя анонимом. Используем токен в качестве идентификатора сессии пользователя.
1.10 Просматривает страницы. Посылает защищенный токен от случайного ключа. Выдает публичный контент. Проверяет младшие 128-бит бит токена.
1.11 Закрывает вкладку браузера. Ничего. Разрывает сессию после таймаута.
1.12 Снова заходит на сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя.
1.13 Создает постоянный ключ сайта. Ничего.
1.14 Активация постоянного ключа. Спрашивает пользователя: вы действительно хотите, чтобы сайт запомнил ваш ключ? Убедитесь, что этот сайт является тем, за кого себя выдает.
Посылает Change-To. Только в это момент браузер передает токен незащищенным. Во все следующие разы браузер будет всегда при логине передавать защищенный токен. Но для этого сайт должен подтвердить смену токенов через CSI-Token-Action: success.
Запоминает в БД новый токен пользователя. Меняет ID сессии. Продолжает ожидать запросы от нового токена. Отправляет CSI-Token-Action: success.
1.15 Выполняет действия (добавление постов, голосования и т.п.) Посылает защищенный Token от постоянного ключа Фиксирует действия от этого пользователя. Проверяет младшие 128-бит токена.
1.16 Делает «Выход». Посылает ключ Logout Разрывает сессию
1.17 Снова заходит на сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем токен в качестве идентификатора сессии пользователя.
1.18 Активация постоянного ключа. Посылает Change-To. Токен уже защищенный, т.к. в прошлый раз сайт ответил нам CSI-Token-Action: success. Подгружаем сохраненный данные пользователя из базы. Меняет ID сессии. Работаем с сохраненным токеном. Мы знаем, что токен на базе постоянного ключа.
1.19 Закрывает вкладку браузера. Ничего. Либо ключ Logout, если настроен «автовыход» при закрытии вкладки. Разрывает сессию после таймаута, либо при получении ключа Logout.
2 Интернет-магазин или сайт объявлений
Пользователь Браузер Сервер сайта
2.1 Впервые входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя.
2.2 Просматривает страницы. Посылает защищенный токен от случайного ключа. Выдает публичный контент. Проверяет младшие 128-бит бит токена.
2.3 Пытается делать действия (добавление объявлений, покупки и т.п.) Посылает защищенный токен от случайного ключа. Говорит пользователю, что необходимо представиться системе. На данном этапе сайт уверен, что ключ – случайный.
2.4 Говорит браузеру, чтобы сайт запомнил его. Фиксирует текущий ключ. Пре первом же запросе посылает защищенный CSI-Token с ключом Permanent. После получения success, перестает посылать этот ключ. Теперь сайт знает, что ключ фиксированный. Может применить технику запоминания пользователя на длительное время: либо сохраняет токен в базе, для будущего восстановления сессии с пользователем. Либо удерживает сессию в течении более длительного времени (несколько суток).
2.5 Выполняет действия (добавление объявлений, покупки и т.п.) Посылает защищенный CSI-Token от фиксированного ключа. Фиксирует действия от этого пользователя. Проверяет токен.
2.6 Закрывает вкладку браузера. Ничего. Удерживает сессию. При длительной неактивности сохраняет данные сессии из оперативной памяти в файл или базу.
2.7 Снова заходит на сайт. Посылает защищенный фиксированный ключ. Сессия продолжается. Работаем с пользователем, как ни в чём не бывало.
2.8 Создает или импортирует постоянный ключ сайта. Ничего.
2.9 Активация постоянного ключа. Здесь фактически происходит переход от использования фиксированного ключа к постоянному. Посылает ключ Change-To. Токен передается незащищенным для вновь созданного ключа и незарегистрированного на сервере токена. Токен передается защищенным для импортированного ключа. 2.9.А. Токен на базе нового ключа.
Если старый токен был сохранен в БД – просто меняем токен в БД.

2.9.В. Токен на базе импортируемого ключа.
Если старый токен был сохранен в БД – удаляем его. Выполняя слияние двух профилей одного пользователя (об о чём можно спросить у него самого) – т.к. по факту у пользователя сохранено в БД два токена: от фиксированного ключа и от импортированного. Меняет ID сессии. Отправляет CSI-Token-Action: success. Продолжает ожидать запросы уже от нового токена.
2.10 Выполняет действия (покупки, размещения объявлений, корзина, избранное, отзывы, сравнения) Посылает защищенный Token от постоянного ключа Фиксирует действия от этого пользователя. Проверяет младшие 128-бит токена.
2.11 Закрывает вкладку браузера. Ничего. Либо ключ Logout, если настроен «автовыход» при закрытии вкладки. Разрывает сессию после таймаута, либо при получении ключа Logout.
3 Сайты с обязательной предварительной регистрацией (соц. сети)
Пользователь Браузер Сервер сайта
3.1 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Пускаем только в публичные разделы. При попытке доступа к закрытому контенту переводим на форму авторизации.
3.2 Создает постоянный ключ сайта Ничего
3.3 Активация постоянного ключа. Спрашивает пользователя: вы действительно хотите, чтобы сайт запомнил ваш ключ? Убедитесь, что этот сайт является тем, за кого себя выдает.

Посылает Change-To.
Токен передается в открытом виде.
Запоминаем новый токен. Не спешим сохранять в БД, пока регистрация ещё не пройдена. Держим пользователя на форме «Регистрация», пока не будет проведено подтверждение обладания (телефоном, почтой). Отправляет CSI-Token-Action: registration
3.4 Вводит свои контактные данные. Отправляет ajax-запросы. Посылает Change-To. Старый токен на том же случайном ключе.
Новый токен уже передается в защищенном виде.

Как только получает success, переходит к использованию нового токена (постоянного ключа).
Проверяет контактные данные. Если всё успешно, отправляет CSI-Token-Action: success. Иначе: CSI-Token-Action: registration. Если отправляется CSI-Token-Action: abort, то регистрация не успешна. Браузер должен вернуться к использованию случайного числа (отмена входа). И сообщить об этом пользователю.
3.5 Переходит к закрытому разделу сайта Посылает защищенный Token от постоянного ключа. Предоставляет доступ, проверяя младшие 128-бит токена.
3.6 Выполняет действия (покупки, размещения объявлений, корзина, избранное, отзывы, сравнения) Посылает защищенный Token от постоянного ключа. Фиксирует действия от этого пользователя. Проверяет младшие 128-бит токена.
3.7 Закрывает вкладку браузера. Ничего. Либо ключ Logout, если настроен «автовыход» при закрытии вкладки. Разрывает сессию после таймаута, либо при получении ключа Logout.
3.8 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Пускаем только в публичные разделы. При попытке доступа к закрытому контенту сообщаем пользователю, что он аноним.
3.9 Активация постоянного ключа. Посылает Change-To. Оба токена передаются защищенным образом. Подгружаем данные пользователя из БД по токену (старшие 128-бит). Теперь сайт знает, кто этот пользователь.
3.10 Меняет постоянный ключ домена (на другой постоянный) Спрашивает пользователя: вы действительно хотите, чтобы сайт запомнил ваш новый ключ? Убедитесь, что этот сайт является тем, за кого себя выдает.

Посылает Change-To.
Новый токен передается в открытом виде; старый – в защищенном
Меняет в БД токен на новый. Подгружает данные профиля. Использует новый токен со следующих запросов. Отправляет CSI-Token-Action: success
3.11 Выполняет действия (добавление постов, голосования и т.п.) Посылает защищенный Token от нового ключа Фиксирует действия от этого пользователя. Проверяет младшие 128-бит токена.
3.12 Делает «Выход». Посылает ключ Logout Разрывает сессию
3.13 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Переводим на форму авторизации.
3.14 Активация постоянного ключа Посылает Change-To. Оба токена передаются защищенным образом. Подгружаем данные пользователя из БД по токену (старшие 128-бит).
3.15 Импортирует другой ключ для этого домена.
Важно: импортируемый ключ должен быть зарегистрирован на сервере.
Посылает ключ Logout Переходит на использование случайного ключа. Разрывает сессию
3.16 Активирует новый ключ Посылает Change-To.
Оба токена передаются в защищенном виде.

Обратите внимание, что в качестве «предыдущего» используется уже случайный ключ (см. 3.15).
Этот ключ должен быть известен БД. Экспорт ключа из браузера разрешается только для зарегистрированных токенов. Таким образом браузер уверен, что импортируемый ключ известен серверу и передает его защищенным. В противном случае – сервер не сможет опознать токен пользователя и не сможет его авторизовать.
3.17 Выполняет действия (добавление постов, голосования и т.п.) Посылает защищенный Token от нового ключа Фиксирует действия от этого пользователя. Проверяет младшие 128-бит токена.
3.18 Выходит Посылает ключ Logout Разрывает сессию
4 Сайты с двух-факторной авторизацией (Сбербанк Онлайн)
Пользователь Браузер Сервер сайта
4.1 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Переводим на форму авторизации.
4.2 Создает постоянный ключ сайта Ничего
4.3 Активация постоянного ключа. Спрашивает пользователя: вы действительно хотите, чтобы сайт запомнил ваш ключ? Убедитесь, что этот сайт является тем, за кого себя выдает.

Посылает Change-To.
Токен передается в открытом виде.
Токен сайту не известен. Запоминает новый токен. Переводит на форму регистрации пользователя. Посылает CSI-Token-Action: registration.
4.4 Вводит в форму свой телефон. Нажимает «продолжить» Посылает Change-To в каждом запросе до получения success. Старый токен на том же случайном ключе.
Новый токен уже передается в защищенном виде.
Валидирует телефон пользователя. Посылает СМС с кодом.
4.5 Вводит в поле код из СМС. Делает ajax-запрос. В нем все тот же Change-To.

Как только получает success, переходит к использованию нового токена (постоянного ключа).
Проверяет СМС код. Сохраняет новый токен в базе (проверяя его). Посылает CSI-Token-Action: success
Переводит пользователя на главную страницу личного кабинета.
Если СМС код неверен, посылает CSI-Token-Action: registration.

При ошибке валидации токена посылает CSI-Token-Action: abort. Браузер может сменить соль, но предложить пользователю повторить последнюю операцию.
4.6 Работает с личным кабинетом. Посылает защищенный Token от постоянного ключа Предоставляет пользователю доступ в соответствии с его полномочиями.
4.7 Делает «Выход» с сайта Посылает ключ Logout Завершает сессию
4.8 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считаем пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Переводим на форму авторизации или стартовую страницу с кнопкой «Войти».
4.9 Активация постоянного ключа. Посылает Change-To.
Токен передается в защищенном виде (т.к. известен уже сайту; мы проходили регистрацию ранее).
Подгружаем данные пользователя из БД по токену (старшие 128-бит). Опознаем пользователя, посылаем СМС с кодом подтверждения на его телефон. На этом этапе мы уже знаем, что за пользователь. Требуем подтвердить свою личность. Отвечаем браузеру CSI-Token-Action: success
4.10 Вводит в поле код из СМС. Делает ajax-запрос. В заголовке запроса  передается защищенный токен на постоянном ключе. Валидирует токен. Проверяет код. Авторизует пользователя. Переводит пользователя на главную страницу личного кабинета.
4.11 Работает с личным кабинетом. Посылает защищенный Token от постоянного ключа. Предоставляет пользователю доступ в соответствии с его полномочиями.
4.12а Делает «Выход» с сайта Посылает ключ Logout Завершает сессию
4.12б Или просто закрывает вкладку (небезопасно). Браузер посылает ключ Logout, если настроен «автовыход» при закрытии вкладки. Либо ничего. Завершает сессию, если пришел запрос с Logout. Либо по таймауту.
5 Корпоративный сегмент: консоль управления ESXi
Пользователь Браузер Сервер сайта
5.1 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считает пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Рисует стартовую страницу.
5.2 Создает постоянный ключ сайта.
5.3 Экспортирует ключ в файл (как есть, без защиты паролем). Браузер помечает, что это экспортированный ключ.
5.4 Подключается по иным протоколам (SSH, RDP). Записывает ключ в конфигурацию системы (например секция .htaccess – см. пример ниже)
5.5 Закрывает вкладку Ничего Разрывает сессию по таймауту
5.6 Входит на данный сайт. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считает пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя. Рисует стартовую страницу.
5.7 Активация постоянного ключа. Посылает Change-To.
Токен передается в защищенном виде (т.к. браузер уверен, что мы сообщили сайту наш ключ по другому каналу; мы ведь пометили ключ экспортируемым).
Рассчитывает возможные значения токенов для своих страниц (см. далее).

Определяет пользователя по токену (старшие 128-бит). 
Проверяем защищенные младшие 128-бит. Создаем сессию на этом токене.
Отвечаем браузеру CSI-Token-Action: success.
Либо отвечаем CSI-Token-Action: abort (если ключа нет в конфиге), а заодно 403 – Forbidden.
Перенаправляем на стартовую страницу консоли.
5.8 Работаем в консоли Посылаем защищенный токен на постоянном ключе. Предоставляет пользователю доступ в соответствии с его полномочиями.
5.9 Закрывает вкладку Браузер посылает ключ Logout, если настроен «автовыход» при закрытии вкладки. Либо ничего. Завершает сессию, если пришел запрос с Logout. Либо по таймауту.
6 Домашний сегмент: управление роутером
Пользователь Браузер Сервер сайта
6.1 Входит на страницу устройства. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считает пользователя анонимом. Используем этот токен в качестве идентификатора сессии пользователя.Выдает обычную страницу логина.Посылает браузеру CSI-Support: yes;
6.2 Создает постоянный ключ.
6.3 Активация постоянного ключа. Спрашивает пользователя: вы действительно хотите, чтобы сайт запомнил ваш ключ? Убедитесь, что этот сайт является тем, за кого себя выдает.

Посылает Change-To.
Токен передается в открытом виде.
Запоминает токен, но возвращает CSI-Token-Action: registration, т.к. пользователь не аутентифицирован.
6.4 Вводит логин/пароль администратора «по умолчанию» Передает логин/пароль POST-запросом с формы. В запросе все тот же Change-To, но только уже защищенный. Проверяет логин/пароль. Сохраняет токен у себя. Применяет права к пользователю. Возвращает CSI-Token-Action: success
6.5  Деактивирует стандартного пользователя администратора в консоли управления устройства в разделе «Безопасность» Серия запросов с защищенным Token от постоянного ключа Запрещает вход под логином/паролем. Сохраняет конфигурацию.
6.6 Выходит Посылает ключ Logout Разрывает сессию
6.7 Входит на страницу устройства. Генерирует случайный ключ. Посылает  незащищенный токен от случайного ключа. Считает пользователя анонимом. Выводит сообщение «Доступ запрещен»
6.8 Активация постоянного ключа. Посылает Change-To.Токен передается в защищенном виде (т.к. уже известен устройству; мы проходили регистрацию ранее). Идентифицирует пользователя по старшим 128-битам токена. Проверяет младшие биты.
6.9 Выполняет привилегированные действия Посылает защищенный Token от постоянного ключа Выполняет действия в соответствии с полномочиями пользователя.
6.10 Выходит Посылает ключ Logout Разрывает сессию

Пример конфигурации доступа по токенам на базе файла .htaccess.
<Directory "/var/www/html">
        AuthType CSI
        AuthName "Restricted Content"
        AuthTokensFile /etc/apache2/.csi_keys
        Require valid-user
</Directory>

cat /etc/apache2/.csi_keys
#
# Client Self Identification tokens file
#
# CSI-Domain-Key							UserName		Role
84bc3da1b3e33a18e8d5e1bdd7a18d7a166d77ac1b46a1ec38aa35ab7e628ab5	MelnikovIN	admin
6d7fce9fee471194aa8b5b6e47267f0348a24b70a0b376535542b996af517398	BoshirovAM	user


2.7.1 Алгоритм расчета сайтом возможных токенов пользователя по известному ключу


Если нам известен ключ K домена, мы легко можем рассчитать возможный «валидный» токен T пользователя, который придет с его запросами. Для этого необходимо, чтобы было выполнено условие: инициатор запросов, получатель запросов и контекст выполнения должен совпадать и быть равен домену. Иными словами, если у нас доменное имя vsphere.local, то:
Sender = Recipient = Context = vsphere.local

Отсюда исходный (сырой) токен рассчитывается, как:

$T_s = HMAC_{K}(Sender \cup Recipient \cup Context)$


При передаче, исходный токен будет дополнительно защищен. Младшие 128 бит токена будут хешированы солью, передаваемой в заголовке запроса CSI-Salt*. Таким образом, сайт увидит следующий токен:

$T = Hi(T_s) \cup HMAC_{salt}( Lo(T_s) )$


Где Hi – старшие 128 бит, Lo – младшие 128 бит исходного токена.
Обычно, для закрытых консолей управления в корпоративной сети, веб-консоли не подгружают внешних скриптов, фреймов и т.п. Поэтому это условие будет в большинстве случае выполнено.

*Способ формирования соли см. в разделе «Процедура обмена солью между браузером и сервером».

2.8 Обработка токенов на сервере


Отправка токена серверу (без ключей)


Статус токена Т в сессии сайта Действия на стороне сервера сайта
Неизвестный Это возможно только при первом входе браузера на сайт, либо при срабатывании защиты протокола и генерации браузером неверного токена на базе случайного числа.

Считаем пользователя анонимом. Создаем новую сессию.
Используем первые 128 бит Т в качестве идентификатора сессии пользователя.
Генерируем соль для защиты токена. Возвращаем браузеру нашу соль в CSI-Salt.

Известный (первые 128 бит) Подгружаем данные сессии.
Если браузер послал свою соль CSI-Salt – соединяем со своей.
Валидируем хеш по алгоритму. Сравниваем с полученными от клиента в CSI-Token.

Если хеш неверный, возвращаем CSI-Token-Action: invalid. Можно вернуть код 400.

Если всё хорошо – ответ 200.



Отправка токена с ключом Permanent


Браузер фиксирует ключ клиента. Пользователь хочет, чтобы сайт запомнил клиента дольше, чем на одну сессию. Сохранять ли токен пользователя в своей базе – решение принимает сервер. Возвращаем клиенту CSI-Token-Action: success или CSI-Token-Action: abort.

Отправка токена с ключом Logout


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


Отправка токена с ключом Change-To


Назовем старый токен T, новый – Т'.

ВАЖНО: в качестве нового токена T' посылается реальное значение токена (в первый раз, для незарегистрированных), тогда как старый токен посылается хешированный (младшие 128 бит).
Статус токена в базе сервера* Действия на стороне сервера сайта
T T'
нет нет Причина: легальная регистрация пользователя.

Меняем идентификатор сессии пользователя на T'
Отправляем клиенту CSI-Token-Action: success.

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

Сервер может послать CSI-Token-Action: registration, чтобы сказать браузеру, что регистрацию необходимо продолжить (пользователь должен выполнить ряд дополнительных действий по подтверждению личности). Тогда браузер будет слать токен с ключом Change-To (ключ уже будет защищенный) до тех пор, пока не будет получен success или abort. В первом случае, браузер считает, что регистрация нового токена завершена. В последнем – что стоит отменить смену токенов (работать на старом).
нет есть Причина: легальный Login.

Подгружаем полный токен T' из базы. Подгружаем профиль пользователя. Меняем идентификатор сессии. Отправляем клиенту CSI-Token-Action: success.

ВАЖНО. Если новый токен хотя бы раз передавался через Change-To в открытом виде, и сервер ответил CSI-Token-Action: success, в следующие разы браузер в ключе Change-To будет передавать уже защищенный токен.
Защищенным токен передается также, если он сформирован на базе импортированного ключа. Экспорт постоянных ключей возможен только после их регистрации на сервере.
Однако сервер при валидации токена должен учитывать, что он может быть передан в «сыром» виде. Это может произойти при первом входе пользователя с другого устройства, когда ключ домена создается на базе мастер-ключа. Т.к. браузер на устройстве «не в курсе», что ключ уже зарегистрирован.
есть нет Причина: легальная смена ключа по инициативе пользователя.

Меняем старый токен T в базе на новый T'. Меняем идентификатор сессии.
Отправляем клиенту CSI-Token-Action: success.
есть,
ключ
фикс
есть Причина: переход с временного ключа на постоянный

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

В данном случае придется сделать слияние двух существующих учетных записей пользователя (с его согласия). Учетную запись от фиксированного токена – удалить.

Меняем идентификатор сессии. Отправляем клиенту CSI-Token-Action: success
есть,
ключ
не
фикс.
есть Ошибочная ситуация. Попытка заменить существующий в БД токен на другой существующий не разрывая сессии. Должна быть отвергнута. Отправляем CSI-Token-Action: abort. Не меняем сессию.

Коллизии 256-битных токенов маловероятны в случае использования честной SHA-2. Возможно нарушение работы хеширующей функции (искусственное ослабление) на стороне браузера или недостаточно хороший генератор случайных чисел.

Следующие вероятные причины возможны только по причине нарушения протокола браузером:
  • пользователь возвращается к использованию предыдущего ключа;
  • пользователь меняет ключ сайта на полученный от другого пользователя;
  • компрометация ключа пользователя
Всё эти ситуации в теории возможны. Но первые две, – только из-за ошибки в работе браузера.
Если оба токена известны сайту, значит это постоянные или фиксированные ключи. В таких ситуациях браузер делает в начале Logout для старого ключа. А затем Login для нового. Никак иначе.

*Имеется в виду сохранен ли в базе данный токен, а не в сессии.

2.9 Меж-доменная идентификация


Как уже говорилось ранее, сайты могут взаимодействовать с другими сайтами-партнерами или своими под-доменами, чтобы предоставлять пользователю некую часть функционала. Самый распространенный пример, когда на сайте site.ru часть ресурсов грузится с поддоменов img.site.ru, часть download.site.ru, а ещё часть с других.

В этом случае сайту site.ru необходимо иметь возможность сообщить своим доменам-партнерам, от кого именно приходят к ним запросы. Ведь, если вы авторизовались на site.ru, это не делает вас автоматически авторизованным на других сайтах, включая под-домены сайта. Они будут видеть от вас иные токены.

Давайте посмотрим, как вычисляется токен и чем нам это может помочь.
Пусть пользователь авторизовался на сайте site.ru постоянным ключом и имеет там токен:

$T_1 = HMAC_{site.ru-key}(site.ru \cup site.ru \cup site.ru)$


Все запросы, идущие со страницы сайта site.ru на домен site.ru и вызванные:
  • ресурсными тегами страницы (статическими или собственными динамическими)
  • собственными скриптами
будут иметь токен T1 (см. правила R1, R4, RB). Это легитимные запросы к сайту site.ru.

Теперь пусть клиент скачивает файл ограниченного доступа со страницы site.ru, но ссылка ведет на download.site.ru. В этом случае поддомен получит следующий токен (правила R1, R4):

$T_2 = HMAC_{site.ru-key}(site.ru \cup download.site.ru \cup site.ru)$



Ровно тот же самый токен download.site.ru получит, если на него будет выполнен ajax-запрос со страницы сайта site.ru (правила RB, RC).

Другой домен domain получит уже токен:

$T_3 = HMAC_{site.ru-key}(site.ru \cup domain \cup site.ru)$



Но, обратите внимание, если условия выполнения запросов не меняются, то для данной связки доменов A, B, C браузер всегда будет генерировать постоянный токен. Значит мы можем провести меж-доменную идентификацию. Например, так.

С сайта site.ru делаем ajax-запросы на поддомены. Передаем идентификатор ID != T1 пользователя, выданный ему сайтом site.ru. Поддомены получат для этого же пользователя ID токены Tx. Каждый из поддоменов сделает связку своего токена с ID пользователя. Информацией о пользователе ID и его правах поддомены уже поделятся межсерверными запросами.

Связка делается однократно. В последствии, поддомены будут ориентироваться на собственные токены, т.к. они для постоянного ключа site.ru тоже будут постоянными.

3 Рекомендации по безопасности


Примечание
Данный раздел не является частью протокола. Здесь идут общие рассуждения о возможных рисках и методах защиты.


3.1 Защита ключевой информации от НСД


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

А вот способы защиты ключей от компрометации необходимо рассмотреть подробнее.

Ключи могут быть скомпрометированы путем:

  • копирования ключевой информации вредоносной программой (удаленный доступ)
  • непосредственного доступа к файлу с ключевой информацией «офлайн» (прямой доступ)
  • в момент распространения между устройствами

Если допустить, что ключевая информация сохраняется на смарт-карте (мы рассматривали данный вариант в разделе «Мобильность учетных записей»), то задача защиты ключевой информации перекладывается на плечи чипа. Правда появляется уязвимость к клавиатурным шпионам, которые могут перехватить вводимый PIN-код; ну и неудобность в использовании.

Помимо смарт-карт для защиты от прямого доступа к ключевой информации можно использовать симметричное шифрование. Но вопрос: какой ключ взять для шифрования?

Если этот ключ генерировать на базе пароля пользователя, то во-первых, получаем уязвимость к подбору пароля «офлайн», во-вторых, собственно, от чего ушли, к тому и пришли: «опять какие-то пароли».

Более правильный вариант зашивать особым образом* такой ключ в сборку браузера (или одной из его специализированных библиотек). При каждом обновлении браузера меняется и ключ, и место его расположения в скомпилированном файле. Такой подход не даст 100% гарантии защиты, но серьезно усложнит задачу по расшифровке. Вначале злоумышленнику необходимо будет выяснить точную версию сборки, затем найти её, провести дизассемблирование, и выяснить как собирается ключ.

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

Можно применить комбинированный вариант: шифрование ключом от браузера + шифрование паролем пользователя от учетной записи ОС (если это позволяет API ОС). Причем ключ всегда генерируется «на лету». Тогда офлайновый брутфорс станет ещё затратнее.

Кроме того, после смены пароля пользователя в ОС, ключ тоже изменится. И если не сделать предварительную расшифровку на старом ключе, то это защитит от ситуаций, когда администратор компьютера меняет вам пароль, чтобы получить доступ к вашей учетной записи и выполнять действия от вашего имени. Ситуации вида: уволился с работы.

Вы же предварительно сделаете резервную копию ключей (экспортируете ключи в файл). Если, конечно, уже не сделали этого ранее при распространении ключей на другие устройства.

*Например, 32-байтный ключ распределен случайным образом в 64К-секции исполнимого файла. И только исходный код знает как собрать из этих байт заветный ключ.

3.2 О паролях в качестве ключей доменов


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

Это позиционировалось как удобный способ мобильности учетных записей. Ввел один пароль и не переживаешь ни о чём. Но потом оказалось следующее:

  1. Если сайт знает свой токен, то сайт может восстановить «брутфорсом» пароль, который был положен в основу формирования ключа домена, формирующий этот токен. А если предположить, что этот пароль пользователь использовал ещё где-либо, то мы получим ключи доменов и от других сайтов пользователя.

    Допустим (гипотетически), что вы используете сложный 8-ми символьный пароль, состоящий из символов латинского алфавита разного регистра, цифр и таких спец.символов: ~!@#$%^&. Общий алфавит составит: 26 + 26 + 10 + 8 = 70 символов. 8-символьный пароль на таком алфавите имеет ёмкость 708 вариантов.

    Представим, что злоумышленник имеет специализированный кластер, способный вычислять наши токены из пароля со скоростью 1012 вариантов в секунду. Тогда для взлома ему потребуется 708 / 1012 = ~576 сек. Т.е. ваш пароль будет гарантировано подобран за ~10 минут. А в среднем такой системе будет достаточно потратить лишь 5 минут на подбор пароля от известного токена. 10-символьный пароль потребует уже в среднем 15 суток. Но повысив производительность системы в 10 раз, мы сократим это время до 1-2 суток.

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


3.3 Риски потери/компрометации ключей и их минимизация


А что если я потеряю мастер-ключ?

Такое может произойти, если вы поменяли пароль или переустановили ОС. Какие риски?

Ну вы не попадете на сайты, где были раньше. Потеряете историю покупок на интернет-магазинах, свои объявления на интернет-площадках, карму на форумах. Не беда.

Хотя, кто мешает сделать процедуру перерегистрации с новым токеном и подтверждением его через телефон, указанный в том же объявлении? Получается, что сайту необходимо делать форму перерегистрации токена (аналог «восстановления пароля»)? Где же обещанное отсутствие «всяких таких» форм?

На самом деле сайту, которому необходимо не просто идентифицировать посетителя, а ещё и знать кто это на самом деле, придется делать форму регистрации. Собственно, эта форма может использоваться для повторной регистрации. Вы указываете ровно те же данные, что и ранее (email, mobile). Подтверждаете, что обладаете этими данными (письмо, СМС). Система видит, что такая учётка уже есть, данные 100% ваши, но токен другой – перезаписывает токен.

Но всё-таки, лучше не терять мастер-ключ.
Как предотвратить потерю? Создавать резервную копию, защищать её паролем и хранить на отчуждаемых носителях. Так же, собственно, как это делается с ключами для bitcoin. В принципе, можно переводить мастер-ключи в печатный вид и сохранять на бумажке. Если на то пошло. А потом восстанавливать ручным вводом. Но это уже для совсем «параноиков», вроде меня.

А что если у меня угонят мастер-ключ?
Это уже серьезно. Хотя описываемые здесь рекомендации по хранению мастер-ключа (не входят в протокол) защищают их от прямого НСД, клавиатурных шпионов и троянов, тем не менее, риск компрометации мастер-ключа сохраняется. К сожалению, идеальной защиты не существует. Ключ может быть угнан прямо из памяти браузера через уязвимость движка javascript. Как пример. Или вы теряете мобильник…

Так какие риски угона мастер-ключа?

Существенные для получения сведений о вас и даже для совершения действий от вашего имени. Получение возможности злоумышленнику авторизовываться под вами и в режиме чтения получать доступ к закрытой информации. Тихо и незаметно. Или разом выкачать все ваши приватные видео из одноклассников. Вам неприятно. Любители котиков ликуют.

Здесь необходимо быстро перерегистрироваться с новым ключом на важных сайтах. И, если случилось страшное, регистрация вашего нового токена в БД поставщика услуг официальным способом, – единственный правильный вариант. Способов регистрации можно придумать множество: от бумажной фиксации в официальном письме, до заявки через службу техподдержки сайта с подтверждением личности приемлемыми способами. Но это только для серьезных сайтов, вроде онлайн-банка.
Способы минимизации рисков. Использование индивидуальных ключей для доменов (но это понижает мобильность учёток). Двухфакторная аутентификация по независимым каналам. Показ сайтом IP-адресов и устройств, откуда было подключение в последний раз, чтобы вы хотя бы вовремя заметили компрометацию.


4 Атаки на схему авторизации



4.1 Трекинг пользователя


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

Чтобы два разных сайта могли определить, что работают с одним и тем же клиентом, применяются две техники:

  1. Выполнение одного сайта в контексте другого и взаимный обмен собственно сгенерированными идентификаторами пользователей (в качестве идентификатора может использоваться всё, что угодно из вашего профиля).
  2. Формирование отпечатка браузера по единому алгоритму (формирование уникального набора атрибутов браузера) и косвенная идентификация клиента по этому отпечатку.

В схеме 2 есть небольшой недостаток: идентифицируется не пользователь, а браузер. Но зачастую браузер == клиент.

Кажется, токен лучшим образом подходит к использованию в схеме № 2. Ведь если пользователь разрешил «запомнить» себя двум сайтам (действующим в паре), наш постоянный токен может выступить в роли такого «отпечатка», только уже не браузера, а самого пользователя. Проблема для сайтов здесь в том, что они получат разные токены.

Но ведь сайты могут попробовать применить ещё и схему № 1. Тогда получится следующее.

Сайт 1 получит от браузера код H1, а сайт 2, выполняемый в контексте сайта 1 – код H2. Кажется, теперь сайты могут сформировать пару (H1, H2) и даже передать это некому сайту-агрегатору.
Пусть есть ещё один сайт 3, который работает в паре с сайтом 2, пытаясь вас отследить. Сайт 3 получит от браузера токен H3, а сайт 2, выполняемый в контексте сайта 3 – токен H2' != H2 (см. как формируется токены). Как результат, объединение полученных данных невозможно, т.к. у них нет пересекающихся частей.

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

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

4.2 Атака вида XSS



XSS – тип атаки, заключающейся во внедрении в страницу атакуемого сайта victim.com вредоносного кода. Например, через партнерский скрипт или взломанный CDN популярного фреймворка.

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

Основная защита от такого рода атак для нашей схемы авторизации – это особые правила генерации поля Source при вычислении токенов.

Уязвимость: для хранимых XSS (когда скрипт в результате взлома сервера непосредственно вставлен на атакуемый сайт и грузится с него), защита не сработает. Поскольку браузер не сможет идентифицировать такой скрипт как «внешний». Эта же проблема возникнет при проксировании злоумышленником трафика клиент-сервер.

4.3 Атака вида СSRF



Жертва заходит на сайт evil.com, созданный злоумышленником. От её лица выполняется запрос (GET/POST/HEAD/PUT/DELETE) на сайт, где пользователь уже авторизован (например, на сервер платёжной системы). Сам запрос осуществляет некую вредоносную операцию (например, перевод денег на счёт злоумышленника). По недосмотру разработчиков, сайт не проверяет поля Referer и не запрашивает дополнительной проверочной информации от пользователя. Как результат, атака проходит успешно.

Предлагаемая схема авторизации на сайтах подавляет большинство сценариев атак CSRF, за счет алгоритма генерации токенов. Любой межсайтовый запрос приведет к получению атакуемым сайтом не валидного токена от пользователя. Как результат, в такой ситуации пользователь для атакуемого сайта будет неизвестным анонимном. Даже попытка выполнить безобидный GET-запрос с атакующего сайта на атакуемый (загрузка картинки) приведет к получению последним невалидного токена.

Это существенно должно упростить жизнь разработчикам сайтов.

4.4 Трекинг с использованием схемы SSO


Два сайта S1 и S2, которым пользователь доверяет и имеет для них ключи, решают применить технологию, аналогичную SSO, для трекинга пользователя. Но т.к. внедрить один сайт в другой нельзя (кто-то из них получит невалидный токен), открыть сайт партнера скриптом тоже нельзя (по этой же причине), то сайт S1 решает применить хитрый прием.

На одной из страниц он размещает полупрозрачный тег A, перекрывающий всё окно. Ссылка ведет на сайт S2, а в адресе передается идентификатор пользователя (от S1) и токен H1. Пользователь не видит ссылку. Нажимая на любую область сайта S1, он инициирует открытие новой вкладки сайта S2.

В данный момент S2 не получит валидный токен. Не поможет ему и самоперезагрузка при помощи тега
<meta http-equiv="refresh" content="0">
или скриптом.

Зато S2 может сделать тег A на всю свою страницу в виде поддельной кнопки «Закрыть»:

Эта ссылка вначале перезагрузит сайт, затем закроет его. В момент перезагрузки браузер пошлет на сайт S2 уже валидный токен H2 (т.к. выполнились правило 2.4 P1: пользователь обе ссылки открыл сам лично).

Как результат S2 получит информацию о действиях своего пользователя на сайте S1, свяжет токен H1 со своим H2, и пошлет H2 межсерверным запросом на S1. В дальнейшем сайты S1 и S2 смогут обмениваться любой информацией о пользователе межсерверным обменом, т.к. теперь могут однозначно его взаимно идентифицировать раздельно друг от друга.
Особо уязвимы к этой атаке мобильные пользователи, т.к. пытаясь закрыть ненужную страницу могут случайно нажать на поддельную ссылку, занимающую весь мобильный экран.
Способ защиты: автоматически разрывать сессию при закрытии вкладки. Тогда сайт S2 не смог бы получить валидный токен до тех пор, пока пользователь сам не авторизовался бы на нем. Правда это не защитит от ситуаций, когда пользователь сам открыл вкладки и авторизовался на S1 и S2. А уже потом сайты провели такую атаку.

4.5 Компрометация ключа для SSO


Пусть учетная запись пользователя на сервере аутентификации, поддерживающим SSO, компрометирована. Оценим возможные риски при нашей схеме аутентификации.

Токены для каждого сайта рассчитываются индивидуально на базе ключей доменов.
Компрометация одного ключа домена не ведет к автоматической компрометации всех остальных.
Большинство сайтов, где вы уже авторизовывались ранее при помощи SSO, наверняка сохранят в своей базе ваш токен с вашим профилем с сервера SSO. В нашей схеме, сайт просто будет подтягивать токен из БД и опознавать вас. Т.е. на таких сайтах сервер SSO уже не нужен – он выполнил свою функцию на этапе регистрации.

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

Не поможет злоумышленнику и попытка провести заново кросс-доменную аутентификацию: сайт должен блокировать попытки создания новой учетной записи со старым Id-пользователя SSO и новым токеном сайта. Либо попытки перезаписи токена пользователя для существующего Id в процессе SSO должны блокироваться. Сам факт этого, должен вызвать обоснованные подозрения на стороне сайта.
Токен пользователя может быть легально изменен только одним способом (см. «Сценарии работы протокола»).

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

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

Максимальный риск: авторизация от вашего имени на других сайтах (где вы ещё не были). Доступ к данным вашего профиля. Совершение незаконных действий от вашего имени. А чтобы законный владелец не смог ничего вернуть, злоумышленник может поменять на сервере авторизации свой токен легальным способом. Этот риск, впрочем, совпадает с рисками, при использовании традиционных схем авторизации.

Способы защиты. Отказ от использования SSO (тем более, что предлагаемая схема и задумывалась как способ уйти от централизованных схем аутентификации). Использование нескольких SSO (не храните все яйца в одной корзине!).

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

4.6 Компрометация токена при передаче


Понятно, что предложенный механизм хеширования токенов при передаче не дает 100% гарантии их защиты. Злоумышленник может перехватить трафик жертвы в момент передачи незащищенного токена (в момент первичной регистрации постоянного ключа), как пример. И потом использовать его.

Поэтому использование SSL приветствуется. Но не стоит воспринимать HTTPS как панацею. Это протокол также вскрывается, как и HTTP. Только чуть сложнее.

Правда столь редкая передача открытого токена, а также использование индивидуального токена для каждого домена снижает риск эксплуатации уязвимости. Тем не менее.

Еще одна опасность – перехват и повторное использование токена в рамках текущей сессии пользователя. Как я говорил ранее, в идеале токен должен хешироваться новой солью при каждом запросе клиента. Однако это убьёт возможность параллельной обработки запросов на сервере и сделает невозможной отправку параллельных запросов от клиента. Вычисление и проверка хэшей вообще-то дорогостоящая операция, снижающая производительность.
Кроме того, токен, передаваемый в заголовке, не должен быть доступен из Javascript никогда. Аналогично Cookie с флагом HttpOnly. Даже при получении ajax-запросов скриптами.
Способ эксплуатации: перехват запроса пользователя, извлечение текущего значения токена, отправка иной операции с тем же токеном (как от имени того же пользователя). Правда и классическая система на базе сессионного cookie тоже уязвима к данному типу атаки.

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

4.7 Взлом сайта и компрометация токенов


Взломы сайтов происходят постоянно. Ломают даже крупные и хорошо защищенные сайты. Путей взлома много: от банальной инъекции, до инсайдерского «слива». Поэтому компрометация вашего токена на каком-либо сайте – событие весьма вероятное.

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

Но при этом использовать ключ домена, чей токен был скомпрометировать, уже, по понятным причинам, нельзя. Придется менять ключ.

Ключ для домена, где произошла официальная утечка, можно сделать либо на базе случайного числа, либо на базе мастер-ключа, с добавлением номера версии:

$DomainKey = HMAC_{M_{key}}( DomainName \cup VersionNumber )$



Заключение


Несколько моих знакомых, которым я показал статью, задавали мне по сути один и тот же вопрос: «А в чем здесь главная фишка?»

Если смотреть с высока
И действительно, поверхностный обзор протокола оставляет о нем впечатление (особенно с точки зрения конечного пользователя), как об ещё одном (очередном?) парольном менеджере, встроенном в браузер.

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

Серверы кросс-доменной авторизации тоже решение «так себе». Те же яйца Тот же парольный менеджер, только сбоку «онлайн». Тут вы доверяете владельцу сервера, а не разработчику менеджера. Но сервер могут взломать (и не важно Google это, или Facebook – утечки происходят рано или поздно у всех). Сервер может быть недоступен (вдруг его DDOS-ят или там просто тех.работы – ЕСИА в пример) или заблокирован каким-либо органом. Да и вообще, такие серверы под маской SSO любят собирать о вас слишком много информации, и нередко становятся целью хакеров со всего мира. Вам это нужно?

К тому же, мне, например, не прельщает перспектива регистрироваться в хомячковых соц.сетях только затем, чтобы авторизоваться на очередной интернет-барахолке и разместить там объявление купи-продай. Тем более, что регистрация в таких соц.сетях, становится всё строже и строже. Раньше требовался лишь подтвержденный email, потом телефон. Сейчас в наглую требуют реальную фотографию. Не удивлюсь, если скоро от нас будут требовать сдать отпечатки пальцев и кровь на анализ. Вам точно это нужно?

Я хочу интернет-независимости. А вы? SSO – не делает на свободными.

Наконец, есть же во многих браузерах встроенная фишка «запомнить пароль». Правда эта фишка исчезает при первой же переустановке ОС. Да и с мобильностью тут неважно. Даже между браузерами в пределах одного устройства. Фактически проблема с хранением паролей и их синхронизацией отдана на откуп самому пользователю. Крутись как можешь, чувак.

Некоторые хитрые браузеры предлагают войти куда-то там в облако и хранить «безопасно» пароли там. Но мы уже знаем, чем пахнет такое «безопасное облако». К тому же ставят вас в зависимоть от конкретного браузера, что уже не хорошо.

Так всё-таки, неужели в предлагаемом протоколе нет ни какой особой фишки?

О вот нет главной фишки! Увы. Но есть ряд деталей, делающих протокол выгоднее традиционной схемы «логин/пароль».

1. Вы, наверное, замечали на многих сайтах этот надоедливый popup
«Наш сайт сохраняет cookie! Наденьте каску и будьте бдительны, ведь большой брат следит за вами! Нажмите «Да», ибо выбора у вас всё равно нет».
Это ещё один popup к куче других таких же назойливых и очень нужных. А всё это благодаря европейскому GDPR (аналог нашего закона ПДн).

Так вот. В нашей схеме, cookie для целей идентификации больше не нужны! От слова «совсем». Пользовать сам решает позволить ли сайту идентифицировать его, и когда и как долго это делать. Минус один назойливый попап, +1 в карму протокола.

2. Разработчику не нужно больше делать формы авторизации и восстановления пароля. Нет необходимости реализовывать непростые алгоритмы SSO и осваивать непростые библиотеки: OAuth, SAML, Kerberos и т.п., проходить процедуру регистрации своего сайта, менять ключи авторизации, следить за их безопасность; а если что-то пошло в друг не так с SSO, в срочном порядке разбираться: «что пошло не так, и почему». Да ещё и сервер авторизации может заблокировать ваш сайт по неизвестным причинам. Пойди разберись. Вчера всё работало, а сегодня… А тут достаточно просто прочитать токен из заголовка и проверить, нет ли такого в нашей базе. Просто = надежно.

просто говоришь...
На самом деле автор тут лукавит. Протокол не такой уж простой. Особенно для разработчиков браузеров и разрабочиков сайтов, которым нужны кросс-доменная и меж-доменная идентификация пользователя. И отсутствие форм регистрации я тоже обещал. Знаю. Но увы.

Но для всяких интернет-магазинов, интернет-барахолок, функция «запомнить пользователя» реализуется крайне легко.


3. Пользователю нет необходимости заводить и помнить кучу паролей. Пользоваться услугами сторонних сайтов или неизвестно кем и как написанных программ. Можно не бояться доступа к компьютеру сторонних лиц, клавиатурных шпионов и троянов. Достаточно сделать резервную копию мастер-ключа, защитить её паролем и хранить где-нибудь на флешке. Как биткоин-кошелек. Чем не фича?

4. Если сайт взломают, вы ничем не рискуете. Ну перегенерируете заново ключ. Тогда как утекший к взломщикам сайта пароль может доставить много неприятностей.

5. Протокол создавался с учетом опыта известных сетевых атак. В его архитектуру уже встроена базовая защита от XSS, CSRF. Опять же веб-мастерам будет проще в разработке сайтов. А их пользователям — спокойнее.

6. Независимость протокола от конкретного поставщика услуг и его прихотей. Протокол делает вас свободным.

7. Наконец, предлагаемый протокол претендует на будущий открытый стандарт. А стандарт, в случае его принятия участниками, накладывает обязательства реализовывать функционал согласно спецификации, а не городить колхоз из собственных решений по авторизации, изобретая в очередной раз форму логина, регистрации, восстановления пароля, логаута. И не накосячить с хэшированием паролей или SQL-инъекцией.

А самое главное, как и любой открытый стандарт, он может быть и должен быть проверен независимыми экспертами. Даже если автор изначальной версии протокола «накосячил» в деталях, интернет-сообщество может своевременно это выявить исправить. Ну или отправить мой протокол в утиль. Увы для меня, и «фух-пронесло» для всех остальных.

– Думаю, мне следует на этом остановиться
Э. Уайлс



PS
Вы можете ознакомиться с вариантом полноформатной статьи в оффлайновом формате. При верстке материала на Habr я мог допустить опечатки. Если у вас есть серьезные замечания, лучше сверяйтесь с оригиналом и оставляйте постатейные комментарии (рецензии) именно в этом файле. Свои правки высылайте мне на почту sergey201991[]гмайл. Я не осьминог, но постараюсь ответить. Многократное совпавшие / интересные замечания добавлю в эту статью. Вместе с ответами на них. Не исключен вариант отдельной статьи-комментариев.

Да, я знаю, что у протокола могут быть проблемы:
  1. нет возможности автозоваться под своей учёткой на чужом девайсе, если у тебя нет ключа под рукой, а нужно срочно; пароли тут удобнее
  2. не совсем понятен алгоритм использования пользователям; могут возникнут сложности с управлением ключами при авторизации на сложных сайтах, особенно SSO
  3. если вдруг мою идею и правда «заценят», веб-мастеры меня проклянут: какое-то время будут использоваться обе системы (а возможно и пожизненно)
  4. я мог упустить что-то важное

По поводу п. 1 — я уже всерьез раздумывал вернуться к идее генерации ключа домена на базе пароля, сделав защиту от брутфорса путем усложнения процесса генерации ключа: скажем, увеличив число раундов хэширования до 1000. Но проблема с возможной коллизией паролей у разных пользователей на одном сайте не дает мне покоя.

По поводу п. 2 — это лечится временем. К новым интерфейсам нужно привыкать. Сначала будет не понятно, потом будет просто. Дай человеку 80-х годов современный смартфон, он тоже бы не догадался как им управлять.

Огромное спасибо, если дочитали это до конца!

Комментарии (124)


  1. APXEOLOG
    21.10.2019 07:08

    нет возможности автозоваться под своей учёткой на чужом девайсе, если у тебя нет ключа под рукой, а нужно срочно; пароли тут удобнее

    А если например полетел винт или винда — со всеми учетками тоже можно попрощаться.
    Идея в целом интересная, но надежность имхо низковатая


    Если сравнивать с текущим кейсом обычного пользователя: сохранение паролей в браузере + перекидывание их между этим же браузером на разных платформах. По сути пароль вам нужно ввести только один раз, а дальше браузер его сам подставит. Безопасно? Не очень. Удобно? Максимально. Плюс всегда есть возможность ввести пароль вручную


    1. BarakAdama
      21.10.2019 11:00

      Сохранение паролей в браузере + перекидывание их между этим же браузером на разных платформах.… Безопасно? Не очень.

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


      1. Sly_tom_cat
        22.10.2019 11:11
        +1

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

        Но они сознательно сломали этот механизм — теперь на новом телефоне мастер пароль не спрашивается хотя данные «зашифрованы». Откуда новый телефон его узнает? Правильно из профиля пользователя. Ну и какой смысл в таком шифровании если пароль лежит рядом с зашифрованным этим паролем контейнером?

        Уроды, блин.


        1. BarakAdama
          22.10.2019 14:25

          Вот поэтому у нас пароль не лежит рядом с контейнером.


      1. KaminskyIlya Автор
        23.10.2019 00:12

        Кстати, обратите внимание, у меня мастер-ключ это не пароль! Это 256-битная случайная последовательность, полученная как результат работы биологического ДСЧ.

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


        1. saege5b
          23.10.2019 10:00

          Длина ключа — 256 бит?
          У меня в генераторе паролей по умолчанию 128 знаков стоит.


        1. BarakAdama
          23.10.2019 10:13

          У нас ключ шифрования это тоже не мастер-пароль, а цепочка расшифровки достаточно длинная, слабые пароли уже не так влияют на уровень защиты.


  1. IkaR49
    21.10.2019 07:38

    Тоже думаю, что идея интересная. Но, по сути, ваш мастер-ключ и превратится в тот самый пароль, который простой обыватель будет записывать на бумажке и клеить на монитор, если захочет зайти во вконтактик как с ПК, так и с телефона.
    Плюс, с точки зрения удобства это самый обычный менеджер паролей. Но вот идея с временной авторизацией это прям мне понравилось.


  1. AlexanderBlack
    21.10.2019 08:22
    +1

    1. KaminskyIlya Автор
      21.10.2019 08:29
      +2

      Ух-ты, ж! Нет, конечно. Иначе бы не потратил почти 4 месяца на разработку и публикацию. Беру таймаут на изучение этого протокола. Если он лучше предложенного (а я, полагаю, что очень может быть) и нет никаких идей из данного протокола, которые можно было бы применить к WAA, то сниму публикацию с Хабра.


      1. vin2809
        21.10.2019 09:08

        Отличная работа.


        Если вы не списали идею у Moziilla, то зачем снимать статью? Это же ваш труд.


        1. IMnEpaTOP
          21.10.2019 09:51

          Вот именно по этой причине тег сарказм нужно использовать всегда, даже если не сомневаешься в очевидности его натурального оформления.


      1. user_man
        21.10.2019 14:11

        Снимать с публикации не надо. Надо улучшать.

        Смысл в чём? В том, что мозилла продаёт свои услуги всем, кто предложит достаточно денег. Поэтому все их протоколы, поддерживаемые их браузером, в одно мгновение переориентируются на нужды нового заказчика, который предложил больше денег, а значит ни о какой анонимности и прочем речи быть не может.

        Поэтому нужны альтернативы. Ваш вариант — возможная альтернатива. Но, как написали ниже, она несколько «тяжеловата».

        Во первых — выделите главное. И сделайте из него верхний уровень протокола. В главном должна быть лишь основная идея — шлём сессионный ключ для сессии или шлём постоянный ключ для постоянного подключения. Всё остальное — следующие уровни протокола.

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

        В целом альтернатива состоит в том, что, во первых, браузер идёт лесом, а во вторых, протокол делится на уровни. При этом прокси будет прост в реализации, что позволит получить множество вариантов на разных языках, и все — с открытым исходным текстом. Топ подобных прокси будет очень заметен и потому их открытый код будет безопасен.

        Всё остальное — детали реализации. Они важны, но если вы заморочитесь ими — вы похороните свой протокол. Важное — верхний уровень. Плюс обязательно выкинуть браузер. Всё остальное — только когда готов (согласован с общественностью) верхний уровень.

        ЗЫ. У меня аж зуд появился на написание прокси. Но только после согласования верхнего уровня.


        1. KaminskyIlya Автор
          22.10.2019 01:53

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

          Золотые слова. Я думал об этом.
          Только у меня правила вычисления токена сильно завязаны на DOM-модель и её состояние, к которому у прокси не будет доступа. Но кто сказал, что нельзя решить и эту проблему. Или сделать комбинированный вариант. Нужно думать.

          Во первых — выделите главное. И сделайте из него верхний уровень протокола.

          Вы правы, стоит использовать опыт OSI. Чётко разделить зоны ответственности.

          У меня аж зуд появился на написание прокси.

          У меня самого зачесались руки и я набросал концепт-код серверной части (пока на PHP; хочу ещё в виде фильтра запросов на Java под tomcat). А ещё нужен тестовый плагин для браузера.
          Я уверен, что тестовая имплементация протокола (в виде рабочего концепта), — правильный (хотя и затратный) способ для оценки его сложности/легкости, удобства/неудобства. И единственный способ, чтобы прогнать все возможные сценарии.


          1. user_man
            22.10.2019 14:00
            +1

            >> Только у меня правила вычисления токена сильно завязаны на DOM-модель

            Зачем? Начать можно с домена, доступного в HTTP, а далее — сервер, поддерживающий протокол, сам скажет, что такой-то поддомен или путь — это отдельный сервис.

            >> А ещё нужен тестовый плагин для браузера.

            Снова подумайте о сложности. Привлекать в дело ещё и потроха браузера — сильно повышать сложность. Никаких DOM и браузерных штучек, останется только чистая обработка простейших заголовков и хранение ключей. А с браузером — ну разве что если интересно освоить написание плагинов.

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

            Не потрогаешь, не поймёшь, да. Но есть опасность ухода в частности, что далее повлечёт опасные последствия. Хотя, разумеется, вам виднее.


      1. EminH
        21.10.2019 14:26

        И на вот это еще гляньте en.wikipedia.org/wiki/WebAuthn


      1. mikhailian
        21.10.2019 22:41
        +1

        Обратите внимание, Webauthn — исключительно хардверное решение. TPM или Secure Element и всё такое.


  1. ne_kotin
    21.10.2019 08:24

    Кто-то только что переизобрел Керберос (:


    1. KaminskyIlya Автор
      22.10.2019 02:05

      Керберос (как и SAML, OAuth) — это протокол авторизации, где требуется посредник (арбитр): третья сторона (Key distribution center). Что делает вас зависимым от этой стороны. Предлагаемая схема авторизации — двусторонняя. Вы и сайт не зависите от кого либо.

      Я изучал этот протокол. Возможно, несколько поверхностно. Если Вы считаете, что я «переизобрел Керберос», буду раз, если покажите в чём именно совпадение.

      Центральная идея — клиент сам себя идентифицирует, присваивая себе уникальный номер. Никто, кроме клиента не знает, как он сформирован.
      Сейчас идентификацией своих пользователей занимается сам сервер, назначая вам некий ID. Схема переворачивает эту идею наоборот.


  1. apapacy
    21.10.2019 08:46

    Мне интересен другой аспект. Юридический так сказать. Сейчас все боятся с куками. В том самом европейском стандарте о защите данных пользователей в тексте указаны запреты именно на куки или же на идентификацию любыми другими способами?


    И заодно второй вопрос. Где-то я слышал что там запрещают сбор информаци если она не нужна для выполнения сайтом стих полезных для посетителя функций. А так вообще о можно собирать.


    Кто-нибудь может внести ясность?


    1. Jabher
      21.10.2019 22:57

      в европейском законе написано "и аналогичные технологии", никак трекать нельзя, они не привязывались к конкретной технологии


    1. MaxVetrov
      22.10.2019 01:37

      Сейчас все боятся с куками.
      Конечно, без печенек трястись никакого резона, успокаивают когда жуешь :)


    1. s-n-ushakov
      22.10.2019 02:06

      Про куки всё так. Не со всеми куками борьба идёт, а только с third-party…
      А в отношении технически необходимых first-party куков есть понимание, что отменить их нельзя, и даже согласие пользователя на их использование не требуется:
      wikis.ec.europa.eu/display/WEBGUIDE/04.+Cookies


      1. apapacy
        22.10.2019 13:50

        Насколько я понимаю, третьи стороны могут устанавливать cookie это в первую очередь google, facebook и иже с ними. То есть их sdk я могу грузить только после того как пользователь подтвердит свое согласие? Или же устанавливать заголовок на страницу какой-то экзотический с CORS-что-то там. Но страница же загружена. То есть что реально делать с этими вещами чтобы не попасть под санкции?


        1. s-n-ushakov
          22.10.2019 14:25

          Как мне видится, технические вещи типа CORS — сами по себе, и заголовки какие нужны, чтобы браузер согласился со всей конструкцией работать, такие и нужны.
          А юридические вопросы — сами по себе. Как на той же самой странице чуть ниже пишут, всё что надо — это:


          • показать сообщение про куки;
          • обеспечить отсутствие third-party куков, пока не будет получено согласие посетителя;
          • разумно после этого создать куки на весь портал, чтобы не переспрашивать одно и то же на разных поддоменах.


          1. apapacy
            22.10.2019 21:48

            Не понял это флоу. Куки третьей стороны это всякие сайты типа google. Я не могу их не устанавливать не отменять. Единственное что я могу сделать так это не грузить gmaps, gtm, facebook sdk пока клиент явно не разрешит мне это сделать.


            1. s-n-ushakov
              22.10.2019 22:59

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


  1. Scf
    21.10.2019 10:00

    Мне больше нравится идея аутентификации через OAuth2 на госуслугах, у них даже есть опция анонимной аутентификации, когда стороннему сервису передается только email.


    Сервера надежно защищены, гарантии существования сервиса дает государство, при потере пароля можно прийти с паспортом в ближайший МФЦ.


    Вот только подключиться к ним нельзя, отвечают отпиской, что подключение только для категорий организаций, явно указанных в каких-то ФЗ...


    1. KaminskyIlya Автор
      22.10.2019 02:23

      Я знаком с ЕСИА (подсистема госуслуг, часть СМЭВ) не понаслышке. Занимался интеграцией двух информационных систем в ЕСИА (по протоколам SAML и OAuth), и юридической регистрацией этих систем. В настоящее время обслуживаю одну из информационных систем, интегрированных в СМЭВ.

      Сервера надежно защищены

      Хотелось бы в это верить. Боюсь, что защита больше «на бумаге». Я видел, как «грамотные» сотрудники пересылали по Skype и TeamViewer секретные дистрибутивы ключей от VipNet с дефолтными паролям, дающие возможность работы с защищенными ресурсами.

      Но самое главное, любое SSO делает вас зависимыми от третьей стороны. И если по каким-то причинам она недоступна вам или веб-серверу, то…

      Вот такое изображение я частенько вижу:
      image
      Периодически ЕСИА проводит «профилактические работы». Из-за которых не доступны многие гос.сервисы (запись к врачу, налоговая, гос.закупки).

      Вот только подключиться к ним нельзя...

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


      1. Sly_tom_cat
        22.10.2019 11:19

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


    1. FSA
      22.10.2019 11:19

      Как физическое лицо подключиться никак нельзя. Необходимо юридическое лицо. Да и то, наверно, не любое. Я просто писал реализацию для аутентификации через ЕСИА (сайт до сих пор работает) и задался сделать это у себя на сайте. Но увы.


  1. Sabubu
    21.10.2019 13:20

    У вас очень сложные и запутанные правила передачи токенов при переходе с сайта на сайт (Sender/Receiver/Context). Их трудно запомнить и при работе с ними легко допустить ошибку. Проблема CSRF понятна, но ваше решение слишком сложное. Вообще, в вашем протоколе все сложное. Это его ахиллесова пята.


    На мой взгляд, один из вариантов решения для борьбы с CSRF мог бы быть — не отправлять авторизационные куки с POST/PUT/DELETE-запросами, а требовать сайт явно включать их в форму (атрибутом вроде send-cookie="auth: 12345") или добавлять в AJAX-запрос. Это, правда, оставляет уязвимыми сайты, где какие-то действия делаются по GET-запросу. Но решает проблему на правильно сделанных сайтах и не требует заучивания сложных правил. Как вам? Другой вариант — не включать куки в запрос при кроссдоменных POST-запросах, но включать при запросах в пределах одного домена, чтобы облегчить жизнь разработчикам. Тогда вообще никакие атрибуты не нужны.


    Под ваше ТЗ (сайт должен запоминать пользователя, пользователь должен иметь возможность стереть информацию о себе) хорошо подходят токены в куках, которые уже есть и работают (правда, уязвимы для CSRF).


    Также, у вас неудачная идея вида "браузер может отправить заголовок с запросом на любую страницу". Это тоже плохо, так как например может быть несколько приложений внутри одного домена, которые имеют разный код, работают на разных серверах (например, у Гугла все на одном домене для лучшей передачи кук). Или запрос может попасть к nginx, обслуживающему статику и игнорирующему такие заголовки. Запросы не должны отправляться "на любой" URL.


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


    Зачем нужны Sender/Receiver и правила работы с ними, если гораздо проще просто не передавать токен при кроссдоменных запросах (когда сайт A шлет POST-запрос на сайт B)?


    У вас сложный протокол из-за того, что он садится поверх существующих запросов и браузеру надо отслеживать состояние, например, что он послал заголовок с меткой Changed, но пока не получил подтверждения. Допустим, браузеру надо отправить параллельно 50 запросов на загрузку статики. Он к каждому будет прикреплять поле changed или только к первому? Что делать, если он не получил подтверждения? Ждать следующей возможности отправить эту пометку? Также, браузер должен сначала узнать, что сайт поддерживает токены, прежде чем слать их на сайт, опять усложнение. Я бы не хотел быть разработчиком, которому поручили это реализовать.


    В описании протокола в пункте 2.3 вы считаете, что запросы отправляются по одному по очереди, однако браузеры шлют запросы параллельно. Запросы могут выполняться очень долго или отваливаться по таймауту. У вас это учтено?


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


    Далее, предположим, что сайт хочет иметь телефон, email и имя пользователя и традиционную регистрацию. Упрощает ли ваша система жизнь пользователю или увеличивает нужное число кликов?


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


    Какая выгода сайтам от интеграции вашего решения?


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


    Ваша система мне кажется очень непонятной для обычного пользователя. Надо нажать на какой-то ключ, выбрать опции с непонятными словами… Это явно фича для продвинутых, а не обычных пользователей. А уж те случаи, когда срабатывает защита и авторизация отключается, вообще будут выносить людям мозг. Представьте — секунду назад у пользователя была полная корзина товаров, а после клика по ссылке они все исчезли. Пользователь не поймет, что произошло, не сможет это объяснить техподдержке, а магазин потеряет заказ. Магазин не захочет использовать такую систему.


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


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




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


    1. KaminskyIlya Автор
      22.10.2019 07:06
      +1

      Благодарю за столь развернутый комментарий! Вы поднимаете важные вопросы. Боюсь, что формат комментариев к статье не самый удобный вариант для ответов.

      запутанные правила передачи токенов… Их трудно запомнить и при работе с ними легко допустить ошибку

      Эти правила для разработчиков браузера. Сложными они кажутся лишь потому, что мне не удалось их лаконично описать. Моя вина. Я попытался не только описать эти правила, но объяснить зачем они такие, да на конкретных примерах, да с картинками. Это перегрузило и так не простую статью. Что касается сложности, если почитать стандарт CSS… Бедные разработчики браузеров!
      Разработчикам веб-сайтов не нужно их запоминать. Всю низко-уровневую работу с протоколом, по задумке, должны на себя брать библиотеки, оформленные, например, как фильтр запросов.
      Что касается фронтенд разработчиков. Всё что им нужно помнить — несколько простых правил: не использовать в закрытых разделах сайта скрипты, загружаемые с CDN или сторонних ресурсов (точне можно, если осторожно); осторожнее делать редиректы на сайты-партнеров. Эти рекомендации стоит включить в соответствующую главу. Но сейчас её нет. Мой косяк.

      ваше решение слишком сложное. Вообще, в вашем протоколе все сложное. Это его ахиллесова пята.

      Боюсь, что не без этого. Но с другой стороны, откройте любой стандарт. Тот же HTTP, SAML, OAuth, Kerberos. И там тоже всё не так просто. Я за простоту.

      На мой взгляд, один из вариантов решения для борьбы с CSRF мог бы быть...
      Так сейчас так и делается. И не только так. Но нередко даже самые лучшие профессионалы допускают досадные ошибки. Ибо такие «правила» тоже необходимо четко помнить и держать в голове при разработке сайта. Предлагаемый протокол может существенно затруднить эксплуатацию уязвимостей на веб-страницах «из коробки». Но 100% гарантий вам никто не даст. Это надо понимать.

      Также, у вас неудачная идея вида «браузер может отправить заголовок с запросом на любую страницу».

      Я даже неправильно поставил акцент: не может, а обязан. Ибо не только веб-страницы будут требовать авторизации, но и загружаемые с них ресурсы (файлы из закрытой секции, как пример). Отсюда напрашивается и вариант реализации на стороне сервера — фильтр запросов, обрабатывающий протокол.

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

      например может быть несколько приложений внутри одного домена

      Думаю, что это плохая практика. Даже для существующей схемы на основе cookie. Но и это решаемо. Спасибо за этот юзер кейс. Буду исследовать.

      Это явно фича для продвинутых, а не обычных пользователей.
      Согласен. Но большинство современных фич тоже когда-то были «только для продвинутых».

      Сайты, очевидно, хотят контролировать вид формы входа/регистрации и их процесс, чтобы иметь возможность сделать его лучше, чем у конкурентов, а не «как у всех». Чтобы иметь возможность сделать его простым.
      Знаете, мне когда-то зацепил подход сайта drom.ru. Хочешь подать объявление о продаже авто? Да не вопрос. Подавай. На телефон приходит код твоего объявления. Ты можешь через неделю отправить платную СМС-ку, чтобы поднять свое объявление в топ. Или ничего не делать. Никаких предварительных регистраций, логинов и паролей. Это, я считаю, и просто и удобно. Не знаю как сейчас там. Но на авито или ам.ру продавать авто точно не буду.

      сохранить токен с сайта в браузер и достать токен из браузера?
      Центральная идея протокола — токен назначается не сайтом, а пользователем самим себе. Собственно, протокол и назван Client Self Identification.

      Кроссдоменную авторизацию проще было бы делать без участия встроенных в браузер протоколов, используя протоколы вроде OAuth2. Сайты ведь всегда могут передавать друг другу какие-то токены через адресную строку.
      Сейчас так и делается. Поверьте, не проще. Для пользователя — да. Но для веб-разработчиков нет. И хотя есть библиотеки, реализующие за вас не простой OAuth2, существует ещё и дополнительная работа, ложащаяся на плечи разработчиков/администраторов сайта. Например, ситуации, когда внезапно «упало». Нет доступа до сервера SSO. Закончил срок действия сертификат ключа. Да и регистрация веб-сайта на SSO-сервере тоже задача не излегких. Особенно на этапе разработки.

      Ваше решение не поможет анонимности, так как сайты будут игнорировать его и принуждать пользователя к традиционной авторизации через куки, чтобы отслеживать их.
      Я надеюсь настанут такие времена, когда такие сайты вымрут, как класс. Пользователи своими «визитами» (точнее их отсутствием) будут голосовать против них.

      В описании протокола в пункте 2.3 вы считаете, что запросы отправляются по одному по очереди, однако браузеры шлют запросы параллельно. Запросы могут выполняться очень долго или отваливаться по таймауту. У вас это учтено?

      Учтено. Первый запрос на сайт браузер посылает на сервер и ждет от него ответа. Как правило, это код HTTP-страницы. Только после получения её кода, когда DOM попадает на парсер, браузер начинает группировать запросы и слать их пачками параллельно. В этот момент браузер уже получил соль от сервера. Он пришел с кодом HTTP-страницы.
      Если загружается не страница, а конкретный файл (по прямой ссылке), то тут вообще всё проще.

      Чуть выше я как раз-таки и пишу: «В идеале CSI-Salt должен меняться при каждом запросе браузера к серверу. Однако это может быть затратным требованием с точки зрения вычислительных ресурсов. Кроме того, это может «убить» возможность отправки параллельных запросов на сервер.»
      Также в сноске я пишу: «Время, через которое делается изменение CSI-Salt определяется браузерами самостоятельно. Это может происходить после серии запросов, после таймаута, после определенного числа запросов.»

      Допустим, браузеру надо отправить параллельно 50 запросов на загрузку статики. Он к каждому будет прикреплять поле changed или только к первому?

      Тоже самое касается запроса с ключем Changed-To. Браузер шлет запрос и ждет на ответа сервера. Только получив положительный (или отрицательный) ответ с заголовком CSI-Token-Action, начинает слать запросы «пачками». Запрос с ключем Change-To относительно редкая операция. Возникает в момент, когда пользователь активирует постоянный ключ (браузер должен перезагрузить страницу). Соответственно, вначале браузер дожидается ответа на этот запрос. А после, получив DOM страницы и заголовок CSI-Token-Action, начинает уже слать запросы пачками. К сожалению, я этот момент (перезагрузки браузером страницы после активации ключа) не отразил ни в тексте, ни в анимациях.

      Зачем при передаче по HTTPS как-то шифровать или хешировать токен, мне непонятно.
      Затем, что HTTPS-трафик тоже может быть перехвачен. У меня есть глава по этому поводу, но я не стал включать её в статью, боясь вызвать ненужный спор. Если хотите, я могу вам скинуть в её личку. Кроме того, протокол проектировался без учета среды передачи (HTTP/HTTPS). Поэтому правила защиты токена едины.
      для чего шифровать токен, который к другим сайтам не подойдет?
      другим не подойдет, но имея такой токен можно выполнить легитимный запрос на целевой сайт от имени жертвы пока «сессия жива». Такая модель угроз рассматривается в разделе «4.6 Компрометация токена при передаче».

      Зачем нужны Sender/Receiver и правила работы с ними, если гораздо проще просто не передавать токен при кроссдоменных запросах
      Затем, чтобы иметь возможность реализовывать меж-доменную идентификацию на группе взаимосвязанных доменов А, В, С. Это стандартная ситуация. Почему меж-доменная идентификация A,B,C возможна, но при этом трекинг сторонними сайтами (например, группой сайтов В, С,D) уже не возможен, рассматривается в модели угроз «4.1 Трекинг пользователя».
      Ещё раз повторюсь эти правила — для разработчиков браузеров. Рядовой пользователь или веб-мастер даже не будет знать о них.

      Какая выгода сайтам от интеграции вашего решения?
      О я ждал этого вопроса! Этому можно посвятить отдельную статью.
      Ну, например, какая выгода сайту от использования HTTPS супротив HTTTP? Безопасность пользователя? Но ведь какое дело до безопасности разработчику сайта?
      Дизайнеру сайта, например, проще — нет лишних виджетов. Сейчас всё движется в сторону простоты. На мобильном экране с маленьким экраном лишний виджет — головная боль для UX-специалиста.
      Веб-мастеру: минус несколько стандартных служебных страниц (регистрация, восстановления пароля, авторизации).
      Ну и, наконец, простота для пользователя. Как следствие, увеличение конверсии.

      Действия могут вызываться яваскриптом или мета-тегами.
      Ни в коем случае в это не должен вмешиваться javascript! Красными буквами это выписать! Это потенциальная дыра!

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


      1. Sabubu
        22.10.2019 17:31

        Эти правила для разработчиков браузера. Сложными они кажутся лишь потому, что мне не удалось их лаконично описать

        И для веб-разработчиков, которым их придется изучать. Так как задача веб-разработчика — чтобы все на сайте работало правильно при всех вариантах переходов с сайта/на сайт.


        Всю низко-уровневую работу с протоколом, по задумке, должны на себя брать библиотеки, оформленные, например, как фильтр запросов.

        Это так не работает. Для отладки какой-то проблемы приходится лезть и вручную разбирать заголовки. И ваши запутанные правила.


        С этим кейсом не знаком. Интересуют подробности. И как это технически реализуется сейчас. Напишите.
        Или вы имеете в виду ситуации, когда вы одновременно, скажем, в яндекс.почте работаете с несколькими ящиками?

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


        Учтено. Первый запрос на сайт браузер посылает на сервер и ждет от него ответа. Как правило, это код HTTP-страницы. Только после получения её кода, когда DOM попадает на парсер, браузер начинает группировать запросы и слать их пачками параллельно.

        HTML-файлы парсятся поточно, по мере загрузки. И новые запросы могут отправляться до окончания получения HTML-файла, хотя заголовки к этому моменту уже получены.


        Затем, что HTTPS-трафик тоже может быть перехвачен. У меня есть глава по этому поводу, но я не стал включать её в статью, боясь вызвать ненужный спор.

        Сейчас идет тенденция к переводу всего на HTTPS. Например, Firefox показывает предупреждение при вводе пароля в форму на HTTP-странице. Следовательно, ваше самодельное шифрование избыточно, сильно усложняет протокол, тем более, как я понял, в первый раз токен все равно передается без шифрования.


        Веб-мастеру: минус несколько стандартных служебных страниц (регистрация, восстановления пароля, авторизации).

        И риск потери ключа при переустановке браузера. А от регистрации они не откажутся, так как им нужен email для рассылки спама.


  1. dth_apostle
    21.10.2019 17:30
    +2

    Создав при помощи мастер-ключа M персональный ключ K для домена D на одном устройстве, пользователь сможет создать тот же самый ключ K для домена D и на любом другом при помощи всё того же мастер-ключа M и единого алгоритма. Точнее это сделает не пользователь, а его браузер. При таком подходе пользователю достаточно распространить свой мастер ключ между всеми используемыми им браузерами и он разом «переносит все свои ключи» доменов. Заодно делает таким образом резервные копии.

    то есть вот захочу на работе или в недовернном окружении зайти на сайт habr.com, риски угона учетной записи к-рого для меня низки, — и «привет» — учетные данные на всех остальных сайтах приезжают скопом.
    Захотел воспользоваться другим браузером или приложением или скриптом — облом.
    А альтернативы — собственно, все то, что уже используется: Dash, OnePassword, LastPass или токен.


    1. BugM
      21.10.2019 21:28
      +3

      А уж какая красота для вирусов. Зеродей в браузере или винде и здравствуйте все аккаунты пользователя.


      1. KaminskyIlya Автор
        22.10.2019 06:32
        +1

        Для классических парольных менеджеров — риски аналогичные. Для «сохраненных» паролей в браузере — тоже самое. Надо понимать, что 100% защиты не существует. В главе 3, я даю рекомендации по защите ключевой информации.

        Мастер-ключ (который по факту просто случайное 256-битное число; не пароль пользователя!) может использоваться на сайтах, для которых вам не жалко потерять авторизацию (всякие одноразовые форумы, магазинчики). Мастер ключ дает вам 100% мобильности, но и повышенный риск. Я об этом в статье писал.

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


        1. BugM
          22.10.2019 10:13

          Как же вы далеки от реальности...


          Берём почту Гугла или Яндекса. И их же ССО завязанный на эту почту. Чувствительнее некуда. Вся жизнь там. А логиниться туда надо со всех своих устройств и иногда даже с чужих. Значит они будут под мастер ключем раскиданным по куче устройств. Кейс логина с чужого устройства я вообще не понимаю как реализовать.


          Смарткарта каждому? А зачем тогда все это? Есть же стандартные протоколы авторизации для них. Они хорошо работают в теории. На практике всем лень.


          Менеджер паролей дает возможность не ставить его на каждое устройство которым ты пользуешься. Да и сценарий логина с чужого устройства вполне решается.


          1. KaminskyIlya Автор
            23.10.2019 01:38

            То, что вы — активный пользователь сервисов яндекса, это ваше право. И не ваша вина, что яндекс смешивает «под одной крышей» сервисы с разным уровнем ответственности. Вот это плохо.
            И ваши опасения здесь понятны. С яндексом у вас нет выбора: только ССО. Вы не можете индивидуально сделать пароль к каждому сервису яндекса.
            В идеале, для каждого сервиса яндекса должна быть отдельная аутентификация.
            Яндекс тут решил свои проблемы, забив на ваши. Да простят меня сотрудники этой компании)

            Одно дело, когда вы компрометирует доступ в Яндекс.Маркет или Яндекс.Музыка. И другое дело, когда в Яндекс.Кошелек.
            Вы можете точно также войти в Яндекс.Почту с постороннего компьютера (арендованный ноутбук в интернет-кафе какого-нибудь отеля в теплых странах; и не зарекайтесь, что с вами это никогда не случится), и «спалить» свой пароль. Но этот пароль даст доступ ко всем сервисам яндекса от вашего имени. И эта проблема не только Яндекса. Это проблема всех крупных ССО: майл, гугл, да кто там ещё?

            Как вы, может быть, помните, технология кросс-доменной авторизации появилась как раз-таки как основной способ решения «парольной проблемы». ССО вас избавляет от необходимости иметь кучу учёток на разных сайтах и иметь кучу паролей к ним. ССО авторизует вас на сайтах, избавляя от необходимости в предварительной регистрации и аутентификации. Удобство — да. Но и риски велики. В информационной безопасности, к сожалению, в большинстве случаев чем удобнее, тем менее безопасно.

            Предлагаемый протокол решает «парольную проблему» иным способом. Он делает крайне легким генерацию аутентификационной информации и процедуру логина (вопрос пары кликов). А это значит, что основная и самая сложная проблема: «придумать уникальный пароль, запомнить его и хранить» — решается просто. При таком функционале ценность ССО значительно снижается. Оно уже не так необходимо. Я не призываю отказываться вообще от этой технологии. Но вы должны понимать, какие риски она влечет и почему.

            Теперь далее. В статье это говорится, но я повторюсь. Протокол определяет два способа формирования ключей: на базе мастер-ключа (который суть 256-битное случайно сгенерированное число); на базе индивидуального 256-битного ключа. Возможно, я не исключаю вариант, что стоит вернуться ещё и к третьему способу: формирование ключа домена на базе пароля пользователя. Необходимо решить вопрос с коллизиями паролей и стойкостью к брутфорсу. Но давайте для упрощения представим, что мы уже сделали это — ввели этот третий способ формирования ключа домена.
            Каждый из этих способов имет свои плюсы и минусы, а потому может применяться в следующих сценариях:

            1. Мастер-ключ. Средняя мобильность (необходимо предварительно распространить его среди ваших устройств). Наибольшая удобность при аутентификации и регистрации. Наименьшие риски при потере (вы ведь распространив по устройствам де-факто сделали его резервную копию). Наибольшие риски при компрометации. Риски к краже руткитами или при административном НСД к вашему компьютеру (их можно уменьшить). Поэтому используется только на сайтах с низким уровнем ответственности. Всякие форумы (где вам необходимо задать вопрос или скачать файл «только для зарегистрированных», а потом навсегда забыть этот сайт), блоги (где вы решили оставить комментарий) и т.п. чепуха. Ну скомпрометируете ключ — да и фиг с ним. Одноразовые доступы. Туда им и дорога.

            2. Индивидуальный ключ. Низкая мобильность. Меньшая удобность в использовании. Но наилучший уровень безопасности. Можно вынести на хранение в смарт-карты. Существуют риски утраты (сломалась смарт-карта). Предполагается к использованию на серьезных сайтах (личные кабинеты провайдеров, финансовых учреждений и т.п.) и только на доверенных устройствах. Предполагается, что такими ключами идентифицируется уже ваша личность (ибо серьезно). Если вы используете такой ключ «где попало» — вы сами себе враг. Мобильность можно обеспечить отчуждаемыми носителями (смарт-карты).

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

            Да, я знаю. Это выглядит сложно и запутано. Безопасность она всегда сложная. Но частично эта проблема решается хорошим UI-интерфейсом и обучением общей грамотности пользователей. Посмотрите сколько в интернете статей и заметок на тему того, какие пароли необходимо придумывать и как их правильно хранить.
            Вот ещё, например, такой UI-кейс. Браузер не позволит вам сделать ключ на базе мастер-ключа, если сайт имеет SSL-сертификат определенной категории (а такой сертификат может получить только крупная уважаемая компания; а Let's Encrypt, скажем такие не выдаст). Т.е. сделать ключ для Сбербанк.Онлайн от мастер-ключа у пользователя не получится. Но с этим необходимо осторожнее. Здесь должны подключиться спрециалисты по UI-интерфейсам.

            Вы не думайте, что придумав какой-то протокол, мы сразу сделаем мир лучше. Проблема должна решаться комплексно. Разработчики браузеров — решают свою часть. Веб-разработчики — свою часть. Разработчики библиотек протокола — свою часть. Попутный софт (nginx) — свою. Обучение пользователей соответствующими статьями — то же мера.

            А что касается Яндекса. Это плохо, что у них все завязано на passport.yandex.ru и без альтернативно. Само ССО удобно. Но отсутствие альтернативы — удручает. К сожалению, мой протокол не решает эту проблему. И эту проблему не решит никакой протокол.


            1. gecube
              23.10.2019 07:45

              Касательно SSO — я так понимаю, что компрометация яндекс.почты как сервиса не приводит к компрометации других сервисов Яндекса. Другой вопрос, что здесь появляется третья сторона — сам SSO-сервис, который и выступает гарантом идентичности пользователя. С тем же успехом это мог бы быть государственный УЦ или что-то подобное.


    1. KaminskyIlya Автор
      22.10.2019 06:34
      +1

      то есть вот захочу на работе или в недовернном окружении
      Ваше право. Но не храните все яйца в одной корзине.
      Dash, OnePassword, LastPass могут использоваться совместно с описанным протоколом. Он (протокол) не отменяет других средств защиты, а органично может их дополнить.


      1. dth_apostle
        22.10.2019 09:35

        Подскажите, как. Через ключ, на основании мастер-ключа?
        Обратите внимание, сейчас зависимость моих паролей на различных сайтах и мастер-ключа отсуствует:
        — я могу сменить мастер-ключ
        — я могу потерять мастер-ключ — и он обо мне ничего не скажет (без дополнительной информации — на каком ресурсе и с какой УЗ он использовался).
        В случае вашего мастер-ключа тот, кто завладел им, завладел *всеми* доступами.


        1. KaminskyIlya Автор
          23.10.2019 01:55

          Я думаю, Вам бы подошел ещё один вариант: генерация ключа домена на базе вашего секретного пароля. Необходимо решить вопрос с коллизиями паролей и стойкостью к брутфорсу.

          Ключ на базе вашего пароля (который у вас голове). Высочайшая мобильность. Решает проблему, когда нужно срочно зайти с чужого компьютера. Риски к клавиатурным шпионам. Но при этом взлом сайта не приводит к компрометации вашего пароля — самая главная фишка. Т.е. вы можете не бояться повторно использовать пароль на других сайтах.

          Удобно. Но необходимо помнить пароль. Вы можете завести себе пару-тройку таких очень «мощных» паролей для разной категории сайтов. Вполне приемлемое число.


  1. Xop
    21.10.2019 20:14
    +1

    А вы случайно не Decentralized Identifiers DID пытаетесь изобрести? Ну и вообще можно погуглить тему Self-Sovereign Identity...


  1. MKMatriX
    21.10.2019 21:39

    Идея хороша, но в текущем виде только для узкого круга лиц. И плоха для всех кто не сможет сколько-нибудь заморочиться. Для пользователей, которые записывают пароли на бумажки так и вовсе в текущем виде слишком сложна. Для внедрения либо придется создать отдельный браузер (а заодно убить html, а то надоел), где все по умолчанию будет максимально удобно, без анонимных сессий, и прочих гик-киберпанк фич по умолчанию, что позволит этим пользоваться огромному пласту далеких от понимания it людей, по причине большей удобности, чем текущая — гугл создай пароль — гугл запомни его. Либо делать очень вкусные фичи для молодого поколения, а там важна быстрая замена девайса, т.е. перенос мастер-ключа.

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


    1. KaminskyIlya Автор
      22.10.2019 06:42

      Для тех, кто часто меняет телефоны, может быть подойдет решение в виде SD-смарт-карты, которая и будет хранить мастер-ключ. Меняете телефон, переставляете карту. Вот только слотов под SD-карты у телефонов не так сказать, чтобы много.
      Протокол не накладывает ограничения на источник ключевой информации. Это может быть браузер, или некий security-proxy, или хардварный девайс.


  1. v1z
    21.10.2019 23:45
    -1

    Как мне кажется, в итоге всё придет к авторизации через биометрию на телефоне. Приложил палец или посмотрел в камеру — залогинился. Потерял телефон — заблокировал, купил новый, восстановился из бэкапа, никаких проблем.

    На данный момент не все устройства достаточно защищены, чтобы это стало массовым, но это лишь дело времени.


    1. Olanonymous
      22.10.2019 00:10
      +1

      Навскидку назову вот такие минусы биометрии:

      • Возможность разблокирования без желания пользователя — приложить к пальцу спящего человека, либо по настойчивой просьбе соответствующих органов (они и пароль так же попросить могут, но его всегда можно «забыть»).
      • Невозможность создания мультиаккаунта, в случае если вы не доверяете сервису и хотите каждый раз выглядеть новым пользователем. Пароль можно сколько раз угодно новый придумывать, а радужка\отпечаток\лицо у вас одни.
      • Тотальное распространение биометрии делает нас на шаг ближе к китайскому сценарию, переводя такой способ авторизации во что-то повседневное и привычное.
      • Необходимость наличия собственно устройства. Пароль можно держать хоть в голове, хоть на бумажке в тайнике, и вводить его на любом девайсе. Биометрия же требует как минимум, телефона с соответствующими датчиками.


      1. MrAloof
        22.10.2019 05:03

        Самое главное забыли — невозможность смены пароля (отпечатка) в случае его компроментации.
        Снять отпечаток иногда можно даже по качественному фото, на котором вы машете ручкой. После печать на пленке и к пальцу.
        Но это для физического получения самого "мастер ключа". Перехват авторизации по отпечатку отличается от перехвата пароля только сложностью (длиной) самого пароля. Или как вы себе представляете инфраструктуру авторизации?


    1. netricks
      22.10.2019 05:24

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


      1. ne_kotin
        22.10.2019 09:00

        Идея с биометрией плохо применима в интернете. Нужно передавать биометрические характеристики в сеть.

        зачем? при накате пальчика — он никуда не передается. и нужен только для локального контроля доступа.
        и передавать для аутентификации его тоже никуда не нужно.


        1. MrAloof
          22.10.2019 09:34

          А что передаётся? От "локального контроля доступа" к сайту? Опишите ваше видение аутентификации по биометрии...


          1. ne_kotin
            22.10.2019 11:35

            там классический challenge-response. а локально отпечатком контролируется доступ к ключу.


            1. MrAloof
              22.10.2019 11:55

              То есть биометрией вы авторизуете доступ к менеджеру паролей/ключей? Ну и чем в данном случае помогает биометрия то? Чем она лучше длинного пароля, узора кроме простоты ввода?


              1. ne_kotin
                22.10.2019 12:18

                Гм. Этим и хороша.


                1. MrAloof
                  22.10.2019 17:52

                  Ну и на этом достоинства и заканчиваются. То есть биометрия применима только как вторичная аутентификация. После аутентификации мастер-ключём ты авторизуешь считыватель биометрии на данном устройстве и далее аутентификация может через него.


                  1. ne_kotin
                    22.10.2019 18:20

                    Зачем так сложно? Ключ в криптопроцессоре. Криптопроцессор связан с считывателем отпечатка. Всё же уже придумано до вас, и даже реализовано в стандартных апишечках мобильных осей.


  1. gecube
    22.10.2019 00:16

    Отличный труд! Рекомендую не бросать, а довести до конца.


  1. Denai
    22.10.2019 03:00
    +1

    А если сайт доступен на нескольких доменах или вынужден переехать — пользователей долой?
    Как-то привязка именно к домену не очень здорово звучит


    1. KaminskyIlya Автор
      22.10.2019 06:43

      А вот про этот кейс я и забыл. Спасибо за замечание!


    1. KaminskyIlya Автор
      25.10.2019 06:28
      +1

      Про миграцию сайта с домена на домен описал здесь habr.com/ru/post/472310/#comment_20801402 (предварительная версия).

      Для сайтов, которые работают в группе, а также для сайта, который доступен на нескольких доменах, можно применить технику меж-доменной и кросс-доменной идентификации пользователя согласно протоколу. Допускаю, что в некоторых случаях, это может быть накладным для разработчиков. Надо прорабатывать конкретные случаи и вырабатывать рекомендации с готовыми примерами «под ключ».

      В любом случае, Ваше замечание я принял в работу.

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


  1. Cerberuser
    22.10.2019 05:11

    В разделе про кросс-сайтовые переходы поймал себя на такой мысли. Допустим, site1.ru загрузил скрипт с site2.ru. Этот скрипт создал ссылку, ведущую на site2.ru. С точки зрения протокола, она будет считаться ссылкой на внешний сайт, созданной внешним сайтом. Но есть ли какие-то препятствия к тому, чтобы считать её "доверенной" (в некотором смысле, конечно)? Ведь site2.ru её сам для себя сделал, никакой evil.ru, в том числе и site1.ru, в этом не участвовал.


    1. KaminskyIlya Автор
      22.10.2019 06:53
      +1

      С точки зрения протокола, она будет считаться ссылкой на внешний сайт, созданной внешним сайтом.
      все верно.
      Но есть ли какие-то препятствия к тому, чтобы считать её «доверенной»
      Есть. site1.ru не может ручаться за действия скрипта с сайта site2.ru, который по факту может принадлежать сторонней организации. Это небезопасная операция. Если у вас есть пример ситуации, где это реально нужно, давайте конкретный пример, обсудим.

      Я приведу свой. Сейчас на страницах Сбербанк-Онлайн внедрена Яндекс.Метрика. Сторонний скрипт от компании, с которой у Сбербенка нет никаких юридических договоренностей, вроде NDA. Кто видел в действии ВебВизор метрики, тот знает, что она записывает реально «все» ваши действия на сайте: движения мышкой, какой текст выделяли, что и куда вводили. Естественно туда утекает и ваш логин/пароль.
      Каждый счетчик метрики имеет уникальный номер. Сотрудникам Яндекса не составляет проблем подгружать именно на страницу Сбербанк-Онлайна модифицированную версию метрики, которая делает «дополнительную» работу.
      Я когда проектировал прокол, особо учитывал это случай.


      1. Cerberuser
        22.10.2019 07:47

        Я говорил про случай, когда пользователь явно переходит по сгенерированной ссылке — к примеру, представим, что на Хабре (он здесь в роли site2.ru) выложили скрипт, который можно вставить на личную страницу (site1.ru), передать ему номер статьи, и он сгенерирует preview статьи и ссылку на неё (не реальный кейс, естественно, но достаточно наглядный). Но да, я упустил тот факт, что в самой сгенерированной ссылке может потенциально храниться произвольная информация, в том числе и та, которая с site1.ru утекать не должна.


      1. Areso
        22.10.2019 12:50

        class=«ym-disable-keys» позволяет отключать запись значений полей в ЯМ


  1. DenisSel
    22.10.2019 06:53

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


    1. KaminskyIlya Автор
      22.10.2019 06:56
      +1

      Это то, чего я больше боюсь. Описанный протокол дает нам — пользователям, слишком много свободы.


    1. Cerberuser
      22.10.2019 07:48

      Владельцы сайтов, браузеров, соц сетей кровно заинтересованы в сборе информации о посетителях

      А браузеров-то каким образом? Ну, кроме Гугла, которому вообще нужно знать всё, независимо от браузера.


      1. gecube
        22.10.2019 09:39

        Ну, любая компания хочет улучшать свой продукт. Для этого сбор информации от клиента практически необходим — начиная от конфигурации, кончая кейсами применения.
        Почему браузеров? Потому что большинство приложений сейчас уже в вебе — раз, два — интернет очень прочно проник в нашу жизнь и без него никуда. А браузер — это по сути окошко в Интернет.


        1. Cerberuser
          22.10.2019 09:41

          Так кто мешает эту информацию собирать с сохранением упомянутой вами анонимности в сети? Кроме жадности создателей, разумеется, но опять-таки, браузеры делает не только Гугл.


          1. gecube
            22.10.2019 10:06

            Извините, не понимаю Вашей позиции.
            Так создателям (владельцам) браузеров нужно собирать информацию или нет? Мое мнение — да.
            Касательно анонимности — как только объем данных переваливает за какой-то предел, то очень легко становится даже анонимные данные собрать в систему. Ну, представьте себе такой пример. Вы знаете из источника А, что в стране есть 10 богатых людей. А из источника Б получаете список транзакций, только очищенный от имен (они там обфусцированы). Но при сопоставлении списка А и Б легко можно найти транзакции именно людей из списка А. А далее уже можно попробовать установить личность каждого.
            Я уж не говорю о том, что любой мало-мальски крупный сайт будет пытаться поставить свою куку или супер-куку или вообще идентифицировать пользователя пикселом.


            1. Cerberuser
              22.10.2019 10:43

              Я не высказываю свою позицию, прошу прощения, если показалось так. Я пытаюсь понять, почему браузеры были перечислены среди "собирающих данные" наряду с соцсетями, хотя, по идее, собирать им требуется существенно меньше.


  1. wafwaftech
    22.10.2019 06:54

    Защиты от XSS не будет. Будет защита от некоторого вида xss при определенном векторе эксплуатации, при прямом векторе эксплуатации активных xss или же хранимых xss никакой разницы не будет. Если идея в том, что нельзя украсть куки — никто не мешает атакующему не красть ваши "токены" а сделать все на месте вашими же руками, даже готвоые решения есть, например BEEF


    1. KaminskyIlya Автор
      22.10.2019 06:55
      +1

      Вы правы. В статье я об этом писал. И не раз. Раздел 4. Также я указывал, что 100% защиты не дает. Но существенно уменьшает риски эксплуатации.


  1. amakhrov
    22.10.2019 09:53

    Что предлагает новый протокол?
    С точки зрения конечного пользователя:
    Сайт должен запоминать и узнавать посетителя без какого-либо ввода данных со стороны пользователя; сайт должен узнавать вас как в пределах сессии, так и между разными сессиями. Никаких cookie, паролей и регистраций.

    Элементарно. При первом заходе сервер генерит PHPSESSIONID (или что там у них), устанавливает куки. Пользователь идентифицирован.


    При этом разные сайты не должны получать возможность взаимно однозначно идентифицировать одного и того же посетителя, получая возможность отслеживать его активность на этих и других сайтах.

    Запрещаем 3rd party cookies в браузере. Или имелось в виду что-то другое?


    Пользователь должен получить возможность «забыть любой сайт» в любое время; и сайт забудет пользователя. Должна быть возможность предоставления прав сайту запомнить клиента по инициативе клиента (без навязчивых popup).

    Куки-менеджер.


    Пользователь должен получить возможность безопасной миграции своей виртуальной личности между разными устройствами и браузерами (если ему это нужно), чтобы иметь единую авторизацию на любимых сайтах.

    Синхронизируем директорию с куками через дропбокс. Или копируем вручную. В любом случае, способ синхронизации файлов — это что-то внешнее для протокола идентификации пользователей. Какой резон упаковывать все это в один стандарт?


    Или я пропустил какие-то ключевые требования к новому протоколу, которые не удовлетворяются куками?


    1. gecube
      22.10.2019 10:11

      Элементарно. Автор перевернул с ног на голову, как я понял. Не сервер ставит куку клиенту, а клиент рапортует серверу, что он это он. Т.е. это обязанность сервера матчить токен со своей внутренней базой. С другой стороны… Это очень похоже на PKI с раздачей сертификатов всем клиентам. Но любой PKI — это централизация. А посыл автора, если я не ошибаюсь, был именно в создании двухзвенной структуры без третьего доверенного лица...


      1. amakhrov
        22.10.2019 18:46

        Не сервер ставит куку клиенту, а клиент рапортует серверу, что он это он

        Это я понял, да. Но это особенности реализации. А вот какую задачу/проблему должен решить этот подход с клиентской генерацией айди, мне и неясно.


        1. KaminskyIlya Автор
          23.10.2019 01:21

          ID (он же токен) выполняет для сайта роль и логина, и пароля. И при этом нивелирует риски клиента при своей компрометации. Защищен при передаче.

          Но это особенности реализации.
          Эта особенность кардинально всё меняет.
          1. Клиент получает большую независимость от сервера. Клиент сам решает какой ID в какой ситуации слать. По какому алгоритму вычислять. Это дает эффектные способы защиты от известных сетевых атак.

          Стандартизация алгоритмов формирования токенов защищает пользователя от кривых реализаций. Браузер не сможет пойти мимо стандарта. Иначе это вызовет несовместимость с другими браузерами.
          Браузер не сможет использовать искусственно ослабленные ключи, иначе это вызовет коллизии у разных пользователей на стороне сервера. Ну и не совместимость, опять же. Спалится тут же.

          Что значит, ослабленные ключи?
          Например, браузер генерирует ключи, у которых только 40 бит случайны, а остальные 216 — линейная комбинация из этих 40-ка, вычисленная хитрым недокументированным образом.


          1. amakhrov
            23.10.2019 01:37

            Клиент получает большую независимость от сервера

            А какую из проблем, перечисленных в начале статьи, это решает?


            Я вот в комменте выше процитировал проблемы, которые вы привели в статье. "Генерация сессии на стороне сервера" там не фигурировала. И не может фигурировать — потому что пользователю это неважно.


            А насчет второго пункта — вообще мимо кассы. Какая разница с точки зрения вебмастера — хранить в базе пароль или токен? Точно так же его могут небезопасно хранить и допустить утечку.


            1. KaminskyIlya Автор
              23.10.2019 02:03

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

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


              1. amakhrov
                23.10.2019 02:18

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


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


                1. KaminskyIlya Автор
                  23.10.2019 05:33

                  Эмм. Как бы вся статья об этом. Или?


                  1. amakhrov
                    23.10.2019 09:36

                    Писал-писал ответ, перечитывал-перечитывал текст.


                    Если отбросить детали про соль (кмк, ненужные при наличии https), то получился аналог Authorization: Bearer .

                    Суть инновации, как я ее вижу
                    1) Создание стандартного протокола регистрации (ну и замена токена бонусом). Упрощая: если сервер не узнает токен из заголовка, он создает новую учетную запись с этим токеном.


                    Постоянный/временный ключ, даже само наличие мастер-ключа в принципе — это уже вопрос удобства пользователей. Браузеры могут решать его как угодно. Хоть сторонними плагинами (при наличии минимального api в браузере для управления токенами). На взаимодействие между сервером и клиентом это никак не влияет.


                    Я правильно понял?


                    1. KaminskyIlya Автор
                      24.10.2019 06:25

                      Всё верно.
                      (Соль не спешите отбрасывать, но вы правы — это детали реализации).

                      Еще можно добавить: самоидентификация клиента; полный отказ от трехзвенной структуры.


            1. KaminskyIlya Автор
              23.10.2019 04:50

              А какую из проблем, перечисленных в начале статьи, это решает?

              Защита от трекинга, XSS, CSRF. Клиент получает возможность манипулировать своим ID в зависимости от контекста и формируемых запросов. Менять на лету. Если сервер вам назначил ID, вы уже не можете это изменять. И не важно как именно он передается: в куках или иных заголовках.

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


              1. amakhrov
                23.10.2019 05:26

                Защита от трекинга

                Браузеры уже сейчас умеют блокировать сторонние куки


                XSS

                Да ну. Вы же и пишете в статье, что реальный XSS, через инъекцию в страницу, так не блокируется. XSS предотвращается только экранированием / фильтрацией данных, вставляемых в страницу. Никакие токены тут не помогут.


                CSRF

                Допустим. Хотя, если бы браузеры блокировали куки в запросах со сторонних доменов, новый протокол бы и не понадобился. Но обратная совместимость важнее. Опять же, можно было изобрести и спец. флаг к кукиз для этого — гораздо проще в реализации и полностью обратно совместимо.


                В остатке имеем: новый протокол решает проблему CSRF. В целом, неплохо — но впечатляет уже меньше.


                1. amakhrov
                  23.10.2019 09:38

                  если бы браузеры блокировали куки в запросах со сторонних доменов

                  Посыпаю голову пеплом. Все уже придумали до нас, в 14м веке.
                  https://www.owasp.org/index.php/SameSite


        1. KaminskyIlya Автор
          24.10.2019 06:58

          Ещё один момент, про который я забыл. К вопросу: «Зачем клиенту самому себя идентифицировать?»

          Если сервер назначает нам идентификатор, чтобы отслеживать наши запросы среди потока других пользователей — это слежка. Налипает на европейский GDPR.
          Ведь по-сути, сервер не спрашивая, помечает вас. О чем уже уведомляет пост-фактум. Или не уведомляет — но тогда это нарушение.

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

          Т.е. сейчас вас просто уведомляют: «Чувак, мы за тобой следим. Расслабься». Единственное, что вы можете сделать — согласиться с этим или покинуть сайт. А если очень надо?

          Хотя в статье этого не написано, но ни кто не мешает браузеру менять ключ/токен при каждом запросе или после серии запросов (типа автосброс сессии после таймаута; режим для параноиков).

          Т.е. протокол помогает серверу выполнить требования закона и решить свою задачу «трекинга». Это к вопросу: какая выгода у владельцев сайта?

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


          1. amakhrov
            24.10.2019 19:42

            Вы неверно трактуете проблему :)
            Никто не мешает браузерам отключить куки вообще. Или отключить для конкретных сайтов. Генерация идентификатора на стороне клиента для этого не нужна.


            А с точки зрения закона (GDPR) — почти все делают неправильно. Сайт не имеет права просто сказать "чувак, за тобой следят — смирись или вали". Сайт обязан предоставить ссылку на детальное описание всех кук (или любых других идентификаторов — неверно тут цепляться только за термин "куки)", используемых для трекинга. И предоставить возможность согласиться или отказаться от них (и возможность поменять свое решение позже).


            Ну и да, уведомлять о "технических" куках (напр, айди сессии), требуемых для предоставления услуги — не обязательно.


        1. KaminskyIlya Автор
          24.10.2019 07:17

          Когда я начинал проектировать протокол я задался вопросом: «А почему назначать идентификатор клиенту всегда была прерогативой сервера?».

          Для себя я вывел следующие ответы:
          1.Так исторически сложилось (если не сервер — то кто? Во времена зарождения Интернета большую часть работы выполнял сервер. Клиент даже javascript не имел. О безопасности никто ещё не думал).
          2. Клиенты могут «пересечься» идентификаторами.
          3. Если клиент назначит себе сам идентификатор и будет использовать его на всех сайтах — это идеальная схема, чтобы за ним следить.

          Что будет, если эту схему поменять? И можно ли её поменять?
          1. Почему бы и нет. Тогда мы получаем большую свободу и право менять свой идентификатор как нам вздумается.
          2. Попробуем использовать сильную криптографию, и большие идентификаторы. 256 бит мало? Ок. будем 512. Здесь необходимо экспертам по криптографии оценить вероятность коллизий SHA.
          3. Сделаем математическую зависимость идентификатора клиента от домена сайта.

          О, у меня раньше в черновике было такое: намеренная генерация браузером ослабленных 16-битных идентификаторов, хитрым нелинейным преобразованием от ключа браузера, представленных как 256-битные. Для гарантированной анонимизации посетителя. Идентификаторы, которые намеренно могут вызвать коллизии на стороне сервера. Чтобы у баннерных сетей даже желание не возникало использовать ваши токены для слежки. Но, просчитав, варианты, отказался от этого.


          1. amakhrov
            24.10.2019 19:57

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


    1. s-n-ushakov
      22.10.2019 14:31

      И я по правде тоже не понял, для какой из декларированных задач куков не хватило…
      Если исходить из тезиса, что главное зло — в логинах с паролями — ну, тогда просто аутентифицировать / идентифицировать посетителя теми средствами, которые нравятся.
      Ну а чем куки плохи для сохранения информации о сеансе — непонятно...


      1. KaminskyIlya Автор
        23.10.2019 00:40

        Зачем нужен SESSIONID, когда ту же задачу решает CSI-Token? Тем более cookie имеют известные проблемы с безопасностью. Особенно при передаче по HTTP (хотя HTTPS тоже вскрывается). CSI-Token не только идентифицирует пользователя, но и делает это более надежным способом: защита от компрометации, от CSRF, XSS и трекинга. Я оговорюсь, что 100% защиты не существует. Но существенное уменьшение вероятности эксплуатации известных атак — хорошее преимущество.


        1. lair
          23.10.2019 10:39

          Зачем нужен SESSIONID, когда ту же задачу решает CSI-Token?

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


          Как, кстати, предлагается решать такую задачу?


          1. KaminskyIlya Автор
            24.10.2019 06:21

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


            1. lair
              24.10.2019 10:54

              Пример номер 1: есть веб-приложения (ну, например, учетные системы), которые привязывают к сессии всякое присходящее — текущие выбранные объекты, измененное состояние. Соответственно, иногда пользователь хочет вести две активности одновременно, и тогда он может открыть два (разных) браузера (или браузер + private mode) и иметь две сессии.


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


              1. user_man
                24.10.2019 12:21

                Два устройства — два ключа. Не понимаю, как здесь можно не видеть решение.

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


                1. lair
                  24.10.2019 12:24

                  Два устройства — два ключа. Не понимаю, как здесь можно не видеть решение

                  … и как между ними при этом установить соответствие? Пользователь-то один.


                  1. user_man
                    24.10.2019 13:27

                    Синхронизация ключей на удалённых устройствах решается элементарно — на любой сервис хранения данных заливается шифрованный ключ. Всё. Далее ключ качается, по мере необходимости.

                    Вообще, любая проблема протокола решается просто — пользователь делает выбор. Либо он раб, либо он свободен. И всё. Тогда вариант «не раб» легко обойдёт все проблемы. Хотя да, ради свободы нужно будет чуть-чуть (реально на копейки) напрячься. Ну так рабы же не мы. Или как вы на это смотрите?


      1. KaminskyIlya Автор
        23.10.2019 02:08

        чем куки плохи для сохранения информации

        Сама реализация кук и огромные исторические пробелы в их безопасности…
        Вам точно удобно хранить данные пользователя (ну кроме как ID сеанса) в куках? Интерфейс работы с печеньками очень древний и ущербный. Разработчики предпочитают использовать для этих целей localStorage/sessionStorage и локальную базу.


        1. amakhrov
          23.10.2019 02:23

          Сама реализация кук

          А есть конкретный пример?
          Проблема HTTP — это проблема HTTP. Незашифрованный канал раскрывает все данные, а не только сессионную куку. Не знаю, зачем про это говорить в 2019.


          Вам точно удобно хранить данные пользователя (ну кроме как ID сеанса) в куках

          А причем тут хранение данных пользователя вообще? В вашем автоматически сгенерированном токене тоже нет данных пользователя же. Данные пользователя храним в базе на сервере (а не в какой-то там локальной базе)


          1. KaminskyIlya Автор
            23.10.2019 05:39

            А причем тут хранение данных пользователя в
            я просто не так понял Вашу формулировку выше.


        1. s-n-ushakov
          23.10.2019 09:57

          Сама реализация кук и огромные исторические пробелы в их безопасности…

          И я не понял: а какие проблемы безопасности есть у куков? Куки — это просто очень низкоуровневый механизм сохранения состояния в цепочке взаимодействий браузера и сервера. Я по правде не вижу там никакой безопасности.


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


          Вам точно удобно хранить данные пользователя (ну кроме как ID сеанса) в куках?

          Так а вроде никто и не заставляет… Можно хранить, и можно не хранить :) Куки — очень низкоуровневые и согласны на всё :) Что, где и как хранить — это ж разработчик этажом выше решает...


          использовать для этих целей localStorage/sessionStorage и локальную базу

          На мой взгляд, localStorage и sessionStorage решают хоть и близкие, но другие задачи. Они все работают на стороне клиента. Они не реализуют никакого взаимодействия сами по себе. Хотя гибкости и добавляют конечно...


          Если подойти конструктивно: букв в тексте, вынесенном на обсуждение, получилось действительно много :) И мне лично, наверно, всё стало бы понятнее, если бы у текста появилась более развитая преамбула с аргументированной критикой того, что сейчас есть. С чуть более подробной классификацией рассматриваемых сценариев и их недостатков...


    1. KaminskyIlya Автор
      23.10.2019 05:31

      Какой резон упаковывать все это в один стандарт?


      Но стандарт и не упаковывает вопрос хранения и синхронизации файлов. И хотя подобное описано в главе 3 «Рекомендации по безопасности», там же под спойлер я вынес оговорку, что эта глава не является частью протокола и носит рекомендательный характер. Про синхронизацию ключей я пишу в разделе «Мобильность учетных записей». Там же под спойлер я вынес альтернативы. Описал плюсы и минусы. Оценил риски. Эту тему хранения ключей ещё развивать и развивать. Но это не должно быть частью стандарта. Максимум — рекомендациями или отдельным под-стандартом. Тут я согласен с Вами.

      Более того, учитывая ценное замечание user_man, протокол можно и нужно разбивать на слои, каждый со своим четким уровнем ответственности. Один отвечает за хранение ключевой информации, второй за выполнение криптографических функций (расчеты токенов, ключей, генерация соли), третий — за формирование параметров исполнения запроса (Recipient/Sender/Context), четвертый — за интерпретацию токенов (серверный уровень). Но это предварительные идеи по улучшению предложенной схемы. Пока не цепляйтесь к этому абзацу.

      Или я пропустил какие-то ключевые требования к новому протоколу, которые не удовлетворяются куками?

      1. Сессионные куки имеют короткий сроки жизни.
      2. Постоянные куки могут иметь большой срок хранения. Но также могут быть случайно удалены при чистке кэша браузера. Ситуация типична, когда необходимо решить проблему с одним из сайтов, саппорт которого рекомендует «почистить куки и кэш», пользователь решает — да нафик всё почищу! И лишается всех кэшированных доступов.
      3. Куки необходимо передавать с флагом HttpOnly, чтобы не были доступны скриптам. Есть вероятность, что разработчик забудет включить этот флаг (хотя сейчас это решают фреймворки).
      Синхронизируем директорию с куками через дропбокс. Или копируем вручную. В любом случае, способ синхронизации файлов — это что-то внешнее для протокола идентификации пользователей.

      4. Куки лежат только в файле. И доступны для НСД. Но опять же, стараюсь не лукавить, место хранения ключей доменов не специфицируется протоколом. Только рекомендации. Ключи доменов могут находиться на отчуждаемых носителях. Ключи домена от вашего пароля — только у вас в голове (по объективным причинам). Мастер-ключ, да — на диске.

      «Ключи домена от вашего пароля» — этого не было в статье. Но, как вариант, возможен возврат к этой схеме.

      Вообще, очень подробно все недостатки куки кратко рассмотрены в хорошей статье ru.wikipedia.org/wiki/Cookie. Но, я почему-то уверен, что Вы хорошо знакомы с её содержанием.


      1. amakhrov
        23.10.2019 08:29

        Срок жизни куки

        можно хоть вечными сделать


        Случайно удалены

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


        Куки необходимо передавать с флагом HttpOnly

        Наконец по существу. Но честно говоря, последний раз вживую я видел сессионную куку без HttpOnly лет эдак 10 назад. Secure — из той же области.


        все недостатки куки кратко рассмотрены в хорошей статье

        Все недостатки куки там можно разделить на 2 категории: 1) не относящиеся к сессионным кукам (иначе говоря — используем куки как хранилище данных) и 2) равным образом применимым к вашим токенам (напр., "неточная идентификация").


        1. KaminskyIlya Автор
          24.10.2019 07:26

          Наконец по существу.

          А то, что куки лежат в файле и доступны вирусам, ну право, вас не смущает? И место это известно и нет возможности его поменять.

          Меня тут выше «размотали», за то что мастер-ключ я предложил хранить на диске. При том, что я предлагал мастер-ключ использовать только на сайтах с «пониженной социальной ответственностью». А вы тут такое предлагаете!


          1. amakhrov
            24.10.2019 19:49

            что куки лежат в файле… вас не смущает

            Нет, не смущает. Способ хранения кук никак не связан с протоколом общения между клиентом и сервером. И, собственно, он не регламентируется никаким стандартом, насколько мне известно. Хоть в блокчейне храните.


            Дело в том, что вы в одной статье объединили несколько независимых решений, направленных на решение разных проблем.


            Все мои комменты тут и выше касаются только протокола сервер-клиент.


            1. KaminskyIlya Автор
              25.10.2019 00:11

              объединили несколько независимых решений, направленных на решение разных проблем
              декомпозицию проводить однозначно надо!


        1. KaminskyIlya Автор
          24.10.2019 07:33

          недостатки куки… равным образом применимым к вашим токенам

          Если вы заметили какой-то существенный недостаток токенов, который я не заметил, — поделитесь. Буду благодарен.

          Про многосеансовость мне уже писали. Про смену домена сайтом — тоже. Я принял к сведению. Уже обдумываю варианты.


  1. Bedal
    22.10.2019 14:54

    Я попытался не только описать эти правила, но объяснить зачем они такие, да на конкретных примерах, да с картинками. Это перегрузило и так не простую статью.
    Можно было спрятать в спойлеры.


  1. MathObsessed
    23.10.2019 00:33

    CSI — плохое название. Уже используется

    Container Storage Interface (CSI) is an initiative to unify the storage interface of Container Orchestrator Systems (COs) like Kubernetes, Mesos, Docker swarm, cloud foundry, etc.


    1. gecube
      23.10.2019 07:49

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


  1. Lestok
    23.10.2019 00:34

    … А что не так с паролями?...
    В настоящее время пароль уже не является средством, достаточным для надёжной защиты, каким бы сложным он ни был!

    Такой вывод основывается на огромных объёмах данных корпорации Microsoft, при ежедневном использовании облачных сервисов которой фиксируется порядка 300 миллионов попыток несанкционированного входа в аккаунты.

    И лишь многофакторная аутентификация делает почти все эти попытки бесполезными, потому что она защищает от 99,9% всех попыток взлома.

    Поэтому пользователь, защищающий свои учётные записи с помощью одного лишь пароля, может с тем же успехом считать, что не защищает их вовсе!

    Источник


    1. gecube
      23.10.2019 07:50

      Согласен — нет пароля — нет проблем.
      Таким образом нужно — "честный" 2ФА и желательно какой-то разделяемый секрет на базе вычислений, а не просто парольная фраза.


  1. lair
    24.10.2019 11:03
    +2

    Еще несколько вопросов.


    1. Что делать сайтам, живущим на одном домене, но по разным путям? (https://some.com/path1, https://some.com/path2). Помимо разработки, это еще бывает, скажем, в AWS Api Gateway при развертывании custom domains.


    2. Что делать веб-сервисам и веб-сайтам, которые доступны на более чем одном адресе одновременно (или адрес которых может меняться)? (самый простой пример: https://some.com и https://api.some.com)


    3. Что делать при делегировании доступа, когда один сервис обращается к другому на основании credentials пользователя, полученных первым сервисом?


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



    1. KaminskyIlya Автор
      24.10.2019 23:52
      +1

      Вот это реально крутые вопросы! А я призадумался.
      Благодарю за это.


    1. KaminskyIlya Автор
      24.10.2019 23:57
      +1

      Дополню недостатки:
      1. проблемы при смене сайтом доменного имени
      2. большая запутанность, смешение зон ответственности
      3. не описаны понятные правила участников взаимодействия

      Буду делать рефакторинг с учетом высказанных замечаний. Декомпозиция — однозначно.


    1. gecube
      25.10.2019 00:24

      Первая проблема она и для куков в общем-то имеет место быть… Не вижу в этой проблеме ничего уникального. Касательно токена… Ну… э… Не знаю.


      1. gecube
        25.10.2019 08:05

        даже более того — насколько я помню (я не очень хороший вэб-разраб), что при определенных условиях, если у нас есть приложения на поддоменах a.b.TLD и c.d.TLD, то они могут видеть свои куки и общие куки для домена b.TLD.
        И там еще целая эпопея была, чтобы отличать двухкомпонентные TLD вроде co.uk от субдоменов.


    1. KaminskyIlya Автор
      25.10.2019 06:14

      Смена домена сайтом. Проблема: слетает авторизация пользователей.
      Пусть был habrahabr.ru. Стал habr.com.

      Создаем новый ключ для нового домена habr.com-key. Способы любые: копия, экспорт, random, от мастера — на выбор пользователя. Сообщаем браузеру, что сайт поменял домен.

      Браузер делает следующее:
      A1. заходит на habr.com, но формирует токен по правилу от имени habrahabr.ru:

      T_1 = HMAC_{habrahabr.ru-key}( habrahabr.ru | habrahabr.ru | habrahabr.ru )
      сайт узнает и авторизует пользователя, т.к. такой токен есть в его базе

      A2. генерирует новый «правильный» токен
      T_2 = HMAC_{habr.com-key} ( habr.com | habr.com | habr.com )

      A3. делает легальную перерегистрацию токенов (предусмотренную протоколом):
      CSI-Token: T_1; Changed-To: T_2

      A4. если сайт принял новый токен (а оснований для отказа у него нет), то он шлет CSI-Token-Action: success, как и предусматривает протокол.
      А5. В дальнейшем, используем токен T_2, как и предписывает протокол

      Под словом «заходит» можно понимать отправку запросов методом GET/HEAD на идексную страницу домена. Как пример. Вводить «специальные» страницы для таких процедур крайне не хочется.


    1. KaminskyIlya Автор
      25.10.2019 06:46

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

      На сайте делается функционал: предоставить доступ приложению от имени пользователя. Предлагается выбрать набор предоставляемых приложению прав. Для приложения генерируется API-ключ. На мой взгляд, так будет более правильно.

      При таком подходе:
      1. получаем контроль над доступами приложения (это может быть чья-то сторонняя разработка; не разработчиков сайта)
      2. не компрометируем ключи/токены пользователя


    1. KaminskyIlya Автор
      25.10.2019 07:50

      Что делать при делегировании доступа, когда один сервис обращается к другому на основании credentials пользователя, полученных первым сервисом?

      Если сервис будет сам обращаться на основании credentials пользователя (без участия последнего; т.е. пользователь покинул сайт сервиса, а тот работает) — поступаем как и с приложением: генерируем для него API-ключ доступа. За генерацию отвечает «другой» сервис. А за распространение API ключа — пользователь, например. Так и безопаснее. И ключ не палим. И права можно выставить. API-ключ передать можно разными способами.

      Если сервис, принадлежащий домену S1, будет обращаться к сервису S2 в результате действий пользователя на S1 — применяем технику ССО.


  1. KaminskyIlya Автор
    25.10.2019 06:36
    +1

    Что делать сайтам, живущим на одном домене, но по разным путям?

    Здесь получается, что даже если пользователь и работает с приложением A1 под учеткой U1, а в приложении A2 под U2, всё-равно, каждый из этих приложений может легко получать доступы от соседнего профиля. Ну, хотя бы, в силу того, что этим «соседним» приложениям доступны все куки пользователя со своего домена.

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

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

    Подойдет такое решение? Или я не Вас правильно понял?


  1. KaminskyIlya Автор
    25.10.2019 06:39

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