HDIV + Spring Security 4: HDIV_PARAMETER_DOES_NOT_EXIST
У меня есть приложение Spring 4 MVC + Security, которое отлично работает.
Я пытаюсь интегрировать HDIV с ним и прошел через документацию и пример витрины: https://github.com/hdiv/hdiv-spring-mvc-showcase/
Когда я использую avoValidationInUrlsWithoutParams = true, все работает нормально до точки, где у меня нет параметров (очевидно).
Когда я удаляю эту часть, она просто перебрасывает меня на страницу ошибки безопасности. Я попытался отладить, и я вижу, что Spring Security успешно прошла проверку подлинности - но HDIV выдает ошибку HDIV_PARAMETER NOTISIST - это то, что у меня есть в журналах:
2016-07-27 08:24:34 [http-apr-8080-exec-5] INFO org.hdiv.logs.Logger - HDIV_PARAMETER_DOES_NOT_EXIST;/EmployeePortal/modules/dashboard.htm;177622190;;;127.0.0.1;127.0.0.1;MALLIKAM;
Видимо, я понимаю, что страница нашла HDIV_STATE по номеру там, но она не смогла найти CSRF? (Я предполагаю, что 3 точки с запятой для некоторого параметра, который HDIV пытался найти, и этот параметр - CSRF?)
Кроме того, я могу видеть сгенерированный файл csrf на странице индекса (что заставляет меня сомневаться, правильно ли я настроил HDIV, потому что в последний раз, когда я его пробовал, все скрытые поля показывались по-разному - либо пустыми, либо 0, если я правильно помню.)
Если так, я хотел бы знать, почему и что я могу сделать, чтобы решить это?
Это то, что я до сих пор:
web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml, /WEB-INF/spring-security.xml, /WEB-INF/hdiv-config.xml, ...</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- For HTTPSession events -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<!-- HDIV Listener -->
<listener>
<listener-class>org.hdiv.listener.InitListener</listener-class>
</listener>
<filter>
<filter-name>ValidatorFilter</filter-name>
<filter-class>org.hdiv.filter.ValidatorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ValidatorFilter</filter-name>
<!-- Spring MVC Servlet name-->
<servlet-name>serv1</servlet-name>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>serv1</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-web-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>serv1</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
весна-security.xml
<!-- To let spring create login page -->
<http auto-config="false" disable-url-rewriting="true"
use-expressions="true">
<access-denied-handler ref="accessDeniedHandler" />
<!-- CSRF is enabled by default Spring 4 onwards -->
<!-- check roles -->
<intercept-url pattern="/modules/favicon.ico" access="isAnonymous()" />
<intercept-url pattern="/login.htm" access="isAnonymous()" />
<intercept-url pattern="/login.htm?error" access="isAnonymous()" />
<intercept-url pattern="/logout" access="isAnonymous()" />
<intercept-url pattern="/modules/**" access="hasAnyRole('ROLE_y','ROLE_x')" />
<form-login login-page="/" default-target-url="/modules/dashboard.htm"
username-parameter="username" password-parameter="password"
authentication-failure-url="/login.htm?error" />
<custom-filter after="SECURITY_CONTEXT_FILTER" ref="hdivFilter" />
<!-- Logout -->
<logout logout-url="/logout.htm" delete-cookies="JSESSIONID"
invalidate-session="true" logout-success-url="/login.htm" />
<!-- Session Management: Invalid Session Url is for SessionTimeout as well
as invalid login -->
<session-management session-fixation-protection="newSession"
invalid-session-url="/login.htm" session-authentication-error-url="/login.htm">
<!-- Concurrency control is to check number of sessions and act accordingly.
Error If Max exceeded stops a user from logging in if max-sessions have been
exceeded. Expired Url is different from invalid url. -->
<concurrency-control max-sessions="2"
expired-url="/login.htm" error-if-maximum-exceeded="true" />
</session-management>
</http>
<!-- Spring security authentication manager -->
<authentication-manager alias="authenticationManager">
<!-- Custom Auth Provider checks for login with DB and LDAP both -->
<authentication-provider ref="customAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<!-- Bean implements AuthenticationProvider and checks if user is valid -->
<beans:bean id="customAuthenticationProvider"
class="..employeeportal.common.util.CustomAuthenticationProvider">
<beans:property name="passwordEncoder" ref="encoder" />
</beans:bean>
<!-- BCrypt Password encoder -->
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />
<!-- Access Denied Handler -->
<beans:bean id="accessDeniedHandler"
class="..employeeportal.common.util.AccessDeniedHandler">
</beans:bean>
<beans:bean id="hdivFilter" class="org.hdiv.filter.ValidatorFilter" />
весна-веб-config.xml
<mvc:annotation-driven validator="hdivEditableValidator"/>
...
applicationContext.xml
... имеет все строки сканирования компонентов уровня сервиса / дао:
<context:component-scan
base-package="..common.service, ..common.dao" />
hdiv-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:hdiv="http://www.hdiv.org/schema/hdiv"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.hdiv.org/schema/hdiv http://www.hdiv.org/schema/hdiv/hdiv.xsd">
<hdiv:config excludedExtensions="css,ico,js,woff,woff2,ttf,jpg,jpeg,png,gif,eot"
errorPage="/security-error" randomName="true" confidentiality="true" debugMode="true">
<hdiv:startPages method="get">/,/login.htm</hdiv:startPages>
<hdiv:startPages method="post">/logout, /logout.htm</hdiv:startPages>
<hdiv:startParameters>_csrf</hdiv:startParameters>
</hdiv:config>
<!-- Accepted pattern within the application for all editable parameters (generated from textbox and textarea) -->
<hdiv:validation id="safeText">
<hdiv:acceptedPattern><![CDATA[^[a-zA-Z0-9@.\-_]*$]]></hdiv:acceptedPattern>
</hdiv:validation>
<!-- Finally, it's necessary to define editable data validation list for
the application -->
<hdiv:editableValidations>
<hdiv:validationRule url="/modules/.*"></hdiv:validationRule>
<hdiv:validationRule url="/modules/.*" enableDefaults="false">safeText</hdiv:validationRule>
</hdiv:editableValidations>
index.jsp
<form:form name='loginForm' modelAttribute="loginForm"
action="login" method='POST'>
<div class="form-group">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-user"></i></span>
<form:input path="username" name="username" id="username"/>
</div>
</div>
<div class="form-group">
<div class="input-group">
<form:input path="password" id="password" name="password"/>
</div>
</div>
<div class="form-group no-border margin-top-20">
<input type="submit"
class="btn btn-success btn-block" value="Submit" />
</div>
</form:form>
Любая помощь будет оценена.
2 ответа
Кажется, что проблема не связана с CSRF.
Hdiv проверяет все входящие запросы, и для этого все URL-адреса и параметры должны отображаться на стороне сервера с использованием некоторых поддерживаемых технологий, таких как Spring MVC-теги.
Используете ли вы URL-тег Spring MVC для отображения URL, включенного в файл ошибок?
Как только вы используете для этого тег Spring MVC, Hdiv добавит в URL дополнительный параметр (HDIV_STATE), и вы избежите этой проблемы.
Этот параметр делает возможной защиту от любой несанкционированной атаки на определенный URL.
Другое возможное решение состоит в том, чтобы исключить проверку этого конкретного типа URL или URls с помощью исключений URL, где Hdiv не будет проверять эти URL.
Посмотрите этот пример: https://github.com/hdiv/hdiv-spring-mvc-showcase-jc/blob/master/src/main/java/org/hdiv/samples/mvc/config/HdivSecurityConfig.java где находится внутри addExclusion Методом определены разные исключения.
С Уважением,
Роберто Веласко
Hdiv Security
Я нашел решение. HDIV требует, чтобы все ссылки были обогащены параметром "_HDIV_STATE_" в его URL. для этого вам нужно использовать taglib из HDIV, а не оригинальную JSTL taglib.
Пожалуйста, обратитесь также к справочной документации HDIV
например, в вашем POM
<dependency>
<groupId>org.hdiv</groupId>
<artifactId>hdiv-jstl-taglibs-1.2</artifactId>
<version>${org.hdiv-version}</version>
</dependency>
например, в вашем JSP (обратите внимание на "www.hdiv.org" в выражении taglib)
<%@ taglib prefix="c" uri="http://www.hdiv.org/jsp/jstl/core"%>
<c:url value="/messages/messages" var="url" />
<li><a href="${url}">Messages</a></li>
Так что вам нужно отрендерить URL через <c:url>
служебный тег. Затем отображается URL с обязательным параметром HDIV, т.е.
localhost:8080/spring-security-example/messages/message?_HDIV_STATE_=26-0-830046F08D66980D1B35F52F2D6677E0
Другим вариантом может быть использование служебного класса из HDIV, см. Также класс LinkUrlProcessor в репозитории github в hdiv
LinkUrlProcessor urlProcessor = HDIVUtil.getLinkUrlProcessor(servletContext);
String processUrl = urlProcessor.processUrl(request, "/messages/messages");