xmlHttp.getResponseHeader + 不适用于 CORS

Posted

技术标签:

【中文标题】xmlHttp.getResponseHeader + 不适用于 CORS【英文标题】:xmlHttp.getResponseHeader + Not working for CORS 【发布时间】:2013-01-19 03:42:10 【问题描述】:

我在 .NET 4 上有一个 asp.NET WCF。该服务用于对用户进行身份验证。我们正在提交用户名和密码,然后应该返回一个包含身份验证 cookie 的 HTTP 标头。使用本地托管的测试页面可以正常工作。我现在正在尝试跨域访问标头信息。我已经在另一台机器上安装了我的测试页面并配置为调用 WCF。通话正常,通话中的“数据”回复正确。但是,我无法通过以下任一方式访问标题信息:

alert(xmlHttp.getAllResponseHeaders());

alert(xmlHttp.getResponseHeader("Set-Cookie"));

使用 IE 中的调试器和 Firefox 的“实时 HTTP 标头”插件,我可以看到正在返回标头信息。

在我的全局 ajax 页面中,我将响应设置为处理 CORS。

private void EnableCrossDomainAjaxCall()

    HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");


    if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
    

        HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");

        HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
        HttpContext.Current.Response.End();
    


这是我用来调用服务的 AJAX:

$("#btnLogin").click(function(e) 
    var geturl;
    geturl = $.ajax(
        // type: "POST",
        type: "GET",
        contentType: "application/json; charset=utf-8",
        url: 'http://10.0.4.66/AuthenticationService.svc/Login?Name=test&password=pwsd',
        // url: '../SecurityServer/AuthenticationService.svc/Login?Name=test&password=pwsd',
        dataType: "jsonp",
        error: function(request, status, error) 
            alert('Error Occured');
        ,
        crossdomain: true,
        success: function(data, textStatus, xmlHttp) 
            // alert(xmlHttp.getResponseHeader("Content-Type"));
            document.write(xmlHttp.getResponseHeader("Content-Type") + "<br/>");
            alert(xmlHttp.getAllResponseHeaders());
            alert(xmlHttp.getResponseHeader("Set-Cookie"));
            var headers = '';
            var headerPair = xmlHttp.getAllResponseHeaders('wcfCookie').split("\r\n");
            var output = '';
            $.each(headerPair, function(key, line) 
                var parts = line.split(':');

                if (parts[0] == 'wcfCookie') 
                  ChocChip = parts[1]
                  return false
                

            );
        
    );

以下是我从“实时 HTTP 标头”中获取的标头信息

Date: Mon, 04 Feb 2013 12:12:40 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 4.0.30319
Access-Control-Allow-Origin: *
Set-Cookie: wcfCookie=8D38D5D6A0F138FEB595DD016F7694EDDF3E6757C82ED3D419F5047A5294974C1885487465CEC0A0BCC2B3802C7B03FF9F5370A05D4CCBDDDABCB1558C3816044BF4F78209BF38C6B1A7CAD34CD3C85C40B8515CFB1C2B2694BC78803D8DACB4
Content-Length: 65
Cache-Control: application/json; charset=utf-8
Content-Type: application/x-javascript

【问题讨论】:

【参考方案1】:

首先,有一点背景:

您正在使用Access-Control-Allow-Headers,它指定允许客户端发送请求标头,但您没有指定响应允许客户端读取的标头。要允许客户端读取非简单响应头,您需要使用Access-Control-Expose-Headers。来自html5 Rocks CORS page:

在 CORS 请求期间,getResponseHeader() 方法只能访问简单的响应标头。简单的响应头定义如下:

缓存控制 内容-语言 内容类型 过期 最后修改 编译指示

如果您希望客户端能够访问其他标头,则必须使用 Access-Control-Expose-Headers 标头。此标头的值是您要向客户端公开的以逗号分隔的响应标头列表。

因此,鉴于这些新信息,您可能会这样做:

HttpContext.Current.Response.AddHeader("Access-Control-Expose-Headers", "Set-Cookie");

...但不止于此。

现在,实际答案:

这里还有一个更严重的问题:XHR 规范explictily disallows reading Set-Cookie。这是因为这在功能上是一种跨域 cookie 窃取攻击

假设域 A 向域 B 发出跨域请求。当域 B 设置 cookie 时,它​​为域 B 设置特定于域的 cookie。域 A 读取域 B 的 cookie 的任何尝试都违反了 cookie 访问的同源策略。

我不知道 WCF,所以我不确定 实际上 做你想做的事的最佳方法,但我猜解决方案可能是传递一个身份验证令牌而不是通过域 A 读取并设置自己的 cookie 的 cookie(例如,X-WCF-Auth 标头?)。

【讨论】:

【参考方案2】:

浏览器的安全策略可能会阻止您的响应,因为您没有设置:

HttpContext.Current.Response.AddHeader("Access-Control-Allow-Credentials","true");

如果没有帮助,请尝试添加

xhrFields:  withCredentials: true 

您的ajax 选项可能也值得一试。

【讨论】:

以上是关于xmlHttp.getResponseHeader + 不适用于 CORS的主要内容,如果未能解决你的问题,请参考以下文章