IE8 XSS / Jquery问题

时间:2010-08-02 06:09:36

标签: jquery ajax internet-explorer-8 xss xmlhttprequest

在Firefox和Chrome中,一切都很完美,但IE8(8.0.6001.18702)除外

这是测试代码(Jquery 1.4.2)(与$ .post相同的问题):

$(function() {
   $.get("http://domain2.tld/some.php", {}, function(response) {
       alert(response);
   });
});

此代码在domain1.tld中执行,并从domain2.tld加载,这样:

<script type="text/javascript" src="http://domain2.tld/test.js"></script>

我在IE8中收到“权限被拒绝”的消息。到目前为止我没有尝试过:

1)添加domain1.tld(php代码):

header("X-XSS-Protection: 0");

2)在IE8选项中禁用XSS过滤器。

我正在使用IE8调试器,它在第5113行显示错误:

xhr.open(type, s.url, s.async);

如果不是调用$ .get(domain2.tld ...),而是调用$ .get(domain1.tld ...),没有错误,这向我确认这是一个XSS“同源策略”问题

我唯一的解决方案(我认为)是通过代理(php代码)来实现的,但我不愿意这样做,因为它会影响性能。

有人知道这个问题的替代/解决办法吗?

注意:更新IE8不是一个选项,因为我想在没有更新的情况下进行测试。

与我的一个非常相似的问题: http://forum.jquery.com/topic/jquery-ui-tabs-ie8-and-injecting-elements-into-dom

3 个答案:

答案 0 :(得分:8)

我很抱歉,如果我的英语不够完美,我可以看到我不够清楚......我的主要关注之一是由其他人解释的:http://forum.jquery.com/topic/cross-domain-ajax-and-ie

那么,还有什么替代方案?

1)XDomainRequest

我个人认为这是在IE8 +中实现跨站点脚本的最佳方式(因为它本身支持)。唯一的问题是,这是一种仅限Microsoft的方式。但是与IE系列一样多的其他东西我们可以轻松扩展JQuery ajax功能。

根据文档,您需要在domain1.tld中指定一些额外的标头,for example, in PHP,如下所示:

header("Access-Control-Allow-Origin: http://domain2.tld"); //use * for any

也许下一个替代方案对于提供XDomainRequest的jquery实现非常有用;

更新(a):有一个XDR library(非jquery)“替换”XHR类使其成为跨浏览器,它基于{{3} }。我还没有尝试过。

2)pmxdr client library

这个插件的唯一问题是它不完全是一个扩展,因为它的函数命名不同,所以你需要更改代码或包装该插件。

更新(b):我修改了CORS插件以简化操作。检查我的其他答案以获取代码。

3)CORS

这应该是解决我问题的最简单方法(因为我可以控制两台服务器)。本地大多数浏览器都支持跨站点脚本,只有在使用json格式时(我相信也可以使用xml)。在这种情况下,使用$ .getJSON()函数。为了使它工作,你需要指定(如文档所述)callback =?在URL中,例如:

$.getJSON("http://domain2.tld/index.php?callback=?",funciton(res){ ... }); 

“?”在“回调”将被替换为标识符...在您的php文件中,您需要获取该标识符并围绕Json代码,如下所示:

print_r($_GET["callback"])."(".json_encode($mydata).");";

(我从JsonP in JQuery获得了这个例子)

这种方法的问题在于,如果你只想检索HTML,它必须驻留在一个json对象中,从而使这个过程变得更加复杂和压倒性。

4)here

如果您需要对JQuery中的本机JSONP支持进行额外的验证和功能,那么请尝试使用此插件,这也将简化该过程。

5)jquery.jsonp plugin

这个插件使用Yahoo的服务YQL使用一个有趣的方法,其中任何网页(或其中的一部分)都可以转换为Json,从而可以将其导入到javascript中。此方法适用于无法更改原始格式的情况。

6)xdomainajax

此解决方案使用flash(swf)来实现魔力。我可以说这是实现几乎完全跨浏览器实现的一种非常快速的方式(因为它依赖于闪存支持)。这种方法对于那些存在闪光的场所(肯定)来说可能是理想的。但是,如果您的站点不需要闪存,那么这将成为主要的缺点,因为用户应该安装闪存才能使用。

7)flXHR

此解决方案基于YUI实现以及“Flash”方法。

8) 如果以前的选项都不适合您,请记住您仍然可以使用插入标记的旧技巧来导入JS代码。

9)将IE安全性降至最低也解决了问题。但我认为这样的消息不会很好:“请降低您的安全设置以便使用此网站”... lol

我希望这可以帮助处于类似情况的其他人。

答案 1 :(得分:5)

(我建议查看我在此回答之前发布的列表)

为了方便这个过程,我使用了CORS插件并对其进行了修改。如果只使用$ .get和$ .post,则无需修改现有的Jquery代码。我在IE8中测试它,它按预期工作。对于其他浏览器,将使用普通的JQuery调用。 您甚至可以按需添加此代码(使用条件标记)。 阅读初始评论以获取更多信息。我希望它有所帮助...

以下是代码(例如将其保存为 jquery.xdomain.js ):

/*
 * XDR (non-XHR) extension functions for IE8+
 * Based in CORS plugin (http://plugins.jquery.com/project/cors)
 * Modified by A.Lepe (www.alepe.com, Aug 2010)
 * 
 * It supports calls using $.get and $.post only.
 * The main difference between the CORS plugin and this one are:
 *
 * 1) This method tries first to use XDR and if not available 
 * will try to use XHR. This is to prevent any alert or 
 * security message from IE.
 *
 * 2) To minimize size and target only IE8+ versions, this method
 * does not provides an alternative fall-back.
 * CORS version uses proxy_xmlhttp.js as fall-back option (see link #1 below).
 *  
 * If you want to support "OLD" browsers, an alternative fall-back 
 * can be easily implemented (instead the error alert).
 * For example, something like:
 *
 * ...
 * } catch(e) {
 *    data["proxy_url"] = url;
 *    $._get(proxy, data, callback, type);
 * }
 * ...
 *
 * in which "proxy" must be a URL where your proxy is located. 
 * Your proxy may look like:
 *
 * <?php
     //GET method example:
     $URL = $_GET["proxy_url"];
     unset($_GET["proxy_url"]);
     $params = http_build_query($_GET);
     echo file_get_contents($URL."?".$params));
 * ?>
 *
 * For POST method you may check link #2.
 *
 * NOTES:
 *
 * $.post() method it might not work as expected. XDR does
 * not send the data to the server in the same way XHR do
 * (am I missing something?). In order to have access to that
 * POST data you will need to:
 *
 * a) set:
 *      always_populate_raw_post_data = On
 *      register_long_arrays = On
 *
 * OR :
 *
 * b) import it manually (see link #3): 
    //-------- Import XDR POST data ---------
    if (isset($GLOBALS["HTTP_RAW_POST_DATA"])) {
        $data = explode('&', $GLOBALS["HTTP_RAW_POST_DATA"]);
        foreach ($data as $val) {
            if (!empty($val)) {
                list($key, $value) = explode('=', $val);
                $_POST[$key] = urldecode($value);
            }
        }
    }
 *
 * Remember to add the respective headers in the server that will
 * allow the XDR calls:
      header('Access-Control-Allow-Origin: *'); //Or http://example.com
      header('Access-Control-Max-Age: 3628800');
      header('Access-Control-Allow-Methods: GET, POST');
 */
(function($) {
$._get = $.get;
$._post = $.post;
$.get = function (url, data, callback, type) {
    // try XDR
    if (jQuery.browser.msie && window.XDomainRequest) {
        var params = '';
        for (var key in data) {
            params += ((params || url.indexOf("?") != -1)?'&':'?')+key+'='+data[key];
        }
        // Use Microsoft XDR
        var xdr = new XDomainRequest();
        xdr.open("GET", url+params);
        xdr.onload = function() {
            callback(this.responseText, 'success');
        };
        xdr.send();
    } else {
        try {
            // Try using jQuery to get data
            $._get(url, data, callback, type);
        } catch(e) {
            alert(e.message);
        }
    }
}
$.post = function (url, data, callback, type) {
    // Try XDR
    if (jQuery.browser.msie && window.XDomainRequest) {
        var params = '';
        for (var key in data) {
            params += (params?'&':'')+key+'='+data[key];
        }
        // Use XDR
        var xdr = new XDomainRequest();
        xdr.open("POST", url);
        xdr.send(params);
        xdr.onload = function() {
            callback(xdr.responseText, 'success');
        };
    } else {
        try {
            // Try using jQuery to POST
            $._post(url, data, callback, type);
        } catch(e) {
            alert(e.message);
        }
    }
}
})(jQuery);

<强>链接:

答案 2 :(得分:-1)

我必须在这里同意jAndy,你根本不可能完成任务。 相同的原始策略适用(http://en.wikipedia.org/wiki/Same_origin_policy),您最好的办法是编写脚本轮询的本地代理,然后让代理执行跨域调用。