2008年的网络安全故事:默默地保护json.parse
#javascript #网络开发人员 #安全 #网络安全

我8岁的孩子正在为网络安全提供一份报告,所以我认为我会挖掘一份旧的报告,以解决我们默默地修复的,据我所知,该报告是一个局限性的安全性脆弱性从未透露过。

回到2008年, json.parse 不是JavaScript语言的一部分。这是一个单独的库,从json.org下载了used JavaScript koude0 to unpack data

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The "{" operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval("(" + text + ")");

json2.js的现代版本中的代码将json源文本包装在括号中,因为{}是javascript中的语句块,但是({})是对象构造函数。

但是使用eval的副作用是,如果源文本与doVeryBadThings()相似,那么javascript引擎会很乐意做那些非常糟糕的事情,即经典的arbitrary code execution vulnerability

在计算机安全性中,任意代码执行(ACE)是攻击者在目标计算机上或目标过程中运行攻击者选择的任何命令或代码的能力。

幸运的是,json2.js进行了一堆正则表达式检查,以确保text包含有效的JSON,允许构建值但不是更强大命令的命令。

不幸的是,JSON在语义意义上不是JavaScript的子集。有重要的区别。

要理解这些差异,让我从我根据这项研究主张的a change to the JavaScript language definition开始。

Screenshot of draft EcmaScript 3.1 specification quoted below

这是更改的规范文本。它反映了来自unicode.org的一些定义,这些定义通常用于控制字母如何在Perso-Arabic和其他草书写作系统中相互连接。

7.1 Unicode格式控制字符
Unicode格式控制字符(即,unicode字符数据库中的类别中的字符,例如左右标记或左右标记)是用于控制格式的控制代码在没有更高级别协议的情况下(例如加价语言)的文本范围。
在源文本中允许它们促进编辑和显示很有用。
格式控制字符可能在标识符,注释和字符串文字和正则表达式文字中使用。

在其中的右边是一些已删除的规范文本。

2008年7月2日已删除:Ecmascript程序的源文本中的任何地方。在应用词汇语法之前,将这些字符从源文本中删除。由于这些字符在处理字符串和正则表达文字之前已删除,因此必须使用Unicode逃生序列(请参见7.6)在字符串或正则表达式中包含Unicode格式对照字符。

因此,JavaScript允许标识符中的这些控制流字符“促进和显示”标识符,例如Ø警。

,但这发生在“应用词汇语法之前”。这是一种说法,我们在JavaScript解析器将源代码分解为令牌之前删除了这些字符,因此

  • 在它配对引号(")启动和端引号的字符串值和
  • 之前
  • 在它成对之前,评论/**/

JSON的规范没有等效子句。 json.org简单地说

使用Backslash Escapes,字符串是一个零或更多的Unicode字符,用双引号包裹。

我意识到,通过在后斜线和引用字符之间放置 [cf] 我可以得到JavaScript的eval,以找到与JSON Grammar在常规上所表达的不同的字符串端审查JSON文本的表达。这将使我能够将代码偷偷加入eval执行的JSON字符串中。

我向JSON维护者Douglas Crockford发送了一封电子邮件,并带有proof of concept

Email to Douglas Crockford dated Mar 14 2008 / On firefox 2, the below alerts "hello world" after "created string about to parse" using a version of http://www.JSON.org/json2.js downloaded earlier today. \<html\> \<head\> \<script src=json2.js\>\</script\> \</head\> \<body onload=\" var s = '\&quot;\\\\\\u200D\\\\\&quot;, alert\(\\'hello world\\'\) //\&quot;\n'; alert\(\'created string about to parse\'\); JSON.parse\(s\); \"\> \</body\> \</html\>

我第一次做得很好,但这是我的第二次尝试:

Email quoted below

概念证明是,|代表unicode的零宽木木材字符(u+200d):

"\|\", alert('hello world') //"

因此,有效的JSON解析器只会看到一个引用的字符串,其中包含两个逃脱的字符,其中一个是逃脱的报价。 json2.js用来近似的正则表达式具有相同的解释。

so json2.js的安全检查让该字符串贯穿到JavaScript的eval

但是,JavaScript的令牌机构看到了不同的东西,因为在令牌化之前将控制字符剥离

"\\", alert('hello world') //"

在那里,两个后斜线(以前具有 [cf] 字符)组合形成一个逃脱的后斜线。
现在逃脱的双引号现在结束字符串。正如电子邮件所解释的那样(添加了子弹为了清晰):

firefox看到...

  1. 一个字面的字符串,仅包含后斜线,然后是
  2. 逗号,然后是
  3. 致电alert,然后是
  4. 线条评论。

(该行评论都夹住了最终的双引号,因此eval不会随着语法错误而停止。)

道格拉斯意识到他需要更改json2.js使用的正则表达式。

Email quoted below

所以我认为我必须对ADSAFE所做的限制字符进行相同的搜索:

cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/,

打扰。

(确实打扰。)

,但后来他意识到我们不希望攻击者能够从目标变化中进行reverse engineer the vulnerability,因此他单方面更改了JSON的定义。

如果我将cx放在json.js中并宣布[sic]问题,它将向不法行为的人发出有关如何利用但是的信号。但是,如果相反,修复程序是我更换regexp

/\\./

仅与\匹配,然后是可打印的ascii角色,然后将拒绝文本。我的修复程序将不那么信息。

因此,这就是如何在2008年使用JSON影响几乎所有JavaScript代码的任意代码执行方式,与Afaik无声地关闭,没有一个人。