У нас есть веб-приложение (5+ лет), которое использует функцию Spring Security (3.1) для аутентификации и авторизации пользователя.
Формат перенаправления:
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.
Мало что мы уже заметили:
- USER1, USER2 отправляют запрос одновременно, т. Е. В тот же час, минуты, секунды. Из журнала доступа видно, что запрос USER 2 идет первым, но с точки зрения ответа USER 1 получает ответ первым с URL-адресом перенаправления USER 2.
- Не вижу большой проблемы с генерацией кода доступа, так как мы видим, что для USER1, USER2 первоначальное перенаправление выхода из системы безопасности с пружиной, похоже, содержит правильные детали
- Как я понимаю, ELB не изменяет никакие подробности заголовка HTTP, кроме заголовков X-Forwarded- *.
- Оба запроса 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 и передаем его в ответ, но не смогли воспроизвести проблему.
Любые предложения или предложения будут полезны.