4

Is it possible to configure CSRF protection in grails3 app using spring-security plugin, I can't find anything except useToken attribute for grails form and then call withForm inside controller. But this is actually not a very flexible solution. I like approach with filter like here

Lifeweaver
  • 986
  • 8
  • 29
enzo
  • 287
  • 5
  • 12

2 Answers2

14

For csrf protection I reused org.springframework.security.web.csrf.CsrfFilter. You need to define new bean in grails resouces.groovy (See snipet below - csrfFilter bean). You can define your own accessDeniedHandler and requireCsrfProtectionMatcher. Here is the snippet from resources.groovy:

csrfFilter(CsrfFilter, new HttpSessionCsrfTokenRepository()) {
    accessDeniedHandler = ref('fnAccessDeniedHandler')
    requireCsrfProtectionMatcher = ref('fnRequireCsrfProtectionMatcher')
}

Now in Bootstrap.groovy add this filter into filter chain:

 SpringSecurityUtils.clientRegisterFilter('csrfFilter',    SecurityFilterPosition.LAST.order + 10)

Now in your main layout GSP add following tags to add csrf token on each page:

<meta name="_csrf" content="${_csrf?.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf?.headerName}"/>

So now csrf token presented on each page of your app, you can use it for each ajax request for example (snippet from application.js (I'm using grails 3)):

$(function () {
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) {
        xhr.setRequestHeader(header, token);
    });
});

For each jquery ajax request we are sending csrf token now.

enzo
  • 287
  • 5
  • 12
  • 6
    Would you mind sharing an example of your custom *accessDeniedHandler* and *requireCsrfProtectionMatcher* classes? – Todd Sharp Jul 12 '17 at 14:34
  • Old thread but in case it helps, see: https://stackoverflow.com/questions/48307781/how-to-write-accessdeniedhandler-in-grails https://stackoverflow.com/questions/31098323/scpting-security-requirecsrfprotectionmatcher-with-csrftokenrepository – jambox Sep 07 '18 at 22:51
4

You can implement it with <g:form> tag:

Example:

<g:form useToken="true" uri="/logout">

Documentation: http://grails.github.io/grails-doc/latest/guide/single.html#formtokens

In my case, I'm using Spring code, so, additionally, I should add manually a _csrf hidden field in the form.

<g:form useToken="true" uri="/logout">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    <input type="submit">Logout</input>
</g:form>

Result:

<form action="/nacho/logout" method="post" >

    <!-- this two lines are added automatically by Grails -->
    <input type="hidden" name="SYNCHRONIZER_TOKEN" value="883a1037-a2c9-4997-8254-e59da6303494" id="SYNCHRONIZER_TOKEN" />
    <input type="hidden" name="SYNCHRONIZER_URI" value="/nacho/userInfo" id="SYNCHRONIZER_URI" />

    <!-- this line was added by myself, but, using the ${_csrf} variable -->
    <input type="hidden" name="_csrf" value="0928f13c-02aa-4122-8ebe-a1239855a85b"/>

    <input type="submit">Logout</input>
</form>
Ignacio Ocampo
  • 2,693
  • 1
  • 20
  • 31
  • 3
    Yes, but then on the backend you always should use withForm method, this is ugly solution. The best option is to use CrsfFilter from spring security, I managed to set it up, now it works fine, but thank you for reply :) – enzo Mar 21 '16 at 20:16
  • 1
    @enzo Could you share your configuration? Perhaps by submitting it as an answer to this question? Would be much appreciated! – Ed J Jun 27 '16 at 07:38
  • @EdJ see my answer above, ask me if you have any questions. – enzo Jun 27 '16 at 12:20
  • @enzo one question friend: I have multiples form in my project. Should i add in my main.gsp: $(function () { var token = $("meta[name='_csrf']").attr("content"); var header = $("meta[name='_csrf_header']").attr("content"); $(document).ajaxSend(function(e, xhr, options) { xhr.setRequestHeader(header, token); }); }); – sirdaiz Nov 19 '20 at 13:28