在前端开发中,我们经常使用JSON.stringify和JSON.parse这两个方法来进行JSON数据的序列化和反序列化操作。但是,在实际使用中,我们会发现这两个方法都存在一些安全性问题,容易被JSON注入攻击。在ES10中,解决了这个问题,本篇文章就以此为主题,来讲述ES10中JSON.stringify和JSON.parse的更安全可靠的用法。
什么是JSON注入攻击
在前端开发中,常常需要通过接口获取JSON数据并展示在页面上,这时就需要使用JSON.parse来将JSON数据解析成JavaScript对象,在JavaScript中操作这些数据。JSON数据中的字符串值(特别是用户输入的数据)可能包含一些特殊字符(例如"&","<",">"等)或者JSON对象属性名或值中包含某些字符成为攻击者的潜在入口,攻击者可以通过JSON注入攻击利用这些字符来突破前端防御机制并获取敏感信息或者攻击服务器。
例如,假设我们有一个包含用户列表的JSON对象:
-- -------------------- ---- ------- - -------- - - ------- -------- ------ -- -- - ------- ------ ------ -- - - -
我们通常通过以下方式将其发送给浏览器:
res.end(JSON.stringify(users));
然而,如果一个用户输入了恶意数据,比如:
<script>alert('JSON injection attack');</script>
其发送的数据将会被攻击者篡改,导致整个页面失效。
ES10如何解决JSON注入攻击
在ES10中,JSON.stringify和JSON.parse方法都添加了第二个参数,可以让我们指定对JSON数据进行额外的处理和安全性检查。
JSON.stringify
JSON.stringify函数接受三个参数:值、未知键和缩进级别。在ES10中,它还接受两个可选的参数:replacer和space。
首先,我们来看一下第一个可选参数:replacer。它是一个函数,可以用来控制序列化哪些属性。它在序列化每个可枚举的属性/键值对之前被传递。在这里,我们可以选择从输出中删除一些属性、删除非法字符、转换数据类型等。
例如,我们可以这样使用replacer参数:
-- -------------------- ---- ------- --- --- - ----- ---------- ---- ------- --- -------- - ----- ------ -- - -- ------- ----- --- ------------ - ------ ------------ - ------ ------ - --- ---- - ------------------- ---------- ------------------ -- -------------------------------
在这个例子中,我们将undefined的值强制转换为字符串值,这样我们就可以在JSON对象中看到这个值。
现在,我们来看一下第二个可选参数:space。这个参数代表是否格式化输出。如果我们不希望输出被格式化,我们可以将它设置为0。如果我们希望格式化输出以人类可读的形式,我们可以将它设置为任意数字,这个数字代表缩进的级别。
接下来,我们来看一下ES10新增的第三个参数:options。它是一个对象,使用它我们可以更加细致地控制序列化过程。options包含以下属性:
options.error
如果我们提供一个可选的error函数,当JSON.stringify遇到一个不可序列化的属性时,它将调用这个函数。这个函数可以将非法值转换为另一个可以安全序列化或表示的值,或者如果您希望,将值删除。
-- -------------------- ---- ------- --- --- - ----- -- -- ---------- ---- ------- --- -------- - ----- ------ -- - -- ------- ----- --- ------------ - ------ ------------ - -- ------- ----- --- ---------- - - ------ ----------- - ------ ------ - --- ------- - - --------- --------- ------ -- ------ ------- -- - ------ ---------- - -- --- ---- - ------------------- --------- ------------------ -- -----------------------------
options.space
这是一个代表空格缩进的数字或字符串。如果它是一个数字,它表示要用于缩进的空格数。如果它是一个字符串,它将用作缩进字符串。
let obj = {foo: undefined, bar: 'baz'}; let options = { space: '*' }; let json = JSON.stringify(obj, null, options); console.log(json); // { "foo": "undefined", "bar": "baz" }
options.escape
如果我们想要JSON中的特殊字符被转义并转换为unicode而不是被嵌入到JSON字符串中,我们可以设置该选项为true。
-- -------------------- ---- ------- --- --- - - ------ ---- ---------- ---- - --- ------- - - ------- ---- - --- ---- - ------------------- ----- --------- ------------------ -- ---------------------------------------
JSON.parse
JSON.parse函数也接受两个参数。第一个参数是一个JSON字符串,第二个参数是一个可选的缩写函数,它在每个键值对被解析之后被调用,并将解析的值作为函数的参数传递。
我们可以将值转换为我们想要的类型,例如字符串转换为数字。
let json = '{"name": "Tom", "age": "25"}'; let value = JSON.parse(json, (key, value) => { return key === 'age' ? +value : value; }); console.log(typeof value.age); // number
我们可以使用缩写函数来过滤非法字符或防止安全隐患。
-- -------------------- ---- ------- --- ---- - -------------------------------------- ------ ----- --- ----- - ---------------- ----- ------ -- - -- ------- ----- --- --------- - ------ ------------------- --------------------- -------- - ------ ------ --- ------------------------ -- --------------------------------------
总结
在ES10中,我们可以使用JSON.stringify和JSON.parse的可选参数来控制JSON数据的序列化和反序列化,更加安全地防御JSON注入攻击。没用过的同学建议深入了解。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64a615e748841e9894299528