0

I have a Spring 4 MVC + Security application that runs perfectly.

I am trying to integrate HDIV with it and have been through the documentation and the showcase example: https://github.com/hdiv/hdiv-spring-mvc-showcase/

When I use avoidValidationInUrlsWithoutParams = true, everything works fine till the point where I don't have parameters (Obviously).

When I remove that part, it just throws me to the Security-Error Page. I tried debugging and I see that Spring Security has authenticated successfully -- but HDIV throws the HDIV_PARAMETER DOES NOT EXIST error - this is what I have in the logs:

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;

Apparently, I understand that the page found HDIV_STATE from the number there, but it could not find the CSRF? (I, assume the 3 semicolons are for some paramter that HDIV was trying to find and that parameter is CSRF?)

Also, I am able to see the generated csrf on the index page (which makes me doubt if I have set up HDIV correctly because the last time, when I had tried it, all hidden fields would show up differently - either blank or 0, if I correctly remember.)

If so, I would like to know why and what can I do to resolve it?

This is what I have so far:

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>

spring-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" />

spring-web-config.xml

<mvc:annotation-driven validator="hdivEditableValidator"/>

...

applicationContext.xml

... has all the service/ dao layer component scan lines:

<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>

Any help would be appreciated.

2 Answers2

1

It seems that the problem is not related with CSRF.

Hdiv validates all incoming requests and in order to do that, all the URLs and parameters has to be rendered at server side using some of the supported technologies such as Spring MVC tags.

Are you using Spring MVC URL tag to render the URL included in the error file?

Once you use Spring MVC tag for that, Hdiv will include an additional parameter (HDIV_STATE) to the URL and you will avoid the issue.

This parameter makes possible the protection against any tampering attack to the defined URL.

Other possible solution is to eliminate the validation of this specific URL or URls types using URL exclusions, where Hdiv will not validate those URLs.

See this example: https://github.com/hdiv/hdiv-spring-mvc-showcase-jc/blob/master/src/main/java/org/hdiv/samples/mvc/config/HdivSecurityConfig.java where within addExclusions method are defined different exclusions.

Regards,

Roberto Velasco

Hdiv Security

rbelasko
  • 626
  • 3
  • 5
  • I have the same problem, but I have no clue what you mean with MVC URL Tag and what I need to change. Can you add some more details please? thx – megloff Jun 09 '17 at 12:01
0

I found a solution. HDIV requires that all links get enriched with a "_HDIV_STATE_" parameter in its URL. in order to achieve that you have to use taglib from HDIV and not the original JSTL taglib.

Please refer also to the reference documentation of HDIV

e.g. in your POM

    <dependency>
        <groupId>org.hdiv</groupId>
        <artifactId>hdiv-jstl-taglibs-1.2</artifactId>
        <version>${org.hdiv-version}</version>
    </dependency>

e.g. in your JSP (note the 'www.hdiv.org' in the taglib statement)

<%@ 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>

So you need to render the URL via th <c:url> utility tag. This renders then the URL with the required HDIV parameter i.e.

localhost:8080/spring-security-example/messages/message?_HDIV_STATE_=26-0-830046F08D66980D1B35F52F2D6677E0

Another option may be is to use the utility class from HDIV, see also class LinkUrlProcessor at the github repository of hdiv

LinkUrlProcessor urlProcessor = HDIVUtil.getLinkUrlProcessor(servletContext);
String processUrl = urlProcessor.processUrl(request, "/messages/messages");
megloff
  • 1,400
  • 4
  • 27
  • 44