UNPKG

4.28 kBMarkdownView Raw
1# @nuxt/devalue
2
3[![npm version][npm-version-src]][npm-version-href]
4[![npm downloads][npm-downloads-src]][npm-downloads-href]
5[![codecov][codecov-src]][codecov-href]
6[![package phobia][package-phobia-src]][package-phobia-href]
7[![bundle phobia][bundle-phobia-src]][bundle-phobia-href]
8
9> Forked from [devalue](https://github.com/Rich-Harris/devalue) to log errors on non-serializable properties rather than throwing `Error`.
10
11Like `JSON.stringify`, but handles
12
13* cyclical references (`obj.self = obj`)
14* repeated references (`[value, value]`)
15* `undefined`, `Infinity`, `NaN`, `-0`
16* regular expressions
17* dates
18* `Map` and `Set`
19* `.toJSON()` method for non-POJOs
20
21Try it out on [runkit.com](https://npm.runkit.com/@nuxt/devalue).
22
23## Goals:
24
25* Performance
26* Security (see [XSS mitigation](#xss-mitigation))
27* Compact output
28
29
30## Non-goals:
31
32* Human-readable output
33* Stringifying functions or arbritary non-POJOs
34
35
36## Usage
37
38```js
39import devalue from '@nuxt/devalue';
40
41let obj = { a: 1, b: 2 };
42obj.c = 3;
43
44devalue(obj); // '{a:1,b:2,c:3}'
45
46obj.self = obj;
47devalue(obj); // '(function(a){a.a=1;a.b=2;a.c=3;a.self=a;return a}({}))'
48```
49
50If `devalue` encounters a function or a non-POJO, it will throw an error.
51
52
53## XSS mitigation
54
55Say 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:
56
57```js
58const state = {
59 userinput: `</script><script src='https://evil.com/mwahaha.js'>`
60};
61
62const template = `
63<script>
64 // NEVER DO THIS
65 var preloaded = ${JSON.stringify(state)};
66</script>`;
67```
68
69Which would result in this:
70
71```html
72<script>
73 // NEVER DO THIS
74 var preloaded = {"userinput":"</script><script src='https://evil.com/mwahaha.js'>"};
75</script>
76```
77
78Using `devalue`, we're protected against that attack:
79
80```js
81const template = `
82<script>
83 var preloaded = ${devalue(state)};
84</script>`;
85```
86
87```html
88<script>
89 var preloaded = {userinput:"\\u003C\\u002Fscript\\u003E\\u003Cscript src=\'https:\\u002F\\u002Fevil.com\\u002Fmwahaha.js\'\\u003E"};
90</script>
91```
92
93This, 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`:
94
95```js
96const value = (0,eval)('(' + str + ')');
97```
98
99
100## Other security considerations
101
102While `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.
103
104When using `eval`, ensure that you call it *indirectly* so that the evaluated code doesn't have access to the surrounding scope:
105
106```js
107{
108 const sensitiveData = 'Setec Astronomy';
109 eval('sendToEvilServer(sensitiveData)'); // pwned :(
110 (0,eval)('sendToEvilServer(sensitiveData)'); // nice try, evildoer!
111}
112```
113
114Using `new Function(code)` is akin to using indirect eval.
115
116
117## See also
118
119* [lave](https://github.com/jed/lave) by Jed Schmidt
120* [arson](https://github.com/benjamn/arson) by Ben Newman
121* [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
122* [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
123
124
125## License
126
127[MIT](LICENSE)
128
129<!-- Refs -->
130[npm-version-src]: https://flat.badgen.net/npm/v/@nuxt/devalue/latest
131[npm-version-href]: https://www.npmjs.com/package/@nuxt/devalue
132
133[npm-downloads-src]: https://flat.badgen.net/npm/dm/@nuxt/devalue
134[npm-downloads-href]: https://www.npmjs.com/package/@nuxt/devalue
135
136[circleci-src]: https://flat.badgen.net/circleci/github/nuxt-contrib/devalue
137[circleci-href]: https://circleci.com/gh/nuxt-contrib/devalue
138
139[package-phobia-src]: https://flat.badgen.net/packagephobia/install/@nuxt/devalue
140[package-phobia-href]: https://packagephobia.now.sh/result?p=@nuxt/devalue
141
142[bundle-phobia-src]: https://flat.badgen.net/bundlephobia/minzip/@nuxt/devalue
143[bundle-phobia-href]: https://bundlephobia.com/result?p=@nuxt/devalue
144
145[codecov-src]: https://flat.badgen.net/codecov/c/github/nuxt-contrib/devalue/master
146[codecov-href]: https://codecov.io/gh/nuxt-contrib/devalue