#jsp #spring-mvc #https #spring-security #load-balancing
#jsp #spring-mvc #https #spring-безопасность #балансировка нагрузки
Вопрос:
Прямо сейчас балансировщики нагрузки обрабатывают https, а затем передают этот https на мои веб-серверы. Таким образом, обработка https удваивается для каждого запроса. То, что я хочу сделать, это полностью разгрузить https, чтобы моим веб-серверам не приходилось иметь с этим дело.
Как мне настроить страницы Spring Security и JSP, учитывая, что веб-серверы считают, что все запросы являются http? Очевидно, мне придется изменить <intercept-url>
элементы моей конфигурации, чтобы их requires-channel
атрибут всегда был http
или any
. На моих страницах JSP мне придется добавлять <c:url value=''/>
ссылки с ${secureUrl}
помощью и ${nonSecureUrl}
в зависимости от того, должна ли результирующая страница быть https или http. Перенаправления с контроллеров также должны быть изменены подобным образом… Что-нибудь еще?
Кажется, довольно сложно изменить все ссылки на страницах JSP, чтобы включить схему и хост. Есть ли лучший способ сделать это?
Ответ №1:
Если вы завершаете работу SSL на балансировщике нагрузки, ваш балансировщик нагрузки должен отправить заголовок, указывающий, какой протокол был запрошен изначально. Например, F5 добавляет X-Forwarded-Proto .
Отсюда вы можете создавать пользовательские ChannelProcessor
s, которые просматривают этот заголовок вместо просмотра request.isSecure()
. Затем вы можете продолжить использовать <intercept-url requires-channel="https">
и relative <c:url>
.
Шаги:
-
Переопределение подклассов SecureChannelProcessor и InsecureChannelProcessor
decide()
.decide()
Проверьте заголовок, отправленный вашим балансировщиком нагрузки.@Override public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException { for (ConfigAttribute attribute : config) { if (supports(attribute)) { if (invocation.getHttpRequest(). getHeader("X-Forwarded-Proto").equals("http")) { entryPoint.commence(invocation.getRequest(), invocation.getResponse()); } } } }
-
Затем установите эти ChannelProcessors в компоненте ChannelDecisionManagerImpl с помощью a
BeanPostProcessor
. См. Этот Часто задаваемые вопросы по безопасности Spring о том, почему / как использовать aBeanPostProcessor
для этого.
Комментарии:
1. попробовал вышеуказанные шаги, метод decide не вызывается, есть ли что-нибудь еще, что нам нужно настроить?
Ответ №2:
Чтобы завершить отличный ответ на sourcedelica, вот полный код :
Для шага 1 :
@Component
public class SecureChannelProcessorHack extends SecureChannelProcessor {
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if ("http".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(),
invocation.getResponse());
}
}
}
}
}
@Component
public class InsecureChannelProcessorHack extends InsecureChannelProcessor {
@Override
public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
for (ConfigAttribute attribute : config) {
if (supports(attribute)) {
if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
getEntryPoint().commence(invocation.getRequest(),
invocation.getResponse());
}
}
}
}
}
И шаг 2 :
@Configuration
public class LoadBalancerHack implements BeanPostProcessor {
@Inject
SecureChannelProcessorHack secureChannelProcessorHack;
@Inject
InsecureChannelProcessorHack insecureChannelProcessorHack;
@Value("${behind.loadbalancer?false}")
boolean behindLoadBalancer;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (behindLoadBalancer amp;amp; bean instanceof ChannelDecisionManagerImpl) {
System.out.println("********* Post-processing " beanName);
((ChannelDecisionManagerImpl) bean).setChannelProcessors(newArrayList(
insecureChannelProcessorHack,
secureChannelProcessorHack
));
}
return bean;
}
}
Ответ №3:
Похоже, Grails поддерживает это как часть плагина безопасности. Проверьте нижнюю часть http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/17 Channel Security.html где они говорят о проверке заголовков запросов, которые установит LB.
grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
grails.plugins.springsecurity.secureChannel.secureHeaderName = '...'
grails.plugins.springsecurity.secureChannel.secureHeaderValue = '...'
grails.plugins.springsecurity.secureChannel.insecureHeaderName = '...'
grails.plugins.springsecurity.secureChannel.insecureHeaderValue = '...'