Воспроизведение проблемы безопасности в отношении файлов cookie и сеансов

Для моего приложения я реализую ту же безопасность, что и в zentask.

public class Secured extends Authenticator {

@Override
public String getUsername(Context ctx) {
    return ctx.session().get("email");

}

@Override
public Result onUnauthorized(Context ctx) {
    ctx.flash().put("error", "please login to proceed");
    return redirect(routes.Application.index());
}

}

Когда пользователь аутентифицируется isuser session().put("email", email);

У меня две проблемы. Во-первых: как вы аннулируете сеанс, когда пользователь покидает приложение, не используя выход из системы? Второй более серьезным является то, что я просмотрел файл cookie с помощью плагина firefox cookies manager+, и я могу скопировать файл cookie, а затем вставить его, тем самым я могу получить доступ к методам без первого входа в систему, в основном я могу украсть сеансы

Ответ 1

Play Framework использует сеансы без состояния. На стороне сервера нет состояния, а все состояние сохраняется в файле cookie сеанса. Чтобы проверить сеанс, Play подписывает сеансы с использованием секретного ключа и проверяет подпись, когда приходит запрос с куки-сообщением сеанса. Если пользователь должен был нарушать данные сеанса, например, если они изменили адрес электронной почты в сеансе на другой адрес электронной почты, тогда подпись не будет соответствовать, и поэтому Play будет отклонять cookie сеанса.

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

По умолчанию Play настроен на создание файлов cookie "session", то есть файлов cookie, срок действия которых истекает при закрытии браузера. Поэтому, если пользователь выходит из своего браузера, браузер удалит все файлы cookie сеанса, и пользователь больше не войдет в систему. Это то же самое для токенов сеанса.

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

Ответ 2

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

Сейчас есть два основных варианта:

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

  • Я бы создал идентификатор сеанса в виде комбинации (userId + providerId (Facebook/Google-в случае OAuth/UsernamePassword/Any Provider) + текущая временная метка + UUID), и после создания этого идентификатора сеанса я зашифрую это с некоторым алгоритмом. Это даст мне идентификатор сеанса

  • Преимущество с этим:

    • Хотя генерация идентификатора сеанса потребует времени, никакое тело не имеет смысла.
    • Еще одно преимущество: вы можете изменить свою логику/стратегию шифрования создание идентификаторов сеансов в любое время в методе createSessionId().

  • Еще одна проблема с сеансом в Playframework заключается в отсутствии истечения срока действия сеанса:
    • Чтобы справиться с этим, как только пользователь войдет в систему, мы можем сохранить временную метку в сеансе, т.е. ничего, кроме файла cookie (путем шифрования может быть?)
    • Теперь для каждого запроса отметьте отметку времени в сеансе. Если отметка времени больше, чем 30-минутная старость, аннулируйте сеанс. Если временная метка не превышает 30 минут, отметьте временную метку в сеансе как текущую временную метку