How to enable CSRF protection in JSF-Spring integrated application

后端 未结 1 1751
一个人的身影
一个人的身影 2021-01-07 07:25

I have a JSF-Spring integrated application. Spring security is also integrated in this application. These are the versions in my application:

  • JSF 2.2
相关标签:
1条回答
  • 2021-01-07 07:28

    Tested with Spring 4.3.7 and Spring Security 4.2.2.

    You need to add a CSRF token to every form in your application. Any PATCH, POST, PUT and DELETE will be protected by Spring security (for the basic verbs). To avoid inserting a hidden input in every form manually you can create a FormRenderer on top of the provided one :

    import com.sun.faces.renderkit.html_basic.FormRenderer;
    
    import javax.el.ELContext;
    import javax.el.ExpressionFactory;
    import javax.faces.component.UIComponent;
    import javax.faces.context.FacesContext;
    import javax.faces.context.ResponseWriter;
    import java.io.IOException;
    
    public class FormWithCSRFRenderer extends FormRenderer {
    
        @Override
        public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
            log.debug("FormWithCSRFRenderer - Adding CSRF Token to form element");
            ELContext elContext = context.getELContext();
            ExpressionFactory expFactory = context.getApplication().getExpressionFactory();
    
            ResponseWriter writer = context.getResponseWriter();
            writer.startElement("input", component);
            writer.writeAttribute("type", "hidden", null);
            writer.writeAttribute("name", expFactory.createValueExpression(elContext, "${_csrf.parameterName}", String.class).getValue(elContext), null);
            writer.writeAttribute("value", expFactory.createValueExpression(elContext, "${_csrf.token}", String.class).getValue(elContext), null);
            writer.endElement("input");
            writer.write("\n");
            super.encodeEnd(context, component);
        }
    }
    

    Then register it to override the FormRenderer by setting it in faces-config.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
                  version="2.2">
        <render-kit>
            <renderer>
                <component-family>javax.faces.Form</component-family>
                <renderer-type>javax.faces.Form</renderer-type>
                <renderer-class>com.acme.FormWithCSRFRenderer</renderer-class>
            </renderer>
        </render-kit>
    </faces-config>
    

    Also don't forget to enable CSRF in your spring context :

    <security:http auto-config="true" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint"
                   use-expressions="true">
        <security:csrf/>
        <security:access-denied-handler error-page="/exception/accessDenied.xhtml"/>
    
        <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMINISTRATOR','ROLE_GUEST')"/>
        <security:intercept-url pattern="/exception/accessDenied.xhtml" access="permitAll"/>
    </security:http>
    

    For your AJAX calls, you will also need to add this token in the data of any protected HTTP Verb. You can retrieve the token directly from the DOM.

    0 讨论(0)
提交回复
热议问题