Сессия пользователя перепутала :: Spring Security - PullRequest
0 голосов
/ 24 апреля 2019

У нас есть веб-приложение (5+ лет), которое использует функцию Spring Security (3.1) для аутентификации и авторизации пользователя.

  • В рамках процесса аутентификации мы создаем случайный 20-значный код доступа (ac) и 5-значный номер пользователя (un)
  • После успешной аутентификации мы перенаправляем в другое приложение, передавая код доступа, номер пользователя в качестве параметров запроса
  • На основе кода доступа APP2 отображает информацию для соответствующих пользователей

    Ниже приведен пример потока и пример формата перенаправления безопасности пружины:

enter image description here

Формат перенаправления:

https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/abc/AccessServlet?ac=astqcssq-Z-3R2LOFjy-&un=12345

Поток кода Аутентификации

@RequestMapping(value="/Authentication.do")
public String doWAuthentication(ModelMap model) {

    User user = super.getUser();        

    String url = app2Baseroot; // instance variable - APP2 Host name

    //generate parameters - static methods
    String accessCode = Utils.generateString(20);
    String userNo = Utils.generateUserNumber(5);

    //write authentication details for APP2 to retrieve
    userDao.saveAuthenticationDetails(user, accessCode, userNo);

    //Add redirection specifics - servlet name & query params
    try {
        url += java.net.URLEncoder.encode("AccessServlet?ac="+accessCode+"&un="+userNo, "UTF-8");
    } catch (UnsupportedEncodingException uee) {

        LOG.error("Unable to encode redirect URL: "+uee.toString());
    }

    //redirect via spring security logout
   // AuthBaseroot - Instance variable - APP1 host name
    return "redirect:"+AuthBaseroot+"j_spring_security_logout?redirectUrl="+url;
}

Недавно мы столкнулись с проблемой, когда ПОЛЬЗОВАТЕЛЬ 1 смог просмотреть детали ПОЛЬЗОВАТЕЛЯ 2, так как URL перенаправления был перепутан. Оба пользователя получили доступ к приложению аутентификации в одно и то же время, то есть в один и тот же час, минуты, секунды.

Мы определили пользовательский вход в форму с помощью свойства always-use-default-target , установленного в « true », а также настроили пользовательский обработчик выхода из системы в XML-файле безопасности весны:

<sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />

LogoutSuccessHandler Расширяет SimpleUrlLogoutSuccessHandler и переопределяет onLogoutSuccess. Все, что делает метод - это получает URL перенаправления из запроса HttpServletRequest и устанавливает его на

AbstractAuthenticationTargetUrlRequestHandler. setDefaultTargetUrl (URL) и вызов метода super (super.onLogoutSuccess).

public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {

    //Set redirection to APP2 url containing security params
    super.setDefaultTargetUrl(request.getParameter("redirectUrl"));

    super.onLogoutSuccess(request, response, authentication);
}
  • Наше приложение размещено в AWS и использует классический ELB и как часть безопасности весь поток запросов через incapsula imperva
  • В ELB включена функция Stickiness для « сгенерированной приложением липкости cookie »
  • Мы также включили журналы доступа на уровне ELB и, проверяя журналы доступа, видим, что URL перенаправления перепутан для USER1, USER2

Ниже приведен пример журналов доступа для справки для USER1, USER 2

ПОЛЬЗОВАТЕЛЬ 2:

2019-04-20T09:34:11.328056Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000171 0.050725 0.0001 302 302 0 321 
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345 
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

2019-04-20T09:34:11.413849Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000074 0.003343 0.000073 200 200 0 799 
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345
HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

Журналы доступа USER 2 подтверждают URL-адрес перенаправления из весеннего выхода из системы безопасности, j_spring_security_logout совпадает с фактическим перенаправлением.

USER 1

2019-03-26T09:34:11.349198Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000137 0.030374 0.00011 302 302 0 321
"GET https://APP1_HOST:PORT/auth/j_spring_security_logout?redirectUrl=https://APP2_HOST/link/AccessServlet%3Fac%3Dn--qcvnq-Z-3R2LOFjy-%26un%3D13267 
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

2019-03-26T09:34:11.408386Z XXX.XXX.XX.XX:XXXXX XX.XXX.XXX.XXX:80 0.000066 0.007958 0.000077 200 200 0 1365 
"GET https://APP2_HOST/link/AccessServlet%3Fac%3DWA-FF7WlNowjyu2R-XaU%26un%3D12345 
HTTP/1.1" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/73.0.3683.86 Safari/537.36" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2

Первый оператор показывает j_spring_security_logout с правильным URL-адресом перенаправления для USER 1, но последующий вызов URL-адреса перенаправления, похоже, перепутался с USER 2. Поскольку пользовательские данные основаны на коде доступа, USER 1 был возможность просматривать данные пользователя USER 2.

Мало что мы уже заметили:

  1. USER1, USER2 отправляют запрос одновременно, т. Е. В тот же час, минуты, секунды. Из журнала доступа видно, что запрос USER 2 идет первым, но с точки зрения ответа USER 1 получает ответ первым с URL-адресом перенаправления USER 2.
  2. Не вижу большой проблемы с генерацией кода доступа, так как мы видим, что для USER1, USER2 первоначальное перенаправление выхода из системы безопасности с пружиной, похоже, содержит правильные детали
  3. Как я понимаю, ELB не изменяет никакие подробности заголовка HTTP, кроме заголовков X-Forwarded- *.
  4. Оба запроса USER1 и USER2 были обработаны одним и тем же экземпляром EC2. Поведение классического ELB по умолчанию - направлять каждый запрос независимо к зарегистрированному экземпляру с наименьшей нагрузкой. Поскольку мы настроили функцию прикрепления сеанса, которая позволяет балансировщику нагрузки привязывать сеанс пользователя к конкретному экземпляру. Это гарантирует, что все запросы от пользователя во время сеанса отправляются одному и тому же экземпляру. REF: https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-sticky-sessions.html

Ниже представлена ​​технология, используемая в модуле аутентификации

  • Java - 1.6
  • Spring MVC, Spring Security (версия 3.1)
  • Servlet API - 2.4
  • Сервер OC4J (10.1.3.5)
  • Развернуто в AWS - используется классический ELB

Я шОбнаружение, если проблема связана с уровнем безопасности Spring (возможно, обработчиком выхода из системы), где мы выбираем URL перенаправления из объекта HttpServletRequest и передаем его в ответ, но не смогли воспроизвести проблему.

Любые предложения или предложения будут полезны.

1 Ответ

0 голосов
/ 26 апреля 2019

Мы определили пользовательский обработчик успеха выхода из системы, как показано ниже

<sec:logout success-handler-ref="logoutSuccessHandler" invalidate-session="true" delete-cookies="JSESSIONID" />
  • класс logoutSuccessHandler расширяет класс SimpleUrlLogoutSuccessHandler, который, в свою очередь, расширяет AbstractAuthenticationTargetUrlRequestHandler.
  • SimpleUrlLogoutSquutler1007 *
  • В моем случае logoutSuccessHandler является одноэлементным, как и суперкласс
  • Метод переопределения onLogoutSuccess в моем logoutSuccessHandler обновляет значение DefaultTargetUrl из запроса и вызывает метод super.handle

    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws IOException, ServletException {
    
    super.setDefaultTargetUrl(request.getParameter("redirectUrl"));
    
    super.onLogoutSuccess(request, response, authentication);
    

    }

DefaultTargetUrl - переменная экземпляра AbstractAuthenticationTargetUrlRequestHandler.class.

В моем сценарии проблемы оба пользователя (USER1, USER2) были обработаны / обработаны в одном и том же экземпляре и запрос получен в то же время.Так как пользовательский обработчик, компоненты пружины являются одноэлементными, а вышеприведенные 2 шага не являются атомарными, существует возможность для потока (t01) переопределить DefaultTargetUrl, установленный другим потоком (t02).

...