Рубрики
Без рубрики

Контролируйте сеанс с помощью Spring Security

Настройка сеансов с помощью Spring Security – настройка параллельных сеансов, включение защиты от фиксации сеансов и предотвращение того, чтобы URL-адреса содержали информацию о сеансе.

Автор оригинала: Eugen Paraschiv.

1. Обзор

В этой статье мы проиллюстрируем, как Spring Security позволяет нам контролировать наши HTTP-сеансы .

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

Дальнейшее чтение:

Получение информации о пользователе в Spring Security

Весенняя охрана Помнит Меня

Весенний выход из системы безопасности

2. Когда Создается Сеанс?

Мы можем точно контролировать, когда будет создан наш сеанс и как Spring Security будет взаимодействовать с ним:

  • всегда – сеанс всегда будет создан, если он еще не существует
  • ifRequired – сеанс будет создан только при необходимости ( по умолчанию )
  • никогда – фреймворк никогда не создаст сеанс сам по себе, но он будет использовать его, если он уже существует
  • без состояния – никакой сеанс не будет создан или использован Spring Security
...

Конфигурация Java:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
}

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

По умолчанию Spring Security создаст сеанс, когда он ему понадобится – это ” ifRequired “.

Для более апатридного приложения опция ” никогда ” гарантирует , что Spring Security сама по себе не создаст никакого сеанса; однако, если приложение создаст его, Spring Security будет использовать его.

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

Это было введено в Spring 3.1 и будет эффективно пропускать части цепочки фильтров безопасности Spring – в основном части, связанные с сеансом, такие как HttpSessionSecurityContextRepository , SessionManagementFilter , RequestCacheFilter .

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

3. Под капотом

Перед выполнением процесса аутентификации Spring Security запустит фильтр, отвечающий за сохранение Контекста безопасности между запросами – фильтр SecurityContextPersistenceFilter . Контекст будет сохранен в соответствии со стратегией – HttpSessionSecurityContextRepository по умолчанию – которая использует сеанс HTTP в качестве хранилища.

Для атрибута strict create-session=”без состояния” эта стратегия будет заменена другой – NullSecurityContextRepository – и сеанс не будет создан или использован для сохранения контекста.

4. Управление Параллельными Сеансами

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

Первым шагом в включении параллельной поддержки session-control является добавление следующего прослушивателя в web.xml :


    
      org.springframework.security.web.session.HttpSessionEventPublisher
    

Или определите его как Боб – следующим образом:

@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
    return new HttpSessionEventPublisher();
}

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

Чтобы включить сценарий, допускающий несколько одновременных сеансов для одного и того же пользователя, в конфигурации XML следует использовать элемент <управление сеансами> :


    
        
    

Или через конфигурацию Java:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement().maximumSessions(2)
}

5. Тайм-аут сеанса

5.1. Обработка тайм-аута сеанса

По истечении времени ожидания сеанса, если пользователь отправит запрос с идентификатором сеанса с истекшим сроком действия , он будет перенаправлен на URL-адрес, настраиваемый через пространство имен:


    

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


    ...

Соответствующая конфигурация Java:

http.sessionManagement()
  .expiredUrl("/sessionExpired.html")
  .invalidSessionUrl("/invalidSession.html");

5.2. Настройте тайм-аут сеанса с помощью Spring Boot

Мы можем легко настроить значение тайм-аута сеанса встроенного сервера с помощью свойств:

server.servlet.session.timeout=15m

Если мы не определим единицу длительности, Spring будет считать, что это секунды.

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

Если мы настроили наш проект на использование Tomcat, мы должны иметь в виду, что он поддерживает только минутную точность тайм-аута сеанса, как минимум одну минуту. Это означает, что если мы зададим значение тайм-аута 170s , например, это приведет к тайм-ауту в 2 минуты.

Наконец, важно отметить, что, несмотря на то, что Spring Session поддерживает аналогичное свойство для этой цели ( spring.session.timeout ), если это не указано, автоконфигурация вернется к значению свойства, которое мы впервые упомянули.

6. Запретить использование параметров URL для отслеживания сеансов

Раскрытие информации о сеансе в URL-адресе является растущим риском для безопасности (с 7-го места в 2007 году до 2-го места в 2013 году в списке Топ-10 OWASP).

Начиная с Spring 3.0 , логику перезаписи URL-адресов, которая добавляла бы jsessionid к URL-адресу, теперь можно отключить, установив disable-url-rewriting=”true” в пространстве имен .

В качестве альтернативы, начиная с Servlet 3.0, механизм отслеживания сеансов также может быть настроен в web.xml:


     COOKIE

И программно:

servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE));

При этом выбирается, где хранить JSESSIONID – в файле cookie или в параметре URL.

7. Защита Фиксации Сеанса С Помощью Пружинной Защиты

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

 ...

Соответствующая конфигурация Java:

http.sessionManagement()
  .sessionFixation().migrateSession()

По умолчанию Spring Security включает эту защиту (” migrateSession “) – при аутентификации создается новый сеанс HTTP, старый становится недействительным, а атрибуты из старого сеанса копируются.

Если это нежелательное поведение, доступны два других варианта:

  • если задано значение ” none “, исходный сеанс не будет признан недействительным
  • когда установлен параметр ” новый сеанс “, будет создан чистый сеанс без копирования каких-либо атрибутов из старого сеанса

8. Безопасный файл Cookie Сеанса

Далее мы обсудим, как защитить наш сессионный файл cookie.

Мы можем использовать флаги HttpOnly и secure для защиты нашего файла cookie сеанса :

  • HttpOnly: если true, то скрипт браузера не сможет получить доступ к файлу cookie
  • secure: если true, то файл cookie будет отправлен только по HTTPS-соединению

Мы можем установить эти флаги для нашего файла cookie сеанса в web.xml :


    1
    
        true
        true
    

Этот параметр конфигурации доступен начиная с Java servlet 3. По умолчанию http-only имеет значение true, а secure – false.

Давайте также посмотрим на соответствующую конфигурацию Java:

public class MainWebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext sc) throws ServletException {
        // ...
        sc.getSessionCookieConfig().setHttpOnly(true);        
        sc.getSessionCookieConfig().setSecure(true);        
    }
}

Если мы используем Spring Boot, мы можем установить эти флаги в нашем application.properties :

server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.secure=true

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

public class SessionFilter implements Filter {
    @Override
    public void doFilter(
      ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        Cookie[] allCookies = req.getCookies();
        if (allCookies != null) {
            Cookie session = 
              Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID"))
                    .findFirst().orElse(null);

            if (session != null) {
                session.setHttpOnly(true);
                session.setSecure(true);
                res.addCookie(session);
            }
        }
        chain.doFilter(req, res);
    }
}

9. Работа С Сессией

9.1. Бобы с областью действия Сеанса

Компонент можно определить с помощью session scope, просто используя аннотацию @Scope для компонентов, объявленных в веб-контексте:

@Component
@Scope("session")
public class Foo { .. }

Или с помощью XML:

Затем боб можно просто ввести в другой боб:

@Autowired
private Foo theFoo;

И Spring свяжет новый компонент с жизненным циклом сеанса HTTP.

9.2. Ввод необработанного сеанса в контроллер

Необработанный HTTP-сеанс также может быть введен непосредственно в метод Controller :

@RequestMapping(..)
public void fooMethod(HttpSession session) {
    session.setAttribute(Constants.FOO, new Foo());
    //...
    Foo foo = (Foo) session.getAttribute(Constants.FOO);
}

9.3. Получение необработанной сессии

Текущий сеанс HTTP также может быть получен программно с помощью raw Servlet API :

ServletRequestAttributes attr = (ServletRequestAttributes) 
    RequestContextHolder.currentRequestAttributes();
HttpSession session= attr.getRequest().getSession(true); // true == allow create

10. Заключение

В этой статье мы обсуждали управление сеансами с помощью Spring Security. Кроме того, ссылка на Spring содержит очень хороший FAQ по управлению сеансами .

Как всегда, код, представленный в этой статье, доступен на Github . Это проект на основе Maven, поэтому его должно быть легко импортировать и запускать как есть.