Статьи

Как создать (и как не создавать) безопасную функцию «запомни меня»

Вот сценарий: пользователь заходит на ваш сайт, возвращается завтра и… должен войти снова. Идея функции «помни меня» — и давайте посмотрим правде в глаза, мы все видели это раньше — заключается в том, что их аутентифицированное состояние сохраняется за пределами непосредственного использования. Это означает, что они могут закрыть браузер, выключить компьютер, а затем вернуться завтра, на следующей неделе или в следующем месяце, или, как много позже вы определите, это разумный срок, и сайт все еще знает, кто они, и предлагает им все те же функции. у них было, когда они оставили это.

Я говорю об этом маленьком парне здесь:

«Держите меня в системе» из Facebook

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

Анти-паттерны

Это кажется очевидным, верно? Я имею в виду, что реализация функции «помни меня» довольно фундаментальна, не так ли легко ошибиться, не так ли? Очевидно нет.

Позвольте мне поделиться двумя анти-шаблонами, и мы обсудим с ними проблемы, прежде чем говорить о том, как сделать это правильно. Первый пример любезно предоставлен Black & Decker, это будет тот же B & D, о котором я недавно писал в « Безопасности» — это сложно, небезопасно легко . Вот идея, когда вы входите в систему:

Вход в Black & Decker

Все это довольно стандартно, интересный момент появляется после того, как вы вошли в систему. Давайте посмотрим на куки:

Печенье Black & Decker

Это довольно впечатляющий набор файлов cookie, но выделенные из них действительно интересны. Эти файлы cookie не будут установлены, если вы не установите флажок «запомнить меня», поэтому они предназначены только для повторного входа в систему. Мой адрес электронной почты довольно четко указан, но это не мой пароль, вместо этого он кажется какой-то непроницаемой криптографической крепостью … держитесь — это кодировка Base64! Дело о кодировке Base64 является то , что он аккуратно дополняет Base64 — де — кодирования , который означает , что вы можете голову куда — нибудь base64decode.org и сделать это:

Base 64, декодирующая печенье Black & Decker

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

Я собираюсь поговорить о двух очень простых способах, и первый относится к более ранней ссылке на простоту небезопасности. Black & Decker обнародовал журналы ELMAH, и в этих журналах было все необработанное исключение внутреннего сервера, где-то к северу от 50 000 из них в то время, когда я сообщал об этом им. Когда ELMAH регистрирует исключение, оно также регистрирует все заголовки запроса, что означает, что файлы cookie регистрируются. Добавьте к этому огромное количество необработанных исключений, создаваемых системой, и теперь у вас есть сокровищница пользовательских учетных данных. Да, для начала им следовало должным образом защитить свой журнал ELMAH, но это хороший пример того, как вас можно легко отменить с помощью одной очень простой неверной конфигурации.

Вот еще один:

Вход в Aussie Farmers Direct

Это Aussie Farmers Direct, и это довольно типичная форма входа в систему. Давайте войдем в систему, скажем, что «помни меня», а затем взглянем на куки:

Aussie Farmers Direct печенье

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

Неправильно закодированный файл cookie на Aussie Farmers Direct

XSS ваш собственный файл cookie JSON? Конечно! Другая особенность заключается в том, что изменение пароля не приводит к изменению файла cookie, поэтому вы позже возвращаетесь на сайт и пытаетесь войти со старым. К сожалению.

Aussie Farmers Direct не раскрывает журналы ELMAH (что помогает PHP в этом!), Но у них есть и другие риски, такие как XSS (кстати, это было ответственно раскрыто, а риск суммарно отклонен — ​​несколько раз). Еще одна вещь на обоих сайтах, указанных выше, заключается в том, что файлы cookie, содержащие пароли, не помечены как HttpOnly, вы можете увидеть это во втором столбце справа в списках файлов cookie. Это означает, что клиентский сценарий может получить доступ к этим файлам cookie, а это означает, что если вы можете получить кусок XSS на сайт — так же, как вы можете на сайте Aussie Farmers — вы можете украсть файлы cookie, содержащие пароли, если вы можете заставить клиента загрузить полезная нагрузка XSS (и есть множество способов сделать это). Отсутствующий атрибут HttpOnly небрежный от имени обоих сайтов,но суть проблемы заключается в хранении паролей в файлах cookie, что делает их уязвимыми из-за других упущений.

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

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

Пример эталонной реализации

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

На новом веб-сайте ASP.NET MVC 4, поставляемом с Visual Studio 2012, вы получаете это прямо из коробки:

Вход в пример приложения ASP.NET

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

Set-Cookie:.ASPXAUTH=6891A5EAF17A9C35B51C4ED3C473FBA294187C97B758880F9A56E3D335E2F020B86A85E1D0074BDAB2E1C9DBE590AF67895C0F989BA137E292035A3093A702DEC9D0D8089E1D007089F75A77D1B2A79CAA800E8F62D3D807CBB86779DB52F012; path=/; HttpOnly

Это просто файл cookie для аутентификации, а в мире без сохранения состояния, который представляет собой HTTP, это один маленький кусочек данных, который связывает вместе все совершенно независимые запросы от одного человека. Каждый раз, когда отправляется этот уникальный для меня файл cookie, веб-сайт знает, что это я, и я уже прошел проверку подлинности. Мы можем видеть это немного яснее, когда смотрим на это в коллекции Cookies Chrome:

Файлы cookie из примера приложения ASP.NET без флажка «запомнить меня»

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

Давайте теперь войдем в систему и попросим сайт запомнить меня, вот ответ файла cookie:

Set-Cookie:.ASPXAUTH=3A92DAC7EFF4EE5B2027A13DD8ABEA8254F0A16D8059FCAF60F5533F1B7D99462DDF57320D069A493481978750526DF952D5C9EA0371C84F5CF1BFC0CCA024C2052824D4BA09670A42B85AEC7FFCB4088FC744C6C0A22749F07AF6E65E674A4A; expires=Tue, 02-Jul-2013 00:27:05 GMT; path=/; HttpOnly

Ага — ты видишь это ?! Это становится понятнее, когда вы видите, что это разбито в Chrome:

Файлы cookie из примера приложения ASP.NET с установленным флажком «запомнить меня»

Теперь у нас есть истечение срока действия файла cookie, которое наступает через 48 часов, в отличие от того, что срок действия файла cookie не истек, что означает, что он будет удален при закрытии браузера. Давайте внимательнее посмотрим на это.

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

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

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

Помнить кого-то может быть так же просто, как сохранить этот файл cookie. Как долго он должен оставаться в живых? В приведенном выше примере по умолчанию используется два дня, что, вероятно, немного для многих законных применений этой функции (хотя ее легко настроить в ASP.NET), попробуйте Facebook, и вы получите файлы cookie, которые сохраняются в течение года. Более короткая продолжительность означает меньший риск, но больше неудобств, большая продолжительность облегчает пользователю, но увеличивает окно потенциальной атаки. Давайте посмотрим на этот риск более подробно.

Использование длительного состояния аутентификации

Пока вы не аутентифицированы, ваша сессия не может быть взломана. Я знаю, проницательные вещи! А если серьезно, возьмите случай как Aussie Farmers Direct выше; срок действия этого файла cookie истекает через шесть месяцев, и в сочетании с тем фактом, что он не помечен как только HTTP и что у них есть недостатки XSS на сайте, теперь есть окно на пол года, в котором после перехода по ссылке я могу непреднамеренно передать свои учетные данные взломщик. Если бы этот период был, скажем, один месяц, да, у них все еще были бы некоторые серьезные недостатки в их дизайне, но тогда окно возможностей для злоумышленника только что сократилось.

С другой стороны, у Black & Decker есть относительно короткий период истечения одной недели, так что в их случае с открытыми журналами ELMAH, с их стороны, произошел ряд серьезных сбоев, но если кто-то не вошел в систему с «помни меня» Ячейка отмечена на прошлой неделе и вызвала необработанное исключение, учетные данные не будут выставлены на всеобщее обозрение. Хорошо, если вы на сайте для начала, есть хороший шанс, что вы уже вошли в систему (по крайней мере, по сравнению с примером Фермеров, где вам не нужно было бы сознательно заходить где-нибудь рядом с сайтом, чтобы потерять ваш пароль), но вы можно увидеть, как этот профиль риска изменяется с периодом истечения срока действия cookie.

Конечно, в основе всего этого лежит то, что auth cookie должен быть тщательно защищен; HttpOnly и безопасные атрибуты абсолютно необходимы. Все ваши классические угрозы угона остаются актуальными, но опять же, как бы вы ни выбрали эту функцию, у вас будет зависимость от файлов cookie, поэтому вам нужно будет очень и очень внимательно следить за этими файлами cookie.

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

Усиление подхода

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

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

Одним из способов обеспечения дополнительной проверки является включение IP-адреса пользователя / агента пользователя / другой отличительной функции в файл cookie «Запомнить меня». Смысл в том, что это предлагает некоторую защиту от угона cookie. Проблема, конечно, заключается в том, что существуют законные случаи использования, когда они меняются. В частности, в мобильном мире часто можно вернуться на сайт с другим IP. Даже в мире физических соединений вы не можете полагаться на провайдера, предоставляющего статический IP-адрес. Что касается пользовательских агентов, с такими браузерами, как Chrome и Firefox, которые обновляются, как каждый день, если вы не слишком избирательны в отношении того, чтоатрибуты строки агента пользователя, которую вы храните и сравниваете, это будет рискованным подходом. Одни и те же средства защиты, связанные с использованием уникальных пользовательских атрибутов и добавлением безопасности, часто обсуждаются в контексте сеансовых и аутентификационных файлов cookie, и хотя я уверен, что для этого есть действительные варианты использования (снова к банковскому делу), я не могу сказать, что « Я видел это на любом из сайтов, которые я тестировал ранее. Там, вероятно, есть веская причина для этого …

Более прагматичным решением будет по-прежнему отделять cookie-файл auth от выделенного cookie-файла «Запомнить меня» и использовать его для повторной аутентификации пользователя, но накладывать некоторые ограничения., Реальность такова, что процесс автоматического сохранения чьего-либо аутентифицированного состояния — с помощью любых средств — вносит компромиссы в модель безопасности. Меры предосторожности могут заключаться в том, чтобы потребовать, чтобы автоматически повторно аутентифицированный пользователь снова явно предоставил свои учетные данные перед просмотром определенных классов данных или выполнением определенных действий. Это не неслыханно даже вне рамок «помни меня», вы можете увидеть это при выполнении ценных операций, таких как банковский перевод. В этом случае мы говорим, что аутентифицированный пользователь подвергается большему риску, потому что есть большая вероятность того, что он не тот, кем он себя считает (то есть кто-то другой сел за компьютер и фактически похитил сеанс).

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

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

Когда вы не должны позволять «помнить меня»? (и некоторые средние альтернативы)

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

Но на самом деле здесь есть нечто среднее:

Поле «запомнить меня» на сайте American Express

Это не совсем то, на что это похоже — когда вы вернетесь после истекшего сеанса, когда вы попросили сайт «Запомнить меня», вы получите следующее:

Сайт American Express предварительно заполняет имя пользователя по возвращении

Я не запутывал имя пользователя, имя пользователя в том виде, в котором оно указано выше со звездами, хранится в файле cookie, который сохраняется в течение трех месяцев вместе с некоторыми другими данными, которые неизбежно идентифицируют пользователя. Честно говоря, я не вижу в этом особой ценности, поскольку помнить ваше имя пользователя обычно не проблема!

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

В заключение…

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

Еще один момент, который стоит убрать из этой статьи, помимо механики функции «помни меня», заключается в том, насколько безопасен такой многоуровневый, взаимозависимый зверь. Возможно, вам удастся обойтись без учетных данных в файлах cookie, но объедините это с ситуацией ELMAH или отсутствием атрибутов HTTP only и недостатками XSS, и внезапно глупая, хотя и относительно безвредная практика станет серьезным риском. Что это за «глубокая защита»?