Spring中的AJAX和CSRF

时间:2013-04-30 07:39:43

标签: json spring jquery csrf spring-json

我在HTTP请求标头和POST隐藏字段中发送CSRF令牌,以防止CSRF攻击,如下所示。

var request;
var timeout;

function insert(callback)
{
    if(!request) 
    {
        CKEDITOR.instances.txtAboutProducts.updateElement();
        var contents=$("#txtAboutProducts").val();
        var csrf_token=$("#token").val();

        if(contents==null||contents=='')
        {
            alert("Please enter the contents.");
            return;
        }

        request = $.ajax({
            headers: { 
                    'Accept': 'application/json',
                    'Content-Type': 'application/json' 
                },
            datatype:"json",
            type: "POST",
            url: "../admin_side/AboutProducts.htm",
            data: JSON.stringify({"contents":contents, "token":csrf_token}),

            beforeSend: function (xhr)
            {
                xhr.setRequestHeader('X-CSRF-Token', csrf_token); 
            },
            success: function(response)
            {
                callback(response);
            },
            complete: function()
            {
                timeout = request = null;
            },
            error: function(request, status, error)
            {
                if(status!=="timeout"&&status!=="abort") // or just if(status==="error")
                {
                    alert(status+" : "+error);
                }
                callback(request);
            }
        });
        timeout = setTimeout(function() {
            if(request) 
            {
                request.abort();
                alert("The request has been timed out.");
            }
      }, 300000); //5 minutes.
    }
}

此函数用于插入CKEditor所持有的CMS内容,以便通过JSON(通过单击按钮时)对Spring进行POST AJAX调用来插入数据库。

函数体开头的条件检查if(!request){...}只是为了防止重复的AJAX调用(可能是由不耐烦的用户)。

一旦页面加载并在JavaScript变量中检索,随机生成的标记值就会存储在隐藏字段中。

var csrf_token=$("#token").val();

然后,以下处理程序设置一个标题,该标题将与请求一起发送。

beforeSend: function (xhr)
{
    xhr.setRequestHeader('X-CSRF-Token', csrf_token); 
},

为什么需要标头?作为隐藏字段发送的令牌是不是足够单独?是否有必要检查标题,因为旧的Flash播放器(仅作为示例)?


使用这种方法,在服务器端,我正在检查,如果标头和隐藏字段的值都匹配(同时检查会话中是否存在该标记{检查标记中是否存在标记会话没有提到虽然})。

上面提到的JavaScript函数调用的Spring控制器类中的方法如下。

@RequestMapping(value=("admin_side/AboutProducts"), method=RequestMethod.POST)
private @ResponseBody CKEditorContentsHandler insert(@RequestBody final CKEditorContentsHandler object, final HttpServletResponse response, final HttpServletRequest request)
{
    if(object!=null&&StringUtils.isNotBlank(object.getToken())&&StringUtils.isNotBlank(request.getHeader("X-CSRF-Token"))&&sessionTokenService.isTokenValid(object.getToken())&&object.getToken().equals(request.getHeader("X-CSRF-Token")))
    {
        aboutProductsService.insert(object.getContents());
        object.setMessage("Insertion done successfully.");
        object.setStatus(1);
    }
    else
    {
        object.setMessage("The authentication token cannot be verified.");
        object.setStatus(-1);
    }
    return object;
}

CKEditorContentsHandler,这个方法的第一个参数是一个简单的Java类,它只包含几个属性来满足需要。


还建议将令牌存储在cookie中,并将其与发布的数据(隐藏字段)一起发送,并检查发布的数据和cookie值是否匹配。如果他们不这样做,则可能是CSRF哎呀(因为相同的原始政策,攻击者无法在受害者的浏览器上读取或修改cookie。)

之后,为什么需要标题?实际上,什么是防范(或至少减轻)CSRF攻击的推荐方法?


以下答案总结得很清楚。

anti-CSRF token and Javascript

0 个答案:

没有答案