Двухфакторая аутентификация
Всё прочитанное вами в первой части касалось идентификации на основании того, что знает запрашивающий. Он знает свой адрес электронной почты, знает, как получить к ней доступ (т.е. знает свой пароль от электронной почты) и знает ответы на секретные вопросы.
«Знание» считается одним фактором аутентификации; двумя другими распространёнными факторами являются то, что у вас есть, например, физическое устройство, и то, кем вы являетесь, например, отпечатки пальцев или сетчатка глаза.
В большинстве случаев выполнение биологической идентификации малореализуемо, особенно когда мы говорим о безопасности веб-приложений, поэтому при двухфакторой аутентификации (two factor authentication, 2FA) обычно используется второй атрибут — «то, что у вас есть». Одним из популярных вариантов этого второго фактора является физический токен, например, RSA SecurID:
Физический токен часто используется для аутентификации в корпоративных VPN и финансовых сервисах. Для аутентификации в сервисе нужно использовать и пароль, и код на токене (который часто изменяется) в сочетании с PIN. Теоретически, для идентификации нападающий должен знать пароль, иметь токен, а также знать PIN токена. В сценарии сброса пароля сам пароль очевидно неизвестен, однако обладание токеном можно использовать для подтверждения владения аккаунтом. Разумеется, как и в случае с любой реализацией защиты, это не обеспечивает «защиту от дурака», но определённо повышает барьер входа.
Одна из основных проблем такого подхода — стоимость и логистика реализации; мы говорим о передаче физических устройств каждому клиенту и об обучении их новому процессу. Кроме того, пользователям нужно иметь с собой устройство, что в случае физического токена бывает не всегда. Ещё один вариант — реализовать второй фактор аутентификации с помощью SMS, которое в случае 2FA может служить подтверждением того, что человек, выполняющий процесс сброса, имеет мобильный телефон владельца аккаунта. Вот как это делает Google:
Также необходимо включить двухэтапную верификацию, но это означает, что при следующем сбросе пароля ваш мобильный телефон может стать вторым фактором аутентификации. Позвольте мне продемонстрировать это на примере своего iPhone по причинам, которые скоро станут понятными:
После идентификации адреса электронной почты аккаунта Google определяет, что была включена 2FA и мы можем сбросить аккаунт с помощью верификации, которая передаётся через SMS на мобильный телефон владельца аккаунта:
Теперь нам нужно выбрать начало процесса сброса:
Это действие приводит к отправке электронного письма на зарегистрированный адрес:
Это письмо содержит URL сброса:
При выполнении доступа к URL сброса отправляется SMS и веб-сайт просит его ввести:
Вот это SMS:
После ввода его в браузер мы возвращаемся на территорию классического сброса пароля:
Вероятно, это кажется слегка многословным, и так и есть, но форма подтверждает, что выполняющий сброс человек имеет доступ к адресу электронной почты и мобильному телефону владельца аккаунта. Но это может быть в девять раз более безопасным, чем сброс пароля только через электронную почту. Однако существуют проблемы…
Проблема связана со смартфонами. Показанное ниже устройство может удостоверять только один фактор аутентификации — оно способно получать SMS, но не электронную почту:
Однако вот это устройство может получать SMS и получать письма о сбросе пароля:
Проблема в том, что мы рассматриваем электронную почту как первый фактор аутентификации, а SMS (или даже генерирующее токены приложение) как второй, но сегодня они объединены в одном устройстве. Разумеется, это означает, что если кто-то доберётся до вашего смартфона, то всё это удобство сведётся к тому, что мы снова вернулись к одному каналу; этот второй фактор «то, то у вас есть» означает, что у вас есть и первый фактор. И всё это защищено одним PIN из четырёх цифр… если у телефона вообще есть PIN и он был заблокирован.
Да, реализованная Google функция 2FA совершенно точно обеспечивает дополнительную защиту, но она не защищена «от дурака», и совершенно точно не зависит от двух полностью автономных каналов.
Сброс по имени пользователя против сброса по адресу электронной почты
Нужно ли разрешать сброс только по адресу электронной почты? Или пользователь должен иметь возможность выполнить сброс и по имени? Проблема сброса по имени пользователя заключается в том, что нет никакого способа уведомить пользователя о неправильном имени пользователя, не раскрывая того, что кто-то другой может иметь аккаунт с этим именем. В предыдущем разделе сброс по электронной почте гарантировал, что законный владелец этой электронной почты всегда будет получать обратную связь без публичного раскрытия его существования в системе. При помощи только имени пользователя это сделать невозможно.
Поэтому ответ краток: только электронная почта. Если вы попытаетесь выполнить сброс только с помощью имени пользователя, то будут возникать случаи, когда пользователь будет недоумевать, что же случилось, или вы будете раскрывать существование аккаунтов. Да, это всего лишь имя пользователя, а не адрес электронной почты и да, любой человек может выбрать любое (доступное) имя пользователя, но всё равно существует большая вероятность того, что вы будете косвенно раскрывать владельцев аккаунтов из-за склонности пользователей к многократному использованию имени.
Так что же происходит, когда кто-то забывает своё имя пользователя? Если принять, что имя пользователя не является сразу адресом электронной почты (а такое бывает часто), то процесс похож на то, как начинается сброс пароля — вводим адрес электронной почты, а затем отправляем сообщение на этот адрес, не раскрывая его существования. Единственное отличие в том, что на этот раз сообщение содержит только имя пользователя, а не URL сброса пароля. Или это, или в электронном письме будет написано, что для этого адреса нет аккаунта.
Проверка личности и точность адресов электронной почты
Ключевым аспектом сброса паролей, и, даже, вероятно, самым ключевым аспектом является проверка личности человека, пытающегося выполнить сброс. На самом ли деле это законный владелец аккаунта, или кто-то пытается пытается его взломать или доставить владельцу неудобства?
Очевидно, что электронная почта является наиболее удобным и самым распространённым каналом проверки личности. Она не защищена от неумелого обращения («от дурака»), и существует множество случаев, когда простой возможности получать письма на адрес владельца аккаунта недостаточно, если требуется высокая степень уверенности в идентификации (поэтому и используется 2FA), однако почти всегда она является начальной точкой процесса сброса.
Если электронная почта будет играть роль в обеспечении уверенности, то первым делом нужно убедиться, что адрес электронной почты на самом деле правилен. Если кто-то ошибся символом, то, очевидно, сброс не начнётся. Процесс верификации электронной почты в момент регистрации — надёжный способ проверки правильности адреса. Мы все видели это на практике: вы регистрируетесь, вам отправляют электронное письмо с уникальным URL, на который нужно нажать, что подтверждает, что вы и в самом деле владелец этого аккаунта электронной почты. Невозможность входа в систему до завершения этого процесса гарантирует наличие мотивации для подтверждения адреса.
Как и в случае со многими другими аспектами безопасности, такая модель снижает юзабилити в обмен на обеспечение повышенной степени безопасности относительно уверенности в личности пользователя. Это может быть приемлемо для сайта, регистрацию на котором пользователь ценит высоко и с радостью добавит ещё один этап процесса (платные сервисы, банкинг, и т.п.), но подобные вещи могут оттолкнуть пользователя, если он воспринимает аккаунт «одноразовым» и использует, например, просто как средство для комментирования поста.
Идентификация того, кто инициировал процесс сброса
Очевидно, что существуют причины для вредоносного использования функции сброса, и злоумышленники могут использовать её множеством разных способов. Один простой трюк, который мы можем использовать в помощь подтверждения источника запроса (этот трюк обычно срабатывает) — это добавление в письмо с предложением сброса IP-адреса запрашивающего. Это снабжает получателя некоторой информацией для идентификации источника запроса.
Вот пример из функции сброса, которую я сейчас встраиваю в ASafaWeb:
Ссылка «find out more» («Узнать больше») переносит пользователя на сайт ip-adress.com, сообщающий такую информацию, как местоположение и организация запрашивающего сброс:
Разумеется, любой, кто хочет сокрыть свою личность, имеют множество способов обфускации своего реального IP-адреса, однако это удобный способ добавления частичной идентификации запрашивающего, и в большинстве случаев это даст вам достаточное представление о том, кто выполнит запрос на сброс пароля.
Уведомление об изменениях по электронной почте
Этот пост проникнут одной темой — коммуникацией; сообщайте владельцу аккаунта как можно больше о том, что происходит на каждом этапе процесса, не раскрывая ничего того, что может быть использовано со злым умыслом. То же самое и относится к ситуации, когда пароль на самом деле изменился — сообщите об этом владельцу!
Причинами смены пароля могут служить два источника:
- Смена пароля после входа в систему, потому что пользователь хочет новый пароль
- Сброс пароля без входа в систему, потому что пользователь его забыл
Хотя этот пост в основном посвящён сбросу, уведомление в первом случае снижает риск того, что кто-то изменит пароль без ведома законного владельца. Как такое может произойти? Очень распространённым сценарием является получение пароля законного владельца (повторно использованного пароля, утекшего из другого источника; пароля, полученного кейлоггингом; легко угадываемого пароля и т.д.), после чего злоумышленник решает его изменить, заблокировав таким образом владельца. Без уведомления по электронной почте настоящий владелец не будет знать о смене пароля.
Конечно, в случае сброса пароля владелец уже должен был сам инициировать процесс (или обойти описанные выше средства проверки идентификации), поэтому смена не должна стать для него сюрпризом, однако подтверждение по электронной почте будет положительной обратной связью и дополнительной проверкой. Кроме того, это обеспечивает единство с описанным выше сценарием.
О, и на случай, если это ещё не очевидно — не отправляйте новый пароль по почте! Кого-то это может рассмешить, но подобное случается:
Логи, логи, логи и ещё немного логов
Функция сброса пароля привлекательна для злоумышленников: нападающий или хочет получить доступ к аккаунту другого человека, или просто причинить неудобства владельцу аккаунта/системы. Многие из описанных выше практик позволяют снизить вероятность злоупотреблений, но не предотвращают их, и они точно не помешают людям пытаться использовать функцию непредусмотренным образом.
Для распознавания злонамеренного поведения абсолютно бесценной практикой является логгинг, и я имею в виду очень подробный логгинг. Фиксируйте неудавшиеся попытки входа в систему, сброс паролей, изменение паролей (т.е. когда пользователь уже вошёл) и практически всё, что может помочь вам в понимании происходящего; это очень пригодится в будущем. Фиксируйте в логах даже отдельные части процесса, например, хорошая функция сброса должна включать в себя инициирование сброса через веб-сайт (фиксируйте запрос и попытки входа для сброса с неправильным именем пользователя или электронной почтой), фиксируйте посещение веб-сайта по URL сброса (в том числе и попытки использования неверного токена), а затем записывайте в лог успешность или ошибочность ответа на секретный вопрос.
Когда я говорю о логгинге, то подразумеваю не только запись факта загрузки страницы, но и сбор как можно большего количества информации, если она не конфиденциальна. Ребята, пожалуйста, не записывайте в логи пароли! В логах нужно регистрировать личность авторизированного пользователя (он будет авторизирован, если он меняет существующий пароль или пытается сбросить чужой пароль после входа в систему), любые пробуемые имена пользователей или адреса электронной почты плюс любые токены сброса, которые он пытается использовать. Но также стоит записывать в логи такие аспекты, как IP-адреса и, если это возможно, даже заголовки запросов. Это позволяет вам воссоздать не только что пользователь (или нападающий) пытается сделать, но и кто он такой.
Делегирование ответственности другим исполнителям
Если вы считаете, что всё это представляет огромный объём работы, то вы не одиноки. На самом деле, построение надёжной системы работы с аккаунтами — непростая задача. Дело не в том, что она тяжела технически, просто в ней есть множество особенностей. Она заключается не только в сбросе, существует целый процесс регистрации, надёжное хранение паролей, обработка множественных неверных попыток входа в систему и т.д, и т.п. Хотя я продвигаю идею использования готовой функциональности наподобие ASP.NET membership provider, помимо неё нужно сделать ещё многое.
Сегодня существует множество сторонних поставщиков, с радостью берущих на себя все мучения и абстрагирующих всё это в один управляемый сервис. Среди таких сервисов есть OpenID, OAuth и даже Facebook. Некоторые люди безгранично верят этой модели (OpenID и в самом деле оказался очень успешным на Stack Overflow), однако другие в буквальном смысле считают её кошмаром.
Без сомнений, сервис наподобие OpenID решает множество проблем разработчика, однако, также несомненно, что он добавляет новые. Имеют ли они какую-то роль? Да, но очевидно, что мы не наблюдаем массового использования услуг поставщиков сервисов аутентификации. Банки, авиакомпании и даже магазины — все они реализуют собственный механизм аутентификации, и очевидно, что для этого есть очень весомые причины.
Злонамеренный сброс
Важный аспект каждого из представленных выше примеров заключается в том, что старый пароль считается бесполезным только после подтверждения личности владельца аккаунта. Это важно, потому что если бы аккаунт можно было сбросить до проверки идентификации, то это предоставило бы возможность всевозможных злонамеренных действий.
Вот пример: кто-то участвует в торгах на сайте аукциона, и ближе к концу процесса торгов он блокирует конкурентов, инициировав процесс сброса, таким образом устранив их из торгов. Очевидно, если плохо спроектированную функцию сброса можно эксплуатировать неправильно, это может привести к серьёзным отрицательным результатам. Стоит заметить, что блокировки аккаунтов при помощи неверных попыток входа являются похожей ситуацией, но это уже тема для другого поста.
Как я говорил выше, если дать анонимным пользователям возможность сбрасывать пароль любого аккаунта, просто зная его адрес электронной почты, то это готовая ситуация для атаки типа «отказ в обслуживании». Это может быть не тот DoS, о котором мы привыкли говорить, но не существует более быстрого способа заблокировать доступ к аккаунту, чем с помощью плохо продуманной функции сброса пароля.
Самое слабое звено
С точки зрения защиты одного аккаунта всё написанное выше замечательно, однако вам всегда нужно помнить об экосистеме, окружающей защищаемый вами аккаунт. Позвольте привести пример:
ASafaWeb хостится на потрясающем сервисе, предоставляемом AppHarbor. Процесс сброса аккаунта хостинга происходит так:
Этап 1:
Этап 2:
Этап 3:
Этап 4:
После прочтения всей предшествующей информации уже легко понять, какие аспекты в идеальном мире мы бы реализовали чуть иначе. Однако здесь я хочу сказать, что если я опубликую сайт наподобие ASafaWeb в сервисе AppHarbor, а затем придумаю отличные секретные вопросы и ответы, добавлю второй фактор аутентификации и сделаю всё остальное по правилам, то это не отменяет факта, что самое слабое звено всего процесса окажется способным всё это сломать. Если кто-то успешно выполнит аутентификацию в AppHarbor, воспользовавшись моей информацией, то он сможет заменить пароль у любого аккаунта ASafaWeb на нужный ему!
Смысл в том, что стойкость реализации защиты следует рассматривать целостно: нужно смоделировать угрозы каждой входной точки системы, даже если это поверхностный процесс, например, вход в систему AppHarbor. Это должно дать мне хорошее представление о том, сколько усилий мне нужно вложить в процесс сброса пароля ASafaWeb.
Соединяем всё вместе
Этот пост содержит большой объём информации, поэтому я хочу сконцентрировать его в простой визуальной схеме:
Помните, что следует выполнять максимально подробный логгинг каждого из этих пунктов. Вот и всё, это просто!
Итоги
Мой пост кажется всеобъемлющим, однако существует множество дополнительных материалов, которые я мог бы включить в него, но решил от казаться от этого ради краткости: роль адреса спасательной электронной почты, ситуация, при которой вы теряете доступ к привязанной к аккаунту электронной почте (например, вы уволились с работы) и так далее. Как я сказал ранее, функция сброса не так сложна, только существует множество точек зрения на неё.
Даже несмотря на то, что сброс не так сложен, часто его реализуют неправильно. Выше мы видели пару примеров, когда реализация может привести к проблемам, и существует гораздо больше прецедентов, когда неправильный сброс действительно вызвал проблемы. Недавно выяснилось, что сброс пароля использовали для кражи биткойнов на сумму 87 тысяч долларов. Это серьёзный негативный результат!
Поэтому будьте аккуратнее со своими функциями сброса, моделируйте угрозы в разных точках, а при проектировании функции не снимайте своей чёрной шляпы, потому что есть большая вероятность, что её наденет кто-то другой!
На правах рекламы
VDSina предлагает недорогие серверы в аренду с посуточной оплатой, каждый сервер подключён к интернет-каналу в 500 Мегабит и бесплатно защищён от DDoS-атак!