0

我有一个标记为 @ConversationScoped 的对象,并在向导的许多步骤之间使用。

这完美地工作,除了当我的用户登录时,Spring 的 SessionFixationProtectionStrategy 调用 session.invalidate() 方法以重新创建具有新 ID 的新会话。然后,它将无效会话的属性重新附加到新会话。

问题是有一个 WeldListener 实例绑定到 sessionDestroyed 事件,这将杀死绑定到 HttpSession 对象的 @ConversationScoped 实例。

我已禁用 SessionFixationProtectionStrategy 并且现在使用 NullAuthenticatedSessionStrategy 什么都不做,但我仍然想保留 Session Fixation 策略以保护我的网站免受此影响。

关于如何解决这个问题的任何建议?

4

2 回答 2

0

您可以通过在用户进行身份验证时设置自定义随机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配置中。

然后你只需要检查值。这样做的好地方是在您的 web 中的自定义投票者中AccessDecisionManager,或者如果这听起来太复杂,您可以使用自定义过滤器来检查用户是否经过身份验证(非空SecurityContext),如果是,请确保值提交的 cookie 与会话中存储的值匹配。

于 2012-08-23T17:38:56.047 回答
0

这是我正在使用的策略:

  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 );            
        }
    }
}
于 2012-12-08T13:39:34.887 回答