Выход оставляет после себя JSESSIONID в браузере. Как это очистить?

Я использую следующий код для выхода пользователя из моей системы.

/**
 * This function helps to set the session attribute for the present user to null and then
 * removes the attribute itself and this helps in clearing the session
 * @param request
 * @param response
 */
@RequestMapping(value = AuthConstants.EXIT, method = RequestMethod.POST)
public void exitPrime(HttpServletRequest request, HttpServletResponse response) {
        /*Getting session and then invalidating it*/
        HttpSession session = request.getSession(false);
        if(request.isRequestedSessionIdValid() && session != null)
        {
            session.invalidate();

        }
}

Это приводит к успешному выходу из системы, но идентификатор JSESSION, заданный при входе в систему, по-прежнему остается в браузере, из-за чего для любого нового пользователя снова используется тот же идентификатор JSESSION при входе в систему. Я хочу, чтобы файл cookie JSESSIONID был действителен только для текущего сеанса, и после выхода пользователя из системы он должен быть уничтожен или недействителен для входа в систему в следующий раз. Мой код входа выглядит следующим образом: -

/**
 * This method allows one to log into the system and generates a token for a valid employee.
 * @param authRequest
 * @param request
 * @param response
 * @return
 */
@RequestMapping(value = AuthConstants.ENTRY, method = RequestMethod.POST, consumes = ApplicationConstants.APPLICATION_JSON)
public @ResponseBody
AuthResponse primeEntry(@RequestBody AuthRequest authRequest,HttpServletRequest request, HttpServletResponse response) {
    AuthResponse authResponse = new AuthResponse();
    if(authRequest != null && authRequest.getEmployeeAuth().getEmployeeNumber() != null 
            && !authRequest.getEmployeeAuth().getEmployeeNumber().isEmpty()){
        /*To check whether the user is valid*/
        String employeeNumber = authRequest.getEmployeeAuth().getEmployeeNumber();
        UserBean userBean = new UserBean();
        userBean = userService.getUser(employeeNumber);
        if(userBean != null)
            {
            HttpSession session = request.getSession(true);
            session.setAttribute("user", userBean);
            setAuthResponseSuccess(authResponse);
        }else{
            /*If user does not exist the too throw error 500*/
            setAuthResponseFailure(authResponse);
        }
    }else{
        /*If input JSON is not valid then throw error 500*/
        setAuthResponseFailure(authResponse);
    }
    return authResponse;
}

Я использую Spring 3.2 и хочу выполнять вход и выход вручную. Пожалуйста помоги.

Полный код класса

@Controller
@RequestMapping(value = "/auth")
public class AuthController {
    @Autowired
    HttpServletRequest request;

    @Autowired
    HttpSession session;

    @Autowired
    IUserService userService;

    /**
     * This method allows one to log into the system and generates a token for a valid employee.
     * @param authRequest
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = AuthConstants.ENTRY, method = RequestMethod.POST, consumes = ApplicationConstants.APPLICATION_JSON)
    public @ResponseBody
    AuthResponse primeEntry(@RequestBody AuthRequest authRequest,HttpServletRequest request, HttpServletResponse response) {
        AuthResponse authResponse = new AuthResponse();
        if(authRequest != null && authRequest.getEmployeeAuth().getEmployeeNumber() != null 
                && !authRequest.getEmployeeAuth().getEmployeeNumber().isEmpty()){
            /*To check whether the user is valid*/
            String employeeNumber = authRequest.getEmployeeAuth().getEmployeeNumber();
            UserBean userBean = new UserBean();
            userBean = userService.getUser(employeeNumber);
            if(userBean != null)
                {
                HttpSession session = request.getSession(true);
                session.setAttribute("user", userBean);
                setAuthResponseSuccess(authResponse);
            }else{
                /*If user does not exist the too throw error 500*/
                setAuthResponseFailure(authResponse);
            }
        }else{
            /*If input JSON is not valid then throw error 500*/
            setAuthResponseFailure(authResponse);
        }
        return authResponse;
    }


    /**
     * This function helps to set the session attribute for the present user to null and then
     * removes the attribute itself and this helps in clearing the session
     * @param request
     * @param response
     */
    @RequestMapping(value = AuthConstants.EXIT, method = RequestMethod.POST)
    public void exitPrime(HttpServletRequest request, HttpServletResponse response) {
            /*Getting session and then invalidating it*/
            HttpSession session = request.getSession(false);
            if(request.isRequestedSessionIdValid() && session != null)
            {
                session.invalidate();

            }
    }

    private AuthResponse setAuthResponseFailure(AuthResponse authResponse) {
        authResponse.setResponseCode(ApplicationConstants.INTERNAL_ERROR_CODE);
        authResponse.setStatus(StatusType.FAILURE);
        authResponse.setResponseMsg(ApplicationConstants.INTERNAL_ERROR_MESSAGE);
        return authResponse;
    }
    private AuthResponse setAuthResponseSuccess(AuthResponse authResponse){
        authResponse.setResponseCode(ApplicationConstants.OK);
        authResponse.setStatus(StatusType.SUCCESS);
        authResponse.setResponseMsg(ApplicationConstants.LOGIN_SUCCESS);
        return authResponse;
    }
}

person Shiv Kumar Ganesh    schedule 06.08.2013    source источник
comment
Пожалуйста, дайте мне знать, если кто-то хочет увидеть перехватчик   -  person Shiv Kumar Ganesh    schedule 06.08.2013
comment
вы используете пружинную безопасность?   -  person Santosh    schedule 06.08.2013
comment
Неа! Я хочу сделать это вручную. Это возможно?   -  person Shiv Kumar Ganesh    schedule 06.08.2013
comment
Я предложил решение. Пожалуйста, проверьте ниже.   -  person Santosh    schedule 06.08.2013
comment
Есть ли конкретная причина, по которой вы не хотите повторно использовать JSESSIONID? На данный момент я считаю, что повторное использование JSESSIONID не должно быть проблемой, и я согласен с этим. Итак, реальный вопрос в том, почему это проблема? Какую проблему это вызывает, которую вы пытаетесь решить?   -  person Nizzo    schedule 06.08.2013
comment
@Nizzo Моя проблема заключается в том, почему сервер повторно использует идентификатор JSESSION и почему он не создает новый идентификатор, когда кто-то пытается повторно войти в систему? Т.к. в большинстве других приложений такое действительно происходит. В остальном проблем нет, я хочу спросить, почему браузер сохраняет JSESSIONID, который переназначается как новый идентификатор сеанса? :(   -  person Shiv Kumar Ganesh    schedule 06.08.2013
comment
Я бы возразил, почему вы ожидаете, что это изменится? JSESSIONID просто содержит значение, которое используется в качестве ссылки на объект Session, хранящийся в памяти. Делая сеанс недействительным, вы уничтожаете объект/данные, но это не влияет на само значение JSESSIONID. Имейте в виду, что такое поведение должно наблюдаться только в том случае, если пользователи входят/выходят из приложения на одном компьютере в одном и том же сеансе браузера. Если бы пользователь перезапустил браузер или попробовал с другого компьютера, JSESSIONID был бы другим.   -  person Nizzo    schedule 07.08.2013
comment
Недостаточно места ... Я не думаю, что сервер приложений сохраняет JSESSIONID, а тот факт, что последующие вызовы приложения ВКЛЮЧАЮТ JSESSIONID как часть вызова. Сервер приложений не будет выдавать новый JSESSIONID, если он уже есть. Вот почему перезапуск браузера должен привести к новому JSESSIONID. Поскольку новый (свежий) вызов приложения не будет включать значение JSESSIONID, что заставит сервер приложений сгенерировать новый.   -  person Nizzo    schedule 07.08.2013
comment
@Nizzo Отличное объяснение :)   -  person Shiv Kumar Ganesh    schedule 07.08.2013
comment
@Nizzo, вы упускаете серьезную проблему. Фиксация сеанса ... Если идентификатор сеанса для следующего сеанса может быть известен, злоумышленник может украсть его и захватить сеанс пользователя, когда следующий пользователь входит в систему с помощью этого браузера. Хотя очистка файла cookie идентификатора сеанса при выходе из системы является лишь рекомендуемой практикой, необходимо назначать новый идентификатор сеанса при каждом входе в систему, даже если он уже существует.   -  person mittal    schedule 01.11.2017
comment
@mittal Я полностью согласен с тем, что при входе в систему должен генерироваться новый JSESSIONID. Это обсуждение было вокруг выхода из системы и того факта, что JSESSIONID не изменился или не был устранен.   -  person Nizzo    schedule 01.11.2017
comment
@Nizzo Как вы сказали выше: Повторное использование JSESSIONID не должно быть проблемой, просто пытаюсь исправить это: JSESSIONID никогда не следует использовать повторно, и его необходимо обновлять при каждом успешном входе в систему. избежать уязвимости фиксации сеанса. Кроме того, OWASP рекомендует очистить/обновить файл cookie идентификатора сеанса при выходе из системы.   -  person mittal    schedule 02.11.2017


Ответы (6)


Нет ничего плохого в том, что JSESSIONID остался в вашем браузере, если он уже недействителен. JSESSIONID — это просто набор случайных символов, которые не содержат ваших реальных данных.

Однако я подозреваю, что ваша проблема в том, что вы использовали аннотацию @SessionAttributes на уровне класса и попытались session.invalidate(). В этом сценарии после того, как предыдущий сеанс становится недействительным, Spring автоматически создает новый сеанс (и JSESSIONID) для вас, поскольку он должен сохранять указанные атрибуты модели в сеансе.

IMO, лучший подход - создать новый контроллер, у которого нет @SessionAttributes, и аннулировать ваш сеанс оттуда.

person gerrytan    schedule 06.08.2013
comment
Я разместил весь свой код выше и не использую @SessionAttribute на уровне класса. Пожалуйста, посмотрите и дайте мне знать, если что-то не так :) - person Shiv Kumar Ganesh; 06.08.2013
comment
Я предполагаю, что можно добавить атрибуты срока действия с файлом cookie, верно? - person Shiv Kumar Ganesh; 06.08.2013
comment
Согласно моему 1-му предложению ответа, нет ничего плохого в том, что JSESSIONID остается в браузере, если он уже признан недействительным. Может быть, ваше понимание HttpSession неверно? - person gerrytan; 06.08.2013
comment
Дело в том, что после выхода из системы, если кто-то пытается войти в систему, новый JSESSIONID не создается. Идентификатор, который сохранился в идентификаторе браузера, был повторно инициализирован с новыми параметрами и отправлен обратно. Таким образом, даже если систему используют 10 пользователей, JSESSIONID остается прежним. Могу ли я принудительно ввести новый JSESSIONID после выхода из системы? Надеюсь, моя проблема ясна. - person Shiv Kumar Ganesh; 06.08.2013
comment
Кстати, это одностраничное приложение, в котором интерфейс и сервер отделены друг от друга. - person Shiv Kumar Ganesh; 06.08.2013
comment
Да, как только сеанс будет правильно признан недействительным, последующий запрос с использованием старого JSESSIONID больше не будет связан с данными сеанса. Если это не так, у вас проблема с методом дескриптора выхода из системы. Я подозреваю, что ваш код даже не выполняет метод выхода из системы - person gerrytan; 06.08.2013
comment
Оно делает. Я проверил это. Но так как я согласен с вашими рассуждениями. Я лучше еще раз протестирую. - person Shiv Kumar Ganesh; 06.08.2013
comment
В моем контроллере @SessionAttributes был на уровне класса. Это вызвало проблему для меня. большое вам спасибо за вашу помощь. - person NEV; 11.02.2016
comment
Как насчет проблем безопасности с остатками JSESSIONID в вашем браузере? - person Ajay Takur; 03.07.2020

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

Set-Cookie: JSESSIONID=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/

Затем вы можете взять этот фрагмент кода и попробовать его.

private void handleLogOutResponseCookie(HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            cookie.setMaxAge(0);
            cookie.setValue(null);
            cookie.setPath("/");
            response.addCookie(cookie);
        }

Это решит проблему и уничтожит файл cookie при выходе из системы.

person Community    schedule 15.08.2013
comment
Не рекомендуется удалять все файлы cookie из запроса. Некоторые из них могут не создаваться приложением, например, файл cookie балансировщика нагрузки или файл cookie отслеживания веб-сервера. - person asgs; 03.04.2015
comment
Более того, возможно, что ваше приложение по какой-то причине использует (или будет использовать где-то в будущем) файлы cookie. Я советую сделать недействительным только файл cookie с именем JSESSIONID. - person Géza; 15.05.2018

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

<beans:bean id="sessionInvalidationFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <beans:property name="filterProcessesUrl" value="/logout"/>
    <beans:constructor-arg>
        <beans:array>
            <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
            <beans:bean class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
                <beans:constructor-arg value="JSESSIONID"/>
            </beans:bean>
        </beans:array>
    </beans:constructor-arg>
</beans:bean>
person Igor Grunskiy    schedule 24.02.2016

Один из способов, который я мог придумать, - это удалить файл cookie JSESSIONID при выходе из системы. Способ удаления файла cookie — установить его возраст равным нулю следующим образом.

Cookie cookie = new Cookie();
cookie.setValue(null);
cookie.setMaxAge(0);
cookie.setPath("/");

Здесь я добавил путь как root. Пожалуйста, проверьте JSESSIONID cookie в вашем браузере на правильный путь.

Получив это, добавьте это в ответ

response.addCookie(cookie);

Вы можете поместить этот код в свой метод exitPrime().

person Santosh    schedule 06.08.2013
comment
может ли значение cookie когда-либо быть нулевым ?? или он может иметь длину 0? - person Shiv Kumar Ganesh; 06.08.2013
comment
Ага. У вас может быть строка нулевой длины, но это не имеет значения, так как срок действия файла cookie истекает немедленно, так как его maxAge устанавливается равным нулю. - person Santosh; 06.08.2013
comment
Я использовал код, указанный вами, следующим образом: Cookie cookie = new Cookie("JSESSION","");//it din allow to be null cookie.setValue(" ");//Same reason as above. Rest of the code remained the same. Это действительно решает проблему и очищает файл cookie, но это приводит к другой мысли о том, что сервер создает идентификатор сеанса, эквивалентный предыдущему, даже после того, как он был признан недействительным (в предыдущем случае? ) Но все равно голосую за тебя!! :D - person Shiv Kumar Ganesh; 06.08.2013
comment
:). Когда вы аннулируете сеанс, он просто уничтожает session object на стороне сервера и не удаляет файл cookie сеанса из браузера. Таким образом, все ваши данные, хранящиеся в объекте сеанса в качестве атрибутов (что делает его действительным), также теряются. Поэтому в следующий раз, когда сервер получит недействительный идентификатор сеанса из файла cookie, он проверит, существует ли связанный с ним объект сеанса, если нет (что будет в случае недействительного сеанса), он просто создаст новый объект сеанса и связывает его с идентификатором сеанса, полученным в файле cookie. - person Santosh; 07.08.2013

Tomcat добавляет косую черту в конце контекстного пути. Теперь, когда вы устанавливаете атрибут delete-cookie, Spring пытается найти cookie для пути без косой черты в конце. Поскольку он не находит его, файл cookie не будет удален, что приведет к отображению страницы окончания сеанса вместо страницы входа.

Следующее обходное решение поможет.

public void logout(HttpServletRequest request, HttpServletResponse response,
                    Authentication auth) {
    Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
    //Tomcat adds extra slash at the end of context path (e.g. "/foo/")
    cookieWithSlash.setPath(request.getContextPath() + "/"); 
    cookieWithSlash.setMaxAge(0); 

    Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
    //JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
    cookieWithoutSlash.setPath(request.getContextPath()); 
    cookieWithoutSlash.setMaxAge(0); 

    //Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
    response.addCookie(cookieWithSlash); //For Tomcat 
    response.addCookie(cookieWithoutSlash); //For JBoss
}
person Debasmita Sahoo    schedule 14.12.2016
comment
Спасибо. Работал с Grails 2.4.4 - person Vishnoo Rath; 16.05.2017

Перечисленный ранее подход не сработал для меня, но с некоторыми изменениями я заставил его работать, хотя я провел только ограниченное тестирование, так что YMMV.

protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
  HttpSession session = req.getSession(false);
  if (session != null) {
    String sessionId = session.getId();
    session.invalidate();
    Cookie[] cookies = req.getCookies();
    for (Cookie cookie : cookies) {
      if (sessionId.equalsIgnoreCase(cookie.getValue())) {
        cookie.setMaxAge(0);
        cookie.setValue(null);
        cookie.setDomain(req.getServerName());
        cookie.setPath(req.getServletContext().getContextPath() + "/");
        cookie.setSecure(req.isSecure());
        res.addCookie(cookie);
        break;
      }
    }
  }
}
person J Gibbs    schedule 22.05.2016