Подтвердить что ты не робот

Как обновить cookie JSESSIONID после входа в систему

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

Они предлагают одно из следующих действий:

  • выпустить новый файл cookie JSESSIONID после входа в систему.
  • запретить установку файла cookie JSESSIONID в первую очередь на странице входа (т.е. до аутентификации)

Я просматривал все, что связано с JSESSIONID на этом сайте, и не могу найти легкого ответа. Я просто надеюсь на некоторые идеи. Мои лучшие решения для каждого:

  • сразу после входа в систему, клонировать сеанс (минус id), копируя все атрибуты, аннулируя старый сеанс, создавая новый, копируя значения, связывая их с запросом и надеясь, что это работает.
  • создать фильтр сервлета в самом конце цепочки, который удаляет cookie JSESSIONID перед загрузкой начальной страницы входа. И затем надеюсь, что запрос на вход будет выполнен без набора JSESSIONID.

Мне нужно немного поспать, но мы будем пытаться это утром. Было бы замечательно получить некоторые отзывы или лучшие предложения от людей гораздо умнее, чем я - как вы!

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

4b9b3361

Ответ 1

Вы не обновляетесь после, а только перед этим. При первом выполнении действия для входа выполните:

HttpSession session = request.getSession(false);
if (session!=null && !session.isNew()) {
    session.invalidate();
}

Тогда do:

HttpSession session = request.getSession(true); // create the session
// do the login (store the user in the session, or whatever)

FYI, что вы решаете с помощью этого трюка, http://www.owasp.org/index.php/Session_Fixation

Наконец, вы можете отключить автоматическое создание сеанса и только создать сеанс, когда вам это действительно нужно. Если вы используете JSP, вы делаете это:

<%@page contentType="text/html"
        pageEncoding="UTF-8"
        session="false"%>

Ответ 2

Я не могу комментировать комментарий @cherouvim выше, поскольку у меня недостаточно очков. Новый идентификатор сеанса должен быть установлен "после", когда пользователь успешно войдет в систему, чтобы избежать фиксации сеанса. Я попытаюсь объяснить свои рассуждения.

Фиксация сеанса эффективно означает, что злоумышленник каким-то образом обманул пользователя, используя значение, известное злоумышленнику. Для простоты предположим, что злоумышленник подошел к пользовательскому столу, использовал Firebug и отредактировал файл cookie пользователя. Теперь, когда пользователь войдет в систему, он/она войдет в систему с файлом cookie, контролируемым атакующем. Так как злоумышленник также знает это значение, он обновит свой браузер, и ресурсы, сопоставленные этому идентификатору сеанса (жертвам ресурсов), будут им предоставлены. Это фиксация сеанса. Правильно?

Теперь скажем, что мы запустили session.invalidate, прежде чем пользователь-жертва войдет в систему. Предположим, что cookie изначально имел значение abc. При запуске session.invalidate значение abc очищается от сеанса сервера.

Теперь приходит часть, в которой я не согласен. Вы предлагаете создать новый сеанс до того, как пользователь действительно войдет в систему (вводит имя пользователя и пароль, а также сообщения для отправки). Это, без сомнения, приведет к созданию нового файла cookie, но он будет находиться в браузере пользователя до входа в систему. Поэтому, если злоумышленник может снова редактировать cookie "prelogin", атака по-прежнему сохраняется, поскольку тот же файл cookie будет использоваться даже после входа пользователя в систему.

Я думаю, что это правильный поток.

  • Пользователь выполняет GET/login.html
  • Верните страницу входа с любым файлом cookie в браузере
  • Пользователь вводит учетные данные и клики submit
  • Приложение проверяет учетные данные
  • Обнаружение правильности учетных данных. запускается session.invalidate().destroying старого файла cookie.
  • СЕЙЧАС сгенерируйте новый файл cookie с помощью request.getSession(true)

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

Вот хороший блог об этой проблеме - https://blog.whitehatsec.com/tag/session-fixation/

Ответ 3

Я повторил следующий способ восстановления нового сеанса из старого сеанса. Надеюсь, вам это удастся.

private void regenerateSession(HttpServletRequest request) {

    HttpSession oldSession = request.getSession();

    Enumeration attrNames = oldSession.getAttributeNames();
    Properties props = new Properties();

    if (attrNames != null) {
        while (attrNames.hasMoreElements()) {
            String key = (String) attrNames.nextElement();
            props.put(key, oldSession.getAttribute(key));
        }

        //Invalidating previous session
        oldSession.invalidate();
        //Generate new session
        HttpSession newSession = request.getSession(true);
        attrNames = props.keys();

        while (attrNames.hasMoreElements()) {
            String key = (String) attrNames.nextElement();
            newSession.setAttribute(key, props.get(key));
        }
    }

Ответ 4

Является ли проблема, что JSESSIONID видна в браузере или что она вообще установлена ​​в cookie? Я предполагаю, что это последнее в вашем случае.

1.Сообщение нового файла cookie JSESSIONID после входа в систему

Это поведение по умолчанию Tomcat, если вы переключаетесь с http на https во время входа в систему. Старый отбрасывается и создается новый.

Если ваш вход в систему превышает http, я предполагаю, что еще одна проблема безопасности для аудиторов;)

Или все ваши страницы по https?

Ответ 5

Две вещи, которые я нашел, могут помочь другим.

  • Если вы используете Apache Wicket, есть решение для этого после версии 1.4. Мое приложение все еще на 1.3, поэтому я не понимал, но мне удалось легко подключить порт в моем собственном классе WebSession. Wicket 1.4 добавляет метод replaceSession() к WebSession, который отлично работает. Вы можете вызвать его сразу после аутентификации, и вы получите новый JSESSIONID. Это в основном решило эту проблему для меня. Подробнее здесь: https://issues.apache.org/jira/browse/WICKET-1767.

  • Доступен клапан Apache Tomcat после версии 5.5.29, который вы можете добавить в context.xml. Он будет обрабатывать выдачу нового JSESSIONID после аутентификации. Дополнительная информация доступна здесь: https://issues.apache.org/bugzilla/show_bug.cgi?id=45255. Вход для клапана будет выглядеть так: <Valve className="org.apache.catalina.authenticator.FormAuthenticator" changeSessionIdOnAuthentication="true"/>

Ответ 6

При использовании spring вы должны использовать SessionFixationProtectionStrategy.

<property name="sessionAuthenticationStrategy" ref="sas"/>
...
<bean id="sas" class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy"/>

Когда вы проверяете исходный код вы увидите, что это похоже на подход harsha89: он будет

  • создать новый сеанс
  • атрибуты переноса старого сеанса.

Ответ 7

Если вы используете Tomcat и хотите применить это глобально ко всем вашим сервлетам, использующим механизм аутентификации Tomcat, вы можете написать Valve, чтобы заставить это поведение, как показано в этом пример.

Ответ 8

Если вы используете более старую версию jboss, например jboss 4, то просто вызов request.getSession(true) после вызова session.invalidate() не изменит идентификатор сеанса.

Если вы не хотите использовать клапан и хотите изменить идентификатор сеанса в классе действий, то он может быть архивирован с использованием отражения, потому что CatalinaRequest будет недоступен непосредственно в вашем классе действий.

Пример кода

private HttpSession changeSessionId( HttpServletRequest request )
{
    HttpSession oldSession = request.getSession( false );
    HttpSession newSession = null;

    try
    {
        //get all cookies from request
        Cookie[] cookies = request.getCookies();

        //Get all attribute from old session
        Enumeration< Object > attrNames = oldSession.getAttributeNames();

        Properties attributFromOldSession = new Properties();

        while ( attrNames.hasMoreElements() )
        {
            String key = (String)attrNames.nextElement();
            attributFromOldSession.put( key, oldSession.getAttribute( key ) );
        }

        //Actual logic to change session id

        Field catalinaRequestField;

        //Getting actual catalina request using reflection
        catalinaRequestField = request.getClass().getDeclaredField( "request" );
        catalinaRequestField.setAccessible( true ); // grant access to (protected) field
        Request realRequest = (Request)catalinaRequestField.get( request );

        //Invalidating actual request
        realRequest.getSession( true ).invalidate();
        realRequest.setRequestedSessionId( null );
        realRequest.clearCookies();

        //setting new session Id
        realRequest.setRequestedSessionId( realRequest.getSessionInternal( true ).getId() );

        //Put back the cookies
        for ( Cookie cookie : cookies )
        {

            if ( !"JSESSIONID".equals( cookie.getName() ) )
            {
                realRequest.addCookie( cookie );
            }
        }

        // put attribute from old session
        attrNames = attributFromOldSession.keys();

        while ( attrNames.hasMoreElements() )
        {
            String key = (String)attrNames.nextElement();
            newSession.setAttribute( key, attributFromOldSession.get( key ) );
        }
    }
    catch ( Exception e )
    {
        e.printStackTrace();
    }
    return newSession;

}

Ответ 9

session=request.getSession(true);
Enumeration keys = session.getAttributeNames();     
HashMap<String,Object> hm=new HashMap<String,Object>();  
while (keys.hasMoreElements())
{
  String key = (String)keys.nextElement();
  hm.put(key,session.getValue(key));
  session.removeAttribute(key);      
}
session.invalidate();
session=request.getSession(true);
for(Map.Entry m:hm.entrySet())
{
  session.setAttribute((String)m.getKey(),m.getValue());  
  hm.remove(m);
}