安全地将 JSON 字符串转换为对象
Posted
技术标签:
【中文标题】安全地将 JSON 字符串转换为对象【英文标题】:Safely turning a JSON string into an object 【发布时间】:2010-09-07 21:13:04 【问题描述】:给定一串 JSON 数据,我如何安全地将那个字符串转换为 javascript 对象?
显然,我可以通过以下方式不安全地执行此操作:
var obj = eval("(" + json + ')');
但这让我很容易受到包含其他代码的 JSON 字符串的攻击,简单地 eval 似乎非常危险。
【问题讨论】:
在大多数语言中,eval 带有额外的风险。 Eval 为黑客的利用敞开了大门。但是,请记住所有 javascript 都在客户端上运行。 预计它将被黑客更改。他们可以 EVAL 任何他们想要的东西,只需使用控制台。您必须在服务器端建立保护。 好的,现在是 2014 年,您永远不应该使用eval
来解析 JSON 字符串,因为您会将代码暴露给“代码注入”。请改用JSON.parse(yourString)
。
JSON 数据是文字吗?
@shanechiu:如果您的意思是标量数据类型,是的。只是一个带有键值语法的字符串。
查看parse()
方法的文档:w3schools.com/js/js_json_parse.asp
【参考方案1】:
JSON.parse(jsonString)
是一种纯 JavaScript 方法,只要您能保证一个相当现代的浏览器。
【讨论】:
我很确定它对 Node.js 是安全的 @vsync 您确实意识到这是 ONLY 纯 Javascript 答案...如果您阅读 javascript 标记的描述,您会看到这个...“除非还包含框架/库的标签,否则需要纯 JavaScript 答案。".. 我给它一个 +1 因为它是唯一的 javascript 答案... Pretty safe to use. 如果您正在使用 NodeJS,我无法加载 jQuery 来将 jsonString 解析为 JSON 对象。所以赞成乔纳森的回答 根据this link,IE8+支持,虽然上面写着:Requires document to be in IE8+ standards mode to work in IE8.
【参考方案2】:
现在不推荐使用 jQuery 方法。请改用此方法:
let jsonObject = JSON.parse(jsonString);
使用已弃用的 jQuery 功能的原始答案:
如果您使用的是 jQuery,请使用:
jQuery.parseJSON( jsonString );
这正是您正在寻找的(参见 jQuery documentation)。
【讨论】:
有理由在 JSON.parse() 上使用它吗?jQuery.parseJSON
默认使用JSON.parse
(如果存在),因此使用它而不是真实的唯一原因是如果您需要 此答案适用于 IE
此答案已过时,Jonathan's answer above (JSON.parse(jsonString)
) 现在是最佳答案。
JSON.org 具有多种语言的 JSON 解析器,包括四种不同的 JavaScript 解析器。我相信大多数人会考虑将json2.js 作为他们的 goto 实现。
【讨论】:
我希望人们停止对这个答案投反对票。它在 2008 年发布时是准确的。只需支持新的。 如果答案现在已经过时,请考虑更新它。 对于 IE 【参考方案4】:使用“JSON.parse()”中的简单代码示例:
var jsontext = '"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]';
var contact = JSON.parse(jsontext);
并反转它:
var str = JSON.stringify(arr);
【讨论】:
【参考方案5】:这似乎是问题:
通过 Ajax websocket 等接收的输入,它将是字符串格式,但您需要知道它是否为JSON.parsable
。问题是,如果你总是通过JSON.parse
运行它,程序可能会继续“成功”,但你仍然会在控制台中看到一个错误,并带有可怕的"Error: unexpected token 'x'"
。
var data;
try
data = JSON.parse(jqxhr.responseText);
catch (_error)
data || (data =
message: 'Server error, please retry'
);
【讨论】:
没有。问题是你期待一个 JSON 对象,最终可能会得到(function() postCookiesToHostileServer(); ());
甚至在 Node 上下文中更糟糕的东西。
那么 JSON.parse 会清除函数的输入(在这种情况下,作为 IIF --> 对象将无济于事)。似乎解决这个问题的最好方法是尝试/捕捉。 (见编辑)【参考方案6】:
我不确定其他方法,但您可以在 Prototype (JSON tutorial) 中这样做。
new Ajax.Request('/some_url',
method:'get',
requestHeaders: Accept: 'application/json',
onSuccess: function(transport)
var json = transport.responseText.evalJSON(true);
);
使用 true 作为参数调用 evalJSON()
会清理传入的字符串。
【讨论】:
【参考方案7】:如果你使用jQuery,你也可以使用:
$.getJSON(url, function(data) );
然后你可以做类似的事情
data.key1.something
data.key1.something_else
等等
【讨论】:
你在用jQuery,不是吗?【参考方案8】:只是为了好玩,这里有一种使用函数的方法:
jsonObject = (new Function('return ' + jsonFormatData))()
【讨论】:
有趣的方法,我不确定我是否将它与可用的 JSON.Parse 一起使用,但很高兴看到有人跳出框框思考。 这与只使用eval
非常相似,并不安全。 :P
这具有使用 eval
的所有缺点,但更复杂,维护者更难理解。【参考方案9】:
$.ajax(
url: url,
dataType: 'json',
data: data,
success: callback
);
回调传递返回的数据,该数据将是由 JSON 结构定义并使用 $.parseJSON()
方法解析的 JavaScript 对象或数组。
【讨论】:
【参考方案10】:使用JSON.parse
可能是最好的方法。
这是一个例子
var jsonRes = ' "students" : [' +
' "firstName":"Michel" , "lastName":"John" ,"age":18,' +
' "firstName":"Richard" , "lastName":"Joe","age":20 ,' +
' "firstName":"James" , "lastName":"Henry","age":15 ]';
var studentObject = JSON.parse(jsonRes);
【讨论】:
【参考方案11】:尝试使用此 Data 对象的方法。例如:Data='result:true,count:1
'
try
eval('var obj=' + Data);
console.log(obj.count);
catch(e)
console.log(e.message);
当您正在使用串行端口编程时,此方法在 Nodejs 中确实很有帮助
【讨论】:
人们固执于“eval 是邪恶的”真的很有趣,他们会做任何事情来避免它,甚至重写整个 eval 功能.. 共识这个技巧是将字符串转换为 JSON 对象的安全方法吗?我可以使用它,因为不需要额外的 js 导入。 ANY 使用eval
或 Function
的方法同样容易受到攻击
undefined; function bye() ... bye();
【参考方案12】:
使用parse()
方法最简单的方法:
var response = '"result":true,"count":1';
var JsonObject= JSON.parse(response);
然后就可以得到JSON元素的值了,例如:
var myResponseResult = JsonObject.result;
var myResponseCount = JsonObject.count;
按照jQuery.parseJSON()
文档中的说明使用jQuery:
JSON.parse(jsonString);
【讨论】:
【参考方案13】:我找到了一个“更好”的方法:
在 CoffeeScript 中:
try data = JSON.parse(jqxhr.responseText)
data ||= message: 'Server error, please retry'
在 Javascript 中:
var data;
try
data = JSON.parse(jqxhr.responseText);
catch (_error)
data || (data =
message: 'Server error, please retry'
);
【讨论】:
【参考方案14】:JSON 解析总是很痛苦。如果输入与预期不符,则会引发错误并使您正在做的事情崩溃。
您可以使用以下小函数来安全地解析您的输入。即使输入无效或已经是在大多数情况下更好的对象,它也总是会转动一个对象:
JSON.safeParse = function (input, def)
// Convert null to empty object
if (!input)
return def || ;
else if (Object.prototype.toString.call(input) === '[object Object]')
return input;
try
return JSON.parse(input);
catch (e)
return def || ;
;
【讨论】:
Object.prototype.toString.call(input) === '[object Object]'
应该是 typeof input === 'object'
IMO
typeof 输入返回 null 对象和数组。所以这不是安全的方法。
您之前已经介绍过null
的情况,并且数组是 一个对象。如果你想测试它,你可以使用instanceof
。此外,如果你给这个函数一个Array
,它会捕捉到return def
,它可以返回完美的数组。
我的评论是关于捕捉物体时的常识。我的函数可以有几个预防措施,但使用 typeof 输入通常不是检测对象的首选方式。
IMO,常识不使用toString()
方法来检查变量是否为对象。见AngularJS、jQuery、Underscore,甚至devs【参考方案15】:
JSON.parse(jsonString);
json.parse 会变成对象。
【讨论】:
【参考方案16】:如果我们有这样的字符串:
"\"status\":1,\"token\":\"65b4352b2dfc4957a09add0ce5714059\""
那么我们可以简单地使用JSON.parse
两次将该字符串转换为JSON 对象:
var sampleString = "\"status\":1,\"token\":\"65b4352b2dfc4957a09add0ce5714059\""
var jsonString= JSON.parse(sampleString)
var jsonObject= JSON.parse(jsonString)
我们可以使用以下方法从 JSON 对象中提取值:
// instead of last JSON.parse:
var status, token = JSON.parse(jsonString);
结果将是:
status = 1 and token = 65b4352b2dfc4957a09add0ce5714059
【讨论】:
【参考方案17】:JSON.parse()
将传入函数的任何 JSON 字符串转换为 JSON 对象。
为了更好地理解它,请按F12在浏览器中打开“Inspect Element”并进入控制台编写以下命令:
var response = '"result":true,"count":1'; //sample json object(string form)
JSON.parse(response); //converts passed string to JSON Object.
现在运行命令:
console.log(JSON.parse(response));
你会得到一个对象result: true, count: 1
的输出。
为了使用那个对象,你可以把它赋值给变量,也许是obj
:
var obj = JSON.parse(response);
通过使用 obj
和点 (.
) 运算符,您可以访问 JSON 对象的属性。
尝试运行命令:
console.log(obj.result);
【讨论】:
【参考方案18】:官方文档:
JSON.parse()
方法解析 JSON 字符串,构造字符串描述的 JavaScript 值或对象。可以提供一个可选的reviver
函数来在结果对象返回之前对其进行转换。
语法:
JSON.parse(text[, reviver])
参数:
text
: 要解析为 JSON 的字符串。有关 JSON 语法的说明,请参阅 JSON 对象。
reviver (optional)
: 如果是函数,这规定了最初通过解析产生的值在返回之前如何转换。
返回值
与给定 JSON 文本对应的 Object。
例外情况
如果要解析的字符串不是有效的 JSON,则抛出 SyntaxError 异常。
【讨论】:
【参考方案19】:用JSON.parse()
解析JSON字符串,数据变成JavaScript对象:
JSON.parse(jsonString)
这里,JSON代表处理JSON数据集。
想象一下我们从网络服务器收到了这个文本:
' "name":"John", "age":30, "city":"New York"'
解析成 JSON 对象:
var obj = JSON.parse(' "name":"John", "age":30, "city":"New York"');
这里 obj
是相应的 JSON 对象,如下所示:
"name":"John", "age":30, "city":"New York"
要获取值,请使用 .
运算符:
obj.name // John
obj.age //30
使用 JSON.stringify()
将 JavaScript 对象转换为字符串。
【讨论】:
【参考方案20】:将对象转换为 JSON,然后对其进行解析,对我有用,例如:
JSON.parse(JSON.stringify(object))
【讨论】:
【参考方案21】:只是针对不同输入类型的封面解析
用 JSON.parse() 解析数据,数据变成 JavaScript 对象。
var obj = JSON.parse(' "name":"John", "age":30, "city":"New York"');
在从数组派生的 JSON 上使用 JSON.parse() 时,该方法将返回 JavaScript 数组,而不是 JavaScript 对象。
var myArr = JSON.parse(this.responseText);
console.log(myArr[0]);
JSON 中不允许使用日期对象。 对于日期做这样的事情
var text = ' "name":"John", "birth":"1986-12-14", "city":"New York"';
var obj = JSON.parse(text);
obj.birth = new Date(obj.birth);
JSON 中不允许使用函数。 如果需要包含函数,请将其写为字符串。
var text = ' "name":"John", "age":"function () return 30;", "city":"New York"';
var obj = JSON.parse(text);
obj.age = eval("(" + obj.age + ")");
【讨论】:
【参考方案22】:老问题,我知道,但是没有人注意到这个解决方案是使用new Function()
,一个返回数据的匿名函数。
只是一个例子:
var oData = 'test1:"This is my object",test2:"This is my object"';
if( typeof oData !== 'object' )
try
oData = (new Function('return '+oData+';'))();
catch(e) oData=false;
if( typeof oData !== 'object' )
alert( 'Error in code' );
else
alert( oData.test1 );
alert( oData.test2 );
这更安全一点,因为它在函数内部执行,而不是直接在您的代码中编译。所以如果里面有函数声明,就不会绑定到默认的window对象。
我使用它来简单快速地“编译”DOM 元素的配置设置(例如数据属性)。
【讨论】:
【参考方案23】:总结:
Javascript(浏览器和 NodeJS)有一个内置的 JSON
对象。在这个对象上有两种方便的方法来处理JSON
。它们是:
JSON.parse()
以JSON
为参数,返回JS对象
JSON.stringify()
以 JS 对象为参数返回 JSON
对象
其他应用:
除了非常方便地处理JSON
之外,它们还可以用于其他方式。 JSON
两种方法的结合使我们能够非常轻松地对数组或对象进行深度克隆。例如:
let arr1 = [1, 2, [3 ,4]];
let newArr = arr1.slice();
arr1[2][0] = 'changed';
console.log(newArr); // not a deep clone
let arr2 = [1, 2, [3 ,4]];
let newArrDeepclone = JSON.parse(JSON.stringify(arr2));
arr2[2][0] = 'changed';
console.log(newArrDeepclone); // A deep clone, values unchanged
【讨论】:
【参考方案24】:您也可以使用reviver
函数进行过滤。
var data = JSON.parse(jsonString, function reviver(key, value)
//your code here to filter
);
更多信息请阅读JSON.parse
。
【讨论】:
【参考方案25】:性能
这个问题已经有了很好的答案,但是我对性能很好奇,今天 2020.09.21 我在 Chrome v85、Safari v13.1.2 和 Firefox v80 上对 MacOs HighSierra 10.13.6 进行了测试,以选择解决方案。
结果
eval/Function
(A,B,C) 方法在 Chrome 上速度很快(但对于大深度对象 N=1000,它们会崩溃:“超出最大堆栈调用)
eval
(A) 在所有浏览器上都是快/中快
JSON.parse
(D,E) 在 Safari 和 Firefox 上最快
详情
我执行了 4 个测试用例:
对于小的浅层物体HERE 对于小的深对象HERE 对于大的浅对象HERE 对于大深度对象HERE上述测试中使用的对象来自HERE
let obj_ShallowSmall =
field0: false,
field1: true,
field2: 1,
field3: 0,
field4: null,
field5: [],
field6: ,
field7: "text7",
field8: "text8",
let obj_DeepSmall =
level0:
level1:
level2:
level3:
level4:
level5:
level6:
level7:
level8:
level9: [[[[[[[[[['abc']]]]]]]]]],
,
;
let obj_ShallowBig = Array(1000).fill(0).reduce((a,c,i) => (a['field'+i]=getField(i),a) ,);
let obj_DeepBig = genDeepObject(1000);
// ------------------
// Show objects
// ------------------
console.log('obj_ShallowSmall:',JSON.stringify(obj_ShallowSmall));
console.log('obj_DeepSmall:',JSON.stringify(obj_DeepSmall));
console.log('obj_ShallowBig:',JSON.stringify(obj_ShallowBig));
console.log('obj_DeepBig:',JSON.stringify(obj_DeepBig));
// ------------------
// HELPERS
// ------------------
function getField(k)
let i=k%10;
if(i==0) return false;
if(i==1) return true;
if(i==2) return k;
if(i==3) return 0;
if(i==4) return null;
if(i==5) return [];
if(i==6) return ;
if(i>=7) return "text"+k;
function genDeepObject(N)
// generate: level0:level1:...levelN: end:[[[...N-times...['abc']...]]] ...
let obj=;
let o=obj;
let arr = [];
let a=arr;
for(let i=0; i<N; i++)
o['level'+i]=;
o=o['level'+i];
let aa=[];
a.push(aa);
a=aa;
a[0]='abc';
o['end']=arr;
return obj;
下面的 sn-p 给出了选择的解决方案
// src: https://***.com/q/45015/860099
function A(json)
return eval("(" + json + ')');
// https://***.com/a/26377600/860099
function B(json)
return (new Function('return ('+json+')'))()
// improved https://***.com/a/26377600/860099
function C(json)
return Function('return ('+json+')')()
// src: https://***.com/a/5686237/860099
function D(json)
return JSON.parse(json);
// src: https://***.com/a/233630/860099
function E(json)
return $.parseJSON(json)
// --------------------
// TEST
// --------------------
let json = '"a":"abc","b":"123","d":[1,2,3],"e":"a":1,"b":2,"c":3';
[A,B,C,D,E].map(f=>
console.log(
f.name + ' ' + JSON.stringify(f(json))
))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
This shippet only presents functions used in performance tests - it not perform tests itself!
以下是 chrome 的示例结果
【讨论】:
【参考方案26】:试试这个。这是用打字稿写的。
export function safeJsonParse(str: string)
try
return JSON.parse(str);
catch (e)
return str;
【讨论】:
我是 Typescript 的新手。这对JSON.parse()
有什么好处?
如果发生任何异常,这将返回输入字符串本身
@MarcL。据我所知,TypeScript 不会修改 JSON.parse() 和任何其他系统方法(但我没有在这个方向进行研究)【参考方案27】:
/**
* Safely turning a JSON string into an object
*
* @param String str - JSON String
* @returns deserialized object, false if error
*/
export function jsonParse(str)
let data = null;
try
data = JSON.parse(str);
catch (err)
return false;
return data;
【讨论】:
以上是关于安全地将 JSON 字符串转换为对象的主要内容,如果未能解决你的问题,请参考以下文章