Grails - Existe uma maneira recomendada de lidar com ataques de CSRF em formas AJAX?

Estou usando o padrão de token de sincronizador para formulários padrão (useToken = true), mas não consigo encontrar nenhum método recomendado para lidar com isso no AJAX.

EDITAR

Desde que publiquei isso, criei minha própria solução incorporando o padrão existente Grails de cima.

No jQuery ajax, eu posto o formulário inteiro (que incluirá os campos ocultos injetados SYNCHRONIZER_TOKEN e SYNCHRONIZER_URI do Grails), para que o fechamento withForm possa funcionar como esperado no controlador.

O problema é que, em resposta bem-sucedida, não há novo conjunto de tokens (como a página não é recarregada e o taglib g: form não é evocado) e, portanto, faço isso manualmente no controlador chamando a mesma biblioteca que o g: form taglib e retorne-o na resposta ajax e, em seguida, redefina o valor do campo oculto. Ver abaixo:

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);
    }
})

no controlador:

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
}

Alguém pode identificar se eu, sem saber, introduzi uma falha de segurança na solução acima. Parece-me adequado, mas não gosto de rolar à mão nada a ver com segurança.

questionAnswers(1)

yourAnswerToTheQuestion