2013-05-12 5 views
12

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

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 plugin cookies manager+, и я могу скопировать куки-файл, а затем вставить его, таким образом, я могу получить доступ к методам без первого входа в систему, в основном я могу воровать сеансы

ответ

36

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

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

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

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

+1

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

+3

Это. Должно быть реализовано в Play. – BAR

4

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

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

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

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

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

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

+0

. Ive разместила следующую информацию о файле cookie session(). put («электронная почта», электронная почта); session(). Put ("timestamp", new Date(). ToString()); сеанс(). Put ("ip", request(). RemoteAddress()); и сравните его. это достаточно хорошо? – naoru

+0

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

+0

так генерируя и UUID, назначьте его файлу cookie и сделайте недействительным, что UUID после 30 минут принесет относительную хорошую защиту? – naoru

7

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

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

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

, вторая альтернатива считается эффективной, она в основном означает, что если украсить класс с помощью аннотации @Secured, каждый reqauest должен быть проверен против db ??? – naoru

+0

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

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

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

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

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

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