What is secure-json-parse?
The secure-json-parse package is designed to safely parse JSON strings without the vulnerabilities associated with the native JSON.parse method. It provides protection against prototype pollution attacks, which can be a security concern when parsing user-supplied JSON data in JavaScript applications. By using secure-json-parse, developers can ensure that their applications are more secure against certain types of attacks that exploit the structure of JSON data.
What are secure-json-parse's main functionalities?
Safe parsing of JSON strings
This feature allows for the safe parsing of JSON strings, ensuring that the resulting object does not have prototype pollution vulnerabilities. The code sample demonstrates how to parse a simple JSON string safely.
const sjson = require('secure-json-parse');
const safeObj = sjson.parse('{"a":"b"}');
Custom reviver function support
This feature allows developers to provide a custom reviver function, which can be used to transform the JSON object's values during parsing. The code sample demonstrates parsing a JSON string with a date field, using a reviver function to convert the date string into a Date object.
const sjson = require('secure-json-parse');
const options = {reviver: (key, value) => (key === 'date' ? new Date(value) : value)};
const safeObj = sjson.parse('{"date":"2023-04-01T00:00:00.000Z"}', options);
Protection options customization
This feature allows for customization of protection actions against prototype pollution. Developers can specify how to handle '__proto__' and 'constructor' properties in the parsed JSON. The code sample demonstrates removing these potentially dangerous properties during parsing.
const sjson = require('secure-json-parse');
const options = {protoAction: 'remove', constructorAction: 'remove'};
const safeObj = sjson.parse('{"__proto__": {"a":"b"}, "constructor": {"prototype": {"a":"b"}}}', options);
Other packages similar to secure-json-parse
fast-json-parse
fast-json-parse is a package that focuses on providing a fast and safe way to parse JSON strings. While it emphasizes performance, it may not offer the same level of security features specifically designed to prevent prototype pollution attacks as secure-json-parse does.
flatted
flatted is a package that offers JSON parsing and stringifying with support for circular references. While it addresses a different aspect of JSON handling (circular references), it does not specifically focus on security concerns like prototype pollution, which is the main focus of secure-json-parse.
secure-json-parse
JSON.parse()
drop-in replacement with prototype poisoning protection.
Introduction
Consider this:
> const a = '{"__proto__":{ "b":5}}';
'{"__proto__":{ "b":5}}'
> const b = JSON.parse(a);
{ __proto__: { b: 5 } }
> b.b;
undefined
> const c = Object.assign({}, b);
{}
> c.b
5
The problem is that JSON.parse()
retains the __proto__
property as a plain object key. By
itself, this is not a security issue. However, as soon as that object is assigned to another or
iterated on and values copied, the __proto__
property leaks and becomes the object's prototype.
Install
npm i secure-json-parse
Usage
Pass the option object as a second (or third) parameter for configuring the action to take in case of a bad JSON, if nothing is configured, the default is to throw a SyntaxError
.
You can choose which action to perform in case __proto__
is present, and in case constructor.prototype
is present.
const sjson = require('secure-json-parse')
const goodJson = '{ "a": 5, "b": 6 }'
const badJson = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "constructor": {"prototype": {"bar": "baz"} } }'
console.log(JSON.parse(goodJson), sjson.parse(goodJson, undefined, { protoAction: 'remove', constructorAction: 'remove' }))
console.log(JSON.parse(badJson), sjson.parse(badJson, undefined, { protoAction: 'remove', constructorAction: 'remove' }))
API
sjson.parse(text, [reviver], [options])
Parses a given JSON-formatted text into an object where:
text
- the JSON text string.reviver
- the JSON.parse()
optional reviver
argument.options
- optional configuration object where:
protoAction
- optional string with one of:
'error'
- throw a SyntaxError
when a __proto__
key is found. This is the default value.'remove'
- deletes any __proto__
keys from the result object.'ignore'
- skips all validation (same as calling JSON.parse()
directly).
constructorAction
- optional string with one of:
'error'
- throw a SyntaxError
when a constructor.prototype
key is found. This is the default value.'remove'
- deletes any constructor
keys from the result object.'ignore'
- skips all validation (same as calling JSON.parse()
directly).
sjson.scan(obj, [options])
Scans a given object for prototype properties where:
obj
- the object being scanned.options
- optional configuration object where:
protoAction
- optional string with one of:
'error'
- throw a SyntaxError
when a __proto__
key is found. This is the default value.'remove'
- deletes any __proto__
keys from the input obj
.
constructorAction
- optional string with one of:
'error'
- throw a SyntaxError
when a constructor.prototype
key is found. This is the default value.'remove'
- deletes any constructor
keys from the input obj
.
Benchmarks
Machine: 2,7 GHz Quad-Core Intel Core i7
v14.8.0
> node ignore.js
JSON.parse x 679,376 ops/sec ±1.15% (84 runs sampled)
secure-json-parse x 649,605 ops/sec ±0.58% (87 runs sampled)
reviver x 244,414 ops/sec ±1.05% (88 runs sampled)
Fastest is JSON.parse
> node no__proto__.js
JSON.parse x 652,190 ops/sec ±0.67% (86 runs sampled)
secure-json-parse x 589,785 ops/sec ±1.01% (88 runs sampled)
reviver x 218,075 ops/sec ±1.58% (87 runs sampled)
Fastest is JSON.parse
> node remove.js
JSON.parse x 683,527 ops/sec ±0.62% (88 runs sampled)
secure-json-parse x 316,926 ops/sec ±0.63% (87 runs sampled)
reviver x 214,167 ops/sec ±0.63% (86 runs sampled)
Fastest is JSON.parse
> node throw.js
JSON.parse x 682,548 ops/sec ±0.60% (88 runs sampled)
JSON.parse error x 170,716 ops/sec ±0.93% (87 runs sampled)
secure-json-parse x 104,483 ops/sec ±0.62% (87 runs sampled)
reviver x 114,197 ops/sec ±0.63% (87 runs sampled)
Fastest is JSON.parse
Acknowledgements
This project has been forked from hapijs/bourne.
All the credits before the commit 4690682 goes to the hapijs/bourne project contributors.
After, the project will be maintained by the Fastify team.
License
Licensed under BSD-3-Clause.