为什么Google会在(1)之前提前; 他们的JSON回复?

Jes*_*ess 3940 javascript security ajax json

为什么Google会while(1);在其(私人)JSON响应前加上?

例如,这是在Google日历中打开和关闭日历时的响应:

while(1);[['u',[['smsSentFlag','false'],['hideInvitations','false'],
  ['remindOnRespondedEventsOnly','true'],
  ['hideInvitations_remindOnRespondedEventsOnly','false_true'],
  ['Calendar ID stripped for privacy','false'],['smsVerifiedFlag','true']]]]
Run Code Online (Sandbox Code Playgroud)

我认为这是为了防止人们eval()对它进行操作,但你真正需要做的就是更换while然后你就可以了.我认为eval预防是为了确保人们编写安全的JSON解析代码.

我已经在其他几个地方看到了这种情况,但谷歌(邮件,日历,通讯录等)的情况更是如此.奇怪的是,谷歌文档开始了&&&START&&&,谷歌联系人似乎开始while(1); &&&START&&&.

这里发生了什么?

rjh*_*rjh 4186

它可以防止JSON劫持,这是一个主要的JSON安全问题,自2011年以来在EMCA5中已在所有主流浏览器中正式修复.

举例说明:Google有一个URL mail.google.com/json?action=inbox,以JSON格式返回收件箱的前50条消息.由于同源策略,其他域上的邪恶网站无法通过AJAX请求获取此数据,但它们可以通过<script>标记包含URL .使用您的 cookie 访问URL ,通过覆盖全局数组构造函数或访问器方法,只要设置了对象(数组或散列)属性,就可以调用该方法,从而允许它们读取JSON内容.

while(1);&&&BLAH&&&防止这样的:在一个AJAX请求mail.google.com将具有完全访问的文本内容,并且可以去除它扔掉.但是<script>标签插入盲目地执行JavaScript而不进行任何处理,从而导致无限循环或语法错误.

这并未解决跨站点请求伪造的问题.

  • `for(;;);`做同样的工作吗?我在facebook的ajax响应中看到过这个. (230认同)
  • 为什么获取此数据的请求不需要CSRF令牌? (222认同)
  • @JakubP.在Google规模上存储和维护CSRF令牌需要大量的基础架构和成本. (176认同)
  • @JakubP.反CSRF令牌与缓存混乱,并需要一些服务器端的加密评估.在谷歌规模,这将需要大量的CPU.这种方式将其卸载给客户端. (124认同)
  • 在我看来,更好的方法是让服务器只在设置了正确的标头时才发送JSON.您可以在AJAX调用中执行此操作,但不能使用脚本标记执行此操作.这样,敏感信息甚至不会被发送,您不必依赖浏览器端安全性. (94认同)
  • @Valipour会看到你警报的人不是黑客. (62认同)
  • 为什么无限循环而不是简单的语法错误(保存字符)?你可以用`)`来启动文件. (22认同)
  • @ dave1010错误仍然不够好.您仍然可以阅读脚本标记的内容.而(1)将挂断翻译. (16认同)
  • @JakubP为什么在有一个不需要基础设施,复杂性或实现的简单解决方案时使用CSRF令牌? (14认同)
  • @silkfire跨域XHR不起作用的事实.script标签纯粹用于发送请求.所以会发生什么,响应被加载然后运行,但是你无法控制它们之间的任何东西. (13认同)
  • 这是为了防止XSSI不是CSRF. (12认同)
  • @silkfire如果您有Gmail的登录cookie,您将看到完整的json****您的**详细信息(联系人列表等).但这里的诀窍是,您在受害者的客户端上运行该页面.因此,脚本标记发送请求以获取其`src`属性中的任何内容,以及**受害者**的cookie.因此,响应将包含受害者的数据,但您的脚本处于控制状态,因此您可以随意执行任何操作. (12认同)
  • 这个解决方案似乎有点过于复杂......你不能通过永远不会在HTTP GET请求上返回JSON来阻止攻击吗? (11认同)
  • 我不喜欢花样.这不是通过总是返回一个对象来解决的吗? (10认同)
  • @mcv如果内容已在某个地方缓存,那将无效. (10认同)
  • @DaveVandenEynde no,请参阅覆盖全局Array构造函数的链接; 可以对全局Object构造函数执行相同的操作 (9认同)
  • 我认为最好不要发送敏感数据,而不是在信任浏览器无法处理数据的同时发送数据.虽然在这种情况下,浏览器中的某些信任是不可避免的.在完全受损的浏览器中,显然没有什么是安全的. (9认同)
  • 那么你是说当Google从他们的合法AJAX请求获得返回的数据响应时,他们发现/替换或使用正则表达式来删除`while(1);`? (8认同)
  • 这今天(2015年)仍然有用吗?我在这篇关于Firefox 3和Chrome 2的讨论中可以找到的所有博客文章,以及JS规范漏洞将/可能会改变.这种安全性今天仍然存在于2015浏览器中吗? (8认同)
  • Salesforce.com还使用`while(1);`来预先设置AJAX响应 (7认同)
  • 从安全角度来看,开放式块评论是否也能正常工作?(即"/*") (6认同)
  • @mattb我不相信.您无法通过脚本标记加载对象文字.这就是WCF和OData将数组包装在具有'd'属性的对象中的原因. (6认同)
  • @ 0xSina你无法读取脚本标签的内容 (6认同)
  • @RavinderPayal他们不能.XSS保护不允许JS从不同的域读取IFRAME的内容. (6认同)
  • 不会返回包含数组的对象,而不是直接返回数组,也解决了问题? (5认同)
  • @silkfire通过将数组构造函数替换为将数据发送到恶意服务器的数组构造函数来获取数据.因为while(1)阻止eval到达数组,所以hack不起作用,因为数组构造函数永远不会触发.从下面的答案http://ejohn.org/blog/re-securing-json/ (5认同)
  • @DuckMaestro如果你尝试`function Array(){console.log('security breach!'); 在Chrome上你会得到答案 (5认同)
  • @mcv你仍然依赖浏览器安全,实际上没有办法解决这个问题 - 最终,用户正在使用浏览器来访问他们的数据:)例如,你的浏览器可能允许任意的AJAX请求,在这种情况下你首先,甚至不需要这个技巧.只要您继续使用cookie进行身份验证,您绝对必须依赖浏览器以安全的方式处理cookie - 这包括域隔离和相同的源策略.阻止该跨站点AJAX请求的不是*服务器* - 如果没有浏览器它甚至会知道它的跨站点? (5认同)
  • @King Julien-是的,他们的优势是每个请求节省1个字节! (5认同)
  • @PedroFelix不,这不会解决问题,因为帖子中提到的相同攻击仍然可以执行.覆盖访问器方法以检索信息. (4认同)
  • 如果生成JSON的脚本需要POST而不是GET请求 - 这是否完全降低了这种风险? (4认同)
  • @Boushley:不,因为这将是一个语法错误(`{`在语句级别开始一个块). (4认同)
  • @rjh:因为顶级对象文字是语法错误; 不会返回对象而不是数组也解决问题吗? (4认同)
  • @Matthew我们谈论跨域数据披露; 显然,如果脚本是本地的,这使得这里讨论的所有内容都无关紧要. (4认同)
  • @ arnaud576875 - 我得到你的意思,但你可以阅读脚本标签的内容(这是大多数客户端模板的完成方式,[例如](http://stackoverflow.com/questions/4912586/explanation-of -script型文本模板脚本)).只是你只能读取脚本标签的_local_内容 - 而不是远程内容([小提琴](http://jsfiddle.net/mlhDevelopment/3Dpfv/)). (3认同)
  • 怎么样`while(1)警报('走开黑客!');`? (3认同)
  • 这仍然相关吗?由于此问题依赖于这种[漏洞](http://ejohn.org/blog/re-securing-json/),这已被固定在很久以前,好像答案我评论. (3认同)
  • @sscarduzio没有它运行一段时间并抛出无响应的脚本警报.它取决于用户阻止它. (3认同)
  • 什么会阻止我刮掉JSON响应,然后用脚本语言删除`while();`语句,然后`eval()`它?我通常不必登录到站点来访问这种敏感的JSON吗?就是想. (2认同)
  • @MDeSchaepmeester我的意思是,我可以在浏览器中输入URL,然后查看结果,即JSON是否完全可读? (2认同)
  • @mcv.标题看起来确实是一个很好的标准解决方案.但为什么"更好"呢?也许在Google的规模上,即使处理标题也是可以避免的. (2认同)
  • @KarlKnechtel - 不幸的是,这会破坏网络。:( 它不会作为选择加入,但作为选择加入是没有用的。 (2认同)

Arn*_*anc 544

它可以防止通过JSON劫持泄露响应.

理论上,HTTP响应的内容受同源策略的保护:来自一个域的页面无法从另一个域的页面获取任何信息(除非明确允许).

攻击者可以代表您在其他域上请求页面,例如使用<script src=...><img>标记,但无法获取有关结果的任何信息(标题,内容).

因此,如果您访问攻击者的页面,则无法从gmail.com读取您的电子邮件.

除了使用脚本标记来请求JSON内容之外,JSON在攻击者的受控环境中作为Javascript执行.如果攻击者可以替换Array或Object构造函数或在对象构造期间使用的其他方法,则JSON中的任何内容都将通过攻击者的代码并被披露.

请注意,这在JSON作为Javascript执行时发生,而不是在解析时.

有多种对策:

确保JSON永远不会执行

通过while(1);在JSON数据之前放置一条语句,Google确保JSON数据永远不会作为Javascript执行.

只有合法的页面才能真正获取整个内容,剥离while(1);并将剩余部分解析为JSON.

for(;;);例如,在Facebook上已经看到了类似的结果.

确保JSON无效Javascript

同样,在JSON之前添加无效标记,例如&&&START&&&,确保它永远不会被执行.

始终在外部返回带有Object的JSON

这是防止JSON劫持的OWASP推荐方法,并且是较少侵入性的方法.

与之前的反措施类似,它确保JSON永远不会作为Javascript执行.

有效的JSON对象(未被任何内容包含)在Javascript中无效:

eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :
Run Code Online (Sandbox Code Playgroud)

但这是有效的JSON:

JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}
Run Code Online (Sandbox Code Playgroud)

因此,确保始终在响应的顶层返回一个Object,确保JSON不是有效的Javascript,同时仍然是有效的JSON.

正如@hvd在评论中所指出的,空对象{}是有效的Javascript,并且知道对象是空的可能本身就是有价值的信息.

比较上述方法

OWASP方式不那么具有侵入性,因为它不需要更改客户端库,并传输有效的JSON.但是,不确定过去或未来的浏览器错误是否会破坏这一点.正如@oriadam指出,目前还不清楚是否数据可以解析错误通过错误处理或不泄露(如window.onerror).

谷歌的方式需要客户端库,以便它支持自动反序列化,并且可以被认为是更安全的浏览器错误.

这两种方法都需要服务器端更改,以避免开发人员意外发送易受攻击的JSON.

  • 值得注意的是_why_返回一个对象文字无法使用`script`标签或`eval`函数.大括号`{}`可以解释为代码块或对象文字,并且JavaScript本身更喜欢前者.作为代码块,它当然是无效的.通过这种逻辑,我看不出未来浏览器行为的任何可预见的变化. (27认同)
  • OWASP推荐很有意思,因为它简单.有人知道谷歌的方式更安全的原因吗? (22认同)
  • 我相信它*在任何方面都不会更安全.提供OWASP似乎是+1的充分理由. (15认同)
  • 糟糕的代码是不够的因为攻击者也可以劫持浏览器的脚本错误处理器(`window.onerror`)我不确定`onerror`的语法错误是什么行为.我猜谷歌也不确定. (13认同)
  • "一个有效的JSON对象,当没有被任何东西包围时,在Javascript中无效:" - 除了空对象(`{}`)的简单情况之外,它也是一个有效的空块.如果知道对象是空的可能本身就是有价值的信息,那么这可能是可利用的. (9认同)
  • 2014年的哪些浏览器允许您替换Array或Object构造函数? (6认同)
  • JSONP要求服务器参与,并且由于JSONP的目的是允许跨域访问有问题的数据,我认为服务器不会关注阻止对该数据的跨域访问. (2认同)
  • 我很惊讶他们没有使用删除第一个字符的方法:`"a":1,"b":2}`或`1,2,3]`是无效的JS而且永远不会是,它是很容易根据最后一个添加正确的字符.谷歌和Facebook将节省数百万TB的带宽. (2认同)
  • 如果它是需要授权的API,则另一个对策(您应该使用它)是CSRF令牌.如果没有有效的CSRF令牌,服务器可以直接拒绝攻击者的请求. (2认同)
  • Medium API始终返回非空对象,但仍带有前缀.例如:`])} while(1); </ x> {'success':true,'payload':{}}`任何人都知道原因吗? (2认同)

bdo*_*lan 360

这是为了确保其他网站无法做出令人讨厌的技巧来试图窃取您的数据.例如,通过替换数组构造函数,然后通过<script>标记包含此JSON URL ,恶意第三方网站可能会从JSON响应中窃取数据.通过while(1);在开始时放置,脚本将挂起.

另一方面,使用XHR和单独的JSON解析器的同站点请求可以轻松忽略while(1);前缀.

  • 攻击者只会使用普通的`<script>'元素,而不是XHR. (12认同)
  • @Matthew,当然,你可以在将数据传递给JSON解析器之前删除它.你不能用`<script>'标签做到这一点 (9认同)
  • 这有什么例子吗?再次引用替换数组构造函数,但这是一个长期修复的错误.我不明白如何访问通过脚本标记接收的数据.我很想看到一个在最近的浏览器中工作的虚拟实现. (7认同)
  • @joeltine,不,不是.请参见http://stackoverflow.com/questions/16289894/is-json-hijacking-still-an-issue-in-modern-browsers/16880162#16880162. (7认同)
  • 从技术上讲,如果您有前缀,"正常"JSON解析器应该给出错误. (6认同)
  • 如果是为了防止JSON劫持,那么`/*[....]*/`也能工作吗? (3认同)
  • 在John Resig的博客中,他提到了非常古老的浏览器.有谁知道这个漏洞是否仍然是当今现代浏览器中的一个问题? (2认同)

Dan*_*llo 106

这将使第三方难以将JSON响应插入带有<script>标记的HTML文档中.请记住,<script>标签不受同源策略的约束.

  • 这只是答案的一半.如果它不是为了覆盖`Object`和`Array`构造函数的技巧,那么执行有效的JSON响应就像它是JavaScript一样,在所有情况下都是完全无害的.是的,`while(1);`阻止响应作为JavaScript执行,如果以`<script>'标记为目标,但你的答案并没有解释为什么这是必要的. (21认同)

Poi*_*nty 78

它可以防止它被用作简单<script>标记的目标.(好吧,它并没有阻止它,但它让它变得令人不快.)那样坏人不能只将那个脚本标记放在他们自己的网站中,而是依靠一个活动的会话来获取你的内容.

编辑 - 记下评论(和其他答案).这个问题与颠覆的内置设施有关,特别是ObjectArray构造函数有关.这些可以被修改,以便在解析时无关紧要的JSON可以触发攻击者代码.

  • 这只是答案的一半.如果它不是为了覆盖`Object`和`Array`构造函数的技巧,那么执行有效的JSON响应就像它是JavaScript一样,在所有情况下都是完全无害的.是的,`while(1);`阻止响应作为JavaScript执行,如果以`<script>'标记为目标,但你的答案并没有解释为什么这是必要的. (16认同)

小智 12

由于这是一篇高流量帖子,我希望在这里提供一个对原始问题稍微不确定的答案,从而提供有关 JSON 劫持攻击及其后果的进一步背景信息

顾名思义,JSON 劫持是一种类似于跨站请求伪造的攻击,攻击者可以从将敏感数据作为数组文字返回到 GET 请求的应用程序访问跨域敏感 JSON 数据。返回数组文字的 JSON 调用示例如下所示:

[{"id":"1001","ccnum":"4111111111111111","balance":"2345.15"}, 
{"id":"1002","ccnum":"5555555555554444","balance":"10345.00"}, 
{"id":"1003","ccnum":"5105105105105100","balance":"6250.50"}]
Run Code Online (Sandbox Code Playgroud)

这种攻击可以通过 3 个主要步骤来实现:

第 1 步:让经过身份验证的用户访问恶意页面。步骤 2:恶意页面将尝试从用户登录的应用程序访问敏感数据。这可以通过在 HTML 页面中嵌入脚本标签来完成,因为同源策略不适用于脚本标签。

<script src="http://<jsonsite>/json_server.php"></script>
Run Code Online (Sandbox Code Playgroud)

浏览器将发出 GET 请求,json_server.php并且用户的任何身份验证 cookie 将随该请求一起发送。步骤 3:此时,虽然恶意站点已执行脚本,但它无法访问任何敏感数据。可以通过使用对象原型设置器来访问数据。在下面的代码中,当尝试设置“ ccnum”属性时,对象原型属性将绑定到定义的函数。

Object.prototype.__defineSetter__('ccnum',function(obj){
    secrets =secrets.concat(" ", obj);
});
Run Code Online (Sandbox Code Playgroud)

至此,恶意站点已成功劫持(ccnum)返回byjson_server.php JSON的敏感财务数据

需要注意的是,并非所有浏览器都支持该方法;概念验证是在 Firefox 3.x 上完成的。此方法现已被弃用并被替换。useObject.defineProperty此攻击还有一种变体,应该适用于返回全名 JavaScript(例如pi=3.14159)而不是 JSON 的所有浏览器大批。

有多种方法可以防止 JSON 劫持:

  • 由于 SCRIPT 标签只能生成 HTTP GET 请求,因此它们只向 POST 请求返回 JSON 对象。

  • 防止 Web 浏览器将 JSON 对象解释为有效的 JavaScript 代码。

  • 通过要求所有 JSON 请求都需要预定义的随机值来实现跨站点请求伪造保护。

正如您所看到的,While(1)属于最后一个选项。用最简单的术语来说,while(1) 是一个无限循环,将一直运行到显式发出break语句为止。因此,什么将被描述为要应用的密钥的锁(谷歌中断语句)。因此,黑客没有密钥的 JSON 劫持将始终被驳回。唉,如果您使用解析器读取 JSON 块,则 while(1) 循环将被忽略。

所以总而言之,while(1)循环可以更容易地被可视化为一个简单的break语句密码,谷歌可以用它来控制数据流。

然而,该声明中的关键词是“简单”一词。值得庆幸的是,自 2010 年以来,经过身份验证的无限循环的使用已从基本实践中删除,因为它在隔离时绝对会大幅降低 CPU 使用率(而且互联网已经不再强制执行粗略的“快速修复”)。如今,代码库已经嵌入了预防措施,该系统不再重要或有效。(其中一部分是从 JSON 劫持转向更富有成效的数据农业技术,我目前不会讨论)


Kri*_*wal 10

由于<script>标签免于同源策略(这是Web环境中的安全必需),因此while(1)添加到JSON响应时可防止在<script>标记中滥用它.