Search code examples
jspspring-mvcspring-securitycsrfcsrf-protection

_csrf token in 2 forms in the same JSP (CSRF protection)


I want to protect my application from Cross Site Request Forgery (CSRF) attacks, so I added this to my

applicationContext.xml:

<security:global-method-security secured-annotations="enabled" />

        <security:http auto-config="true">
            <security:csrf/>    
            <security:intercept-url pattern="/**" access="permitAll"    />
        </security:http>

<security:authentication-manager/>  

this to my web.xml

<!-- spring security csrf -->
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>fr.telecom.support.context.DevicesSecurityFilter</filter-class>
        </filter>    
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>

and this my filter

public class DevicesSecurityFilter extends DelegatingFilterProxy {

    public DevicesSecurityFilter() {
        // TODO Auto-generated constructor stub
    }

    public DevicesSecurityFilter(Filter delegate) {
        super(delegate);
    }

    public DevicesSecurityFilter(String targetBeanName) {
        super(targetBeanName);
    }

    public DevicesSecurityFilter(String targetBeanName,
            WebApplicationContext wac) {
        super(targetBeanName, wac);
    }

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain filterChain) throws ServletException, IOException {


        HttpServletRequest httpServletRequest;
        ThreadContext threadContext;

        if (request instanceof HttpServletRequest) {
            httpServletRequest = (HttpServletRequest) request;
            threadContext = ThreadContext.getInstance();

            try {
                EcasUser ecasUser = (EcasUser) httpServletRequest.getUserPrincipal();
                if (ecasUser != null) {
                    threadContext.setDomainUsername(ecasUser.getDomainUsername());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            threadContext.setUserID(httpServletRequest.getRemoteUser());
        }

        System.out.println ("filterChain -> " + filterChain );  

        if (filterChain != null) {

            filterChain.doFilter(request, response);

        }
    }

There is 1 JSP with 2 forms, as follows: When I submit the first form everything is fine, but when I submit the second, I have this error:

This error (HTTP 403 Forbidden) means that Internet Explorer was able to connect to the website, but it does not have permission to view the webpage. For more information about HTTP errors, see Help.

<form name="buttonpanelform1" action="products.do" method="POST">

  <input type="hidden" name="_csrf" value="470bb7e4-1985-42c8-92fe-0b5edbfcd432"/>

    <table align="center" border="0" cellpadding="10" cellspacing="0" width="100%">
       <tbody>
<tr>
    <td align="left">
    <input type="submit" name="btn_addItem" value="btn_addItem">
    </td>
    <td align="right">
       <input type="submit" name="btn_saveAndContinue" value="btn_saveAndContinue">
    </td>
</tr>
</tbody>
</table>
</form>


<form name="addItemForm" class="special" action="products.do" method="POST" enctype="multipart/form-data" style="clear:both;">

                        <input type="hidden" name="_csrf" value="470bb7e4-1985-42c8-92fe-0b5edbfcd432"/>


<table align="center" border="0" cellpadding="10" cellspacing="0" width="100%">
<tbody>
<tr>
<td align="left"></td>
<td align="right">
   <input type="submit" name="btn_saveItem" value="btn_saveItem">
</td>
</tr>
</tbody>
</table>
</form>

Solution

  • Your second form uses the multipart encoding therefor the spring security filter is unable to extract the posted csrf token. If your form needs this encoding (it is uploading a file) you have 2 possible solutions provided by the spring security documentation.

    Either make sure the multipart data is parsed before the request reaches the spring security filter chain or post the csrf token as as a request parameter in the form action attribute.

    For more information see: http://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-multipart