Spring SessionFixationProtectionStrategy убивает CDI Conversation под JBoss/Weld

У меня есть объект, помеченный как @ConversationScoped, который используется между многими шагами мастера.

Это работает отлично, за исключением того, что когда мой пользователь входит в систему, SessionFixationProtectionStrategy Spring вызывает метод session.invalidate() для воссоздания нового сеанса с новым идентификатором. Затем он идет и повторно прикрепляет атрибуты недействительного сеанса к новому.

Проблема в том, что существует экземпляр WeldListener, привязанный к событию sessionDestroyed, который уничтожит экземпляры @ConversationScoped, привязанные к объекту HttpSession.

Я отключил SessionFixationProtectionStrategy и теперь использую NullAuthenticatedSessionStrategy, который ничего не делает, но я все равно хотел бы сохранить стратегию фиксации сеанса, чтобы защитить свой сайт от этого.

Любые предложения о том, как обойти это?


person Community    schedule 22.08.2012    source источник
comment
Какую версию весенней безопасности вы используете?   -  person Xaerxess    schedule 23.08.2012
comment
Я использую Spring-Security 3.1.0 и JBoss 7.   -  person    schedule 23.08.2012


Ответы (2)


Вот стратегия, которую я использую:

  1. Отсоедините контексты сварки (сеанс и диалог) от текущего сеанса.
  2. После копирования всех атрибутов сеанса удалите их из сеанса, прежде чем сделать его недействительным (по какой-то причине это не работает, возможно, прослушиватель уничтожения сеанса где-то в сварке)
  3. Создать новый сеанс, скопировать атрибуты из предыдущего сеанса
  4. Повторно присоедините контексты сварки.

Вам нужно скопировать класс SessionFixationProtectionStrategy, чтобы иметь возможность реализовать это, поскольку уже нет подходящих ловушек. Вот onAuthenticate.

public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
        boolean hadSessionAlready = request.getSession(false) != null;

        if (!hadSessionAlready && !alwaysCreateSession) {
            // Session fixation isn't a problem if there's no session

            return;
        }

        // Create new session if necessary
        HttpSession session = request.getSession();

        if (hadSessionAlready && request.isRequestedSessionIdValid()) {
            // We need to migrate to a new session
            String originalSessionId = session.getId();

            if (logger.isDebugEnabled()) {
                logger.debug("Invalidating session with Id '" + originalSessionId +"' " + (migrateSessionAttributes ?
                        "and" : "without") +  " migrating attributes.");
            }

            String id = weldAwareSessionFixationProtectionStrategyHelper.beforeInvalidateSession( request );

            Map<String, Object> attributesToMigrate = extractAttributes(session);

            for( String key : attributesToMigrate.keySet() ) {
                session.removeAttribute( key );
            }


            session.invalidate();
            session = request.getSession(true); // we now have a new session

            if (logger.isDebugEnabled()) {
                logger.debug("Started new session: " + session.getId());
            }


            if (originalSessionId.equals(session.getId())) {
                logger.warn("Your servlet container did not change the session ID when a new session was     created. You will" +
                        " not be adequately protected against session-fixation attacks");
            }

            transferAttributes(attributesToMigrate, session);

            weldAwareSessionFixationProtectionStrategyHelper.afterCreateNewSession( request, id );

            onSessionChange(originalSessionId, session, authentication);
        }
    }

... а вот WeldAwareSessionFixationProtectionStrategyHelper

@ApplicationScoped
public class WeldAwareSessionFixationProtectionStrategyHelper {

    @Inject
    private HttpSessionContext httpSessionContext;

    @Inject
    private HttpConversationContext httpConversationContext;

    public String beforeInvalidateSession( HttpServletRequest httpServletRequest ) {

        String currentId = null;

        if( !httpConversationContext.getCurrentConversation().isTransient() ) {
            currentId = httpConversationContext.getCurrentConversation().getId();
        }

        httpConversationContext.deactivate();
        httpConversationContext.dissociate( httpServletRequest );

        httpSessionContext.deactivate();
        httpSessionContext.dissociate( httpServletRequest );

        return currentId;
    }

    public void afterCreateNewSession( HttpServletRequest httpServletRequest, String cid ) {

        httpSessionContext.associate( httpServletRequest );
        httpSessionContext.activate();

        httpConversationContext.associate( httpServletRequest );

        if( cid == null ) {
            httpConversationContext.activate();
        } else {
            httpConversationContext.activate( cid );            
        }
    }
}
person Jonathan    schedule 08.12.2012

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

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

public class MySessionAS extends SavedRequestAwareAuthenticationSuccessHandler {

    /**
     * Called after the user has successfully logged in.
     */
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) {
        // Generate random value
        String myAuthToken = ...
        request.getSession().setAttribute("myAuthToken", myAuthToken);
        Cookie myAuthCookie = new Cookie("myAppCookie", myAuthToken);
        myAuthCookie.setSecure(true); // You're using HTTPS, right?
        myAuthCookie.setMaxAge(-1); // It's a session cookie.
        response.addCookie(cookie);
        super.onAuthenticationSuccess(request, response, authentication);
    }
}

и подключите это к вашей конфигурации form-login.

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

person Shaun the Sheep    schedule 23.08.2012