知道为什么JSON遗漏了NaN和+/- Infinity?它将Javascript放在奇怪的情况下,否则,如果它们包含NaN或+/-无穷大值,那么否则可以序列化的对象不会.
看起来像是一成不变的:见RFC4627和ECMA-262(第24.3.2节,JSON.stringify,第4节,第507页,最后编辑):
有限数字通过调用进行字符串化ToString(number)
.无论符号如何,NaN和Infinity都表示为String null
.
olliej..
87
Infinity
并且NaN
不是关键字或任何特殊的,它们只是全局对象上的属性(按原样undefined
),因此可以更改.这是因为这个原因JSON不包括他们在规范-在本质上,如果你做任何真正的JSON字符串应该具有的EcmaScript相同的结果eval(jsonString)
或JSON.parse(jsonString)
.
如果它被允许那么有人可以注入类似的代码
NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
进入一个论坛(或其他),然后该网站上的任何json使用可能会受到损害.
1> olliej..:
Infinity
并且NaN
不是关键字或任何特殊的,它们只是全局对象上的属性(按原样undefined
),因此可以更改.这是因为这个原因JSON不包括他们在规范-在本质上,如果你做任何真正的JSON字符串应该具有的EcmaScript相同的结果eval(jsonString)
或JSON.parse(jsonString)
.
如果它被允许那么有人可以注入类似的代码
NaN={valueOf:function(){ do evil }};
Infinity={valueOf:function(){ do evil }};
进入一个论坛(或其他),然后该网站上的任何json使用可能会受到损害.
@olliej:你认为NaN不是文字,我不知道Javascript足以判断javascript的语义.但对于存储双精度浮点数的文件格式,应该有一种方法来定义IEEE浮点数,即通过文字NaN/Infinity/NegInfinity.这些是64位双精度的状态,因此应该是可表示的.有些人依赖他们(原因).它们可能被遗忘了,因为JSON/Javascript起源于Web开发而不是科学计算.
对于JSON来说,任意省略NaN,Infinity和-Infinity的完全有效和标准浮点数状态是100%,绝对错误.从本质上讲,JSON决定支持IEEE浮点值的任意子集,无意中省略了三个特定值,因为它们很难或者什么的.不,Eval-ability甚至不是一个借口,因为这些数字可能被编码为文字1/0,1/0和0/0.它们是附加"/ 0"的有效数字,它不仅易于检测,而且实际上可以同时作为ES进行评估.别找借口.
如果你评估1/0你获得无穷大,如果你评估-1/0你得到-Infinity,如果你评估0/0你得到NaN.
关于安全性/安全性,所有一个体面的JSON解析器在转换NaN时必须要做的是产生值0/0(而不是评估符号NaN),这将返回"真正的"NaN而不管是什么符号NaN重新定义为.
但是术语"NaN"和"Infinity"是属性名称,所以String(1/0)产生一个字符串"Infinity",它只是值无穷大的字符串表示.由于文字值是ES,因此无法表示"NaN"或"Infinity" - 您必须使用表达式(例如,1/0,0/0等)或属性查找(指"无穷大")或"NaN").由于那些需要代码执行,它们不能包含在JSON中.
我喜欢你选择拒绝_Why_ NaN和Infinity不被允许的唯一答案 - JSON专门设计为ES语言的一个子集,它只允许文字,并且根据定义,任何属性访问都不是文字.
这里给出的安全论点是荒谬的.如果某人有权按照答案中的描述注入javascript,那么访问该网站的人会担心更大的安全问题.
此外,如果不支持最基本的除法数学运算的三个明确定义的结果,JSON不能声称支持IEEE754浮点数,更糟糕的是,它甚至没有理由这么说.与标准脱离也没有任何好处,因为即使这样做可能允许任意大数......它不仅在实践中无用(祝你把非标准数字推入任何实际变量并用它做任何事情......也可以在这一点上使用带有自定义解析器的字符串),但它将永远保持不足.
你在讨论错误的事情.JSON不应该是'eval`'d.JavaScript包含内部`NaN`和`Infinity` /`-Infinity`对象.这个答案没有说明为什么Crockford不会简单地指定JSON可以使用这些表达式对这些内部对象进行编码.
@wirrbel,我完全同意这些值应该可以在JSON中表示.至于代码执行问题:如果解析JSON的代码之前已经与NaN混淆,那么程序员决定改变它.这不是"远程执行漏洞".至少不超过:`String.prototype.indexOf = function(){throw new Error('Crash!')};`在某个时刻跟着`obj = JSON.parse(remoteString); alert((obj.丙|| "")的indexOf( 'OK'));`.再一次,它是程序员决定搞乱`String`类,而JSON只是_refers_它,但没有决定它做什么.
好吧,如果有人可以注入任何代码,javascript使用会受到影响......
尝试运行jsdb或Firebug控制台:NaN = {toString:function(){return"fiddledeedee"}}然后运行0/0你得到内部NaN对象; 无法重新定义它.
NaN和Infinity不是属性名称(也许它们在IE的JScript中).
需要与"eval"相同的结果似乎是对JSON放置自身的愚蠢限制.即使在JSON上,也不应该使用`eval`.结果是,在某些情况下,如果不跳过篮球,你就无法做你真正需要的事情.关于JSON的最好的部分之一是它在很大程度上避免了跳过箍来传递你的数据.JSON是一种数据交换格式(也是一种非常好的格式!),它广泛用于*许多*编程语言中.除了JavaScript之外,语言的`eval`功能怎么样?它应该试图支持那些吗?
JSON不是ES的子集,eval和JSON.parse在某些情况下已经给出了不同的结果.值得注意的是,JSON允许字符串中的原始`\ u2028`和`\ u2029`字符,但Ecmascript不允许.
2> 小智..:
在最初的问题上:我同意用户"cbare",因为这是JSON中遗憾的遗漏.IEEE754将这些定义为浮点数的三个特殊值.所以JSON不能完全代表IEEE754浮点数.事实上更糟糕的是,因为ECMA262 5.1中定义的JSON甚至没有定义它的数字是否基于IEEE754.由于为ECMA262中的stringify()函数描述的设计流程确实提到了三个特殊的IEEE值,因此可以怀疑其意图实际上是支持IEEE754浮点数.
作为另一个与问题无关的数据点:XML数据类型xs:float和xs:double表示它们基于IEEE754浮点数,并且它们支持这三个特殊值的表示(参见W3C XSD 1.0第2部分) ,数据类型).
我同意这一切都很不幸.但也许JSON数字没有指定确切的浮点格式是一件好事.甚至IEEE754也规定了许多格式 - 不同的大小,以及十进制和二进制指数之间的区别.JSON特别适合十进制,所以如果某些标准将它固定为二进制,那将是一个遗憾.
@AdrianRatnapala +1确实:JSON数字具有潜在的无限精度,因此它们比IEEE规范要好得多,因为它们没有大小限制,没有精度限制,也没有舍入效果(如果序列化器可以处理它).
@ArnaudBouchez。也就是说,JSON应该仍然支持代表NaN和+ -Infinity的字符串。即使不应该将JSON固定为任何IEEE格式,定义数字格式的人们也应该至少查看Wikipedia页面IEEE754并停下来思考一下。
3> Zoidberg..:
你可以调整空对象模式,并在你的JSON中表示这样的值
"myNum" : {
"isNaN" :false,
"isInfinity" :true
}
然后在检查时,您可以检查类型
if (typeof(myObj.myNum) == 'number') {/* do this */}
else if (myObj.myNum.isNaN) {/* do that*/}
else if (myObj.myNum.isInfinity) {/* Do another thing */}
我知道在Java中你可以覆盖序列化方法以实现这样的事情.不确定序列化的位置,所以我不能详细介绍如何在序列化方法中实现它.
@Zoidberg:`undefined`不是关键字,它是全局对象的属性
@Zoidberg:未定义是全局对象上的属性 - 它不是一个关键字,所以`"未定义"在this`在全球范围内返回true.这也意味着你可以做`undefined = 42`和`if(myVar == undefined)`变成(基本上)`myVar == 42`.这可以追溯到ECMAScript的东东JavaScript的初期其中`undefined`不存在默认情况下,于是人们就在全球范围内做了`变种undefined`.因此,在不破坏现有网站的情况下,"undefined"无法成为关键字,因此我们注定有时候将undefined作为普通属性.
@olliej:我不知道为什么你认为undefined是全局对象的属性.默认情况下,undefined的查找是undefined的内置值.如果使用"undefined = 42"覆盖它,那么当您将undefined作为变量查找进行访问时,您将获得被覆盖的值.但是尝试做"zz = undefined; undefined = 42; x = {};'undefined old ='+(xa === zz)+',undefined new ='+(xa === undefined)".您永远不能重新定义null,undefined,NaN或Infinity的内部值,即使您可以覆盖它们的符号查找.
@Jason`undefined`是一个全局属性,因为它是这样指定的.请参阅ECMAScript-262 3rd ed的15.1.1.3.
4> teh_senaus..:
字符串"Infinity"," - Infinity"和"NaN"都强制转换为JS中的预期值.所以我认为在JSON中表示这些值的正确方法是字符串.
> +"Infinity"
Infinity
> +"-Infinity"
-Infinity
> +"NaN"
NaN
遗憾的是,JSON.stringify不会这样做.但有一种方法:
> JSON.stringify({ x: Infinity }, function (k,v) { return v === Infinity ? "Infinity" : v; })
"{"x":"Infinity"}"
JSON值不能是算术表达式...使标准与语言文字语法分离的目的是使JSON不可序列化而不执行任何代码.不知道为什么我们不能将`NaN`和`Infinity'添加为关键字值,如`true`和`false`.
5> 小智..:
如果您有权访问序列化代码,则可能将Infinity表示为1.0e + 1024.指数太大而不能表示为double,而当反序列化时,它表示为Infinity.适用于webkit,不确定其他json解析器!
IEEE754支持128位浮点数,因此1.0e5000更好
无穷+ 1:P
吨:后来添加了128位.如果他们决定添加256位怎么办?然后,您将不得不添加更多的零,现有代码的行为将有所不同."无限"将永远是"无限",所以为什么不支持呢?
1,-1和0 .....完全有效/可解析的数字,只需在它们的末尾添加`/ 0`即可成为这三个特殊值。它易于解析,立即可见甚至可评估。他们还没有将其添加到标准中是不可原谅的:`{“不是数字”:0/0,“无穷大”:1/0,“负无穷大”:-1/0}`<<为什么没有?`alert(eval(“ \”非数字\“”))//有效``alert(eval(“ 1/0”))//也有效,打印'Infinity'`。