使用未加引号的键安全解析JSON字符串

问题描述:

json2.js严格要求所有对象键都用双引号。但是,在Javascript语法中,{"foo":"bar"}相当于{foo:"bar"}使用未加引号的键安全解析JSON字符串

我有接受来自用户的JSON输入,并希望“缓和”的限制双引号键一个文本。我已经看过json2.js如何在四个阶段验证一个JSON字符串,然后它才会对它进行处理。我能够添加第5个阶段来允许不带引号的键,并想知道这个逻辑是否存在任何安全隐患。

var data = '{name:"hello", age:"23"}'; 

// Make sure the incoming data is actual JSON 
// Logic borrowed from http://json.org/json2.js 
if (/^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") 
    .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") 
    .replace(/(?:^|:|,)(?:\s*\[)+/g, ":") // EDITED: allow key:[array] by replacing with safe char ":" 
    /** everything up to this point is json2.js **/ 

    /** this is the 5th stage where it accepts unquoted keys **/   
    .replace(/\w+\s*\:/g, ":"))) { // EDITED: allow any alphanumeric key 

    console.log((new Function("return " + data))()); 
} 
else { 
    throw("Invalid JSON: " + data); 
} 
+4

您认为JavaScript Object Literal等价于JSON,事实并非如此。 – Stephen 2010-11-17 23:28:13

+6

'{name:“Joe”}'是有效的Javascript,但它是_invalid_ JSON。你也不想破解'json2.js',因为它只反映浏览器本机JSON支持的工作原理。例如,在Chrome中,没有'json2.js'的'JSON.parse()'也会窒息。但更糟糕的是,如果浏览器具有本地JSON支持,那么'json2.js'不会加载任何内容。因此,您将处于一种情况,即使用本机JSON支持的浏览器从不会看到这种黑客行为,因为它使用本机代码来解析它。 – 2010-11-17 23:29:01

+0

@Stephen你是对的。也许我应该改为“安全解析JavaScript对象文字和转换为JSON”的问题? – daepark 2010-11-17 23:33:50

JSON不允许未加引号的键。 JSON是JavaScript表示法的一个子集,并且不包含未加引号的键。将未加引号的键传递给几乎任何JSON解析器都可能会抛出错误或返回“意外”结果。

希望这有助于

+3

当然,关于JSON是真的,但JavaScript确实允许在对象字面量中使用未加引号的键。这只是有点问题,因为你不能使用不带引号的破折号或保留字。然而,我认为提问者已经知道这一点。 – JAL 2010-11-18 00:27:45

data.replace(/(['"])?([a-zA-Z0-9]+)(['"])?:/g, '"$2":'); 

,它将取代在参数名称的单引号,并添加任何缺失。

+5

这似乎工作。除非你没有处理下划线。这是一个更新正则表达式:''hash.replace(/(['“])?([a-zA-Z0-9 _] +)([''])?:/ g,'”$ 2“:'); – 2011-03-14 18:57:04

+0

touche,谢谢你是一个疏忽 – 2011-03-16 19:22:02

+4

这个答案是非常完美的。尝试'{a:['b','c']}'或'{a:“注意:发生了什么。”} – powerboy 2012-08-25 22:25:06

我认为让实际的测试用例清除这个实现中的任何问题会很有帮助。我已经通过一些测试添加了一个名为JSOL的github项目。请随意填写以添加并找到问题。谢谢。

https://github.com/daepark/JSOL