Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

security - Grails - Is there a recommended way of dealing with CSRF attacks in AJAX forms?

I am using the Synchronizer Token Pattern for standard forms (useToken = true) but I cannot find any recommended method of dealing with this over AJAX.

EDIT

Since posting this, I have rolled my own solution incorporating Grails existing pattern from above.

In the jQuery ajax I post the entire form (which will include Grails' injected SYNCHRONIZER_TOKEN and SYNCHRONIZER_URI hidden fields) such that the withForm closure can perform as expected in the controller.

The problem is, on successful response, there is no new token set (as the page is not reloaded and the g:form taglib is not evoked) and so I do this manually in the controller calling into the same library as the g:form taglib, and return it in the ajax response, and then reset the hidden field value. See below:

var formData = jQuery("form[name=userform]").serializeArray();

$.ajax({
    type: 'POST',
    url: 'delete',
    data: formData,
    success: function (data) {
        // do stuff
    },
    complete: function (data) {
        // Reset the token on complete
        $("#SYNCHRONIZER_TOKEN").val(data.newToken);
    }
})

in the Controller:

def delete(String selectedCommonName) {

    def messages = [:]
    withForm {
        User user = User.findByName(name)

        if (user) {
            userService.delete(user)
            messages.info = message(code: 'user.deleted.text')

        } else {
            messages.error = message(code: 'user.notdeleted.text')
        }
    }.invalidToken {
            messages.error = message(code: 'no.duplicate.submissions')
    }
    // Set a new token for CSRF protection
    messages.newToken = SynchronizerTokensHolder.store(session).generateToken(params.SYNCHRONIZER_URI)
    render messages as JSON
}

Can anyone identify if I have unknowingly introduced a security flaw in the above solution. It looks adequate to me but I don't like hand rolling anything to do with security.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Nice!

IMO, you'd better reset the token at the same time.

SynchronizerTokensHolder.store(session).resetToken(params.SYNCHRONIZER_URI)

and if you have multiple forms in the same page, define a variable to hold tokens returned from each ajax request.

btw, why not implement the token pattern on your own?

  • Generate a token, e.g., UUID.randomUUID().toString(), and store it into session with the url as the key.
  • Check and reset the token at the satrt of post actions.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...