Expand description
A crate to protect against malicious JSON payloads.
This crate provides functionality to validate JSON payloads against a set of constraints.
- Maximum depth of the JSON structure.
- Maximum length of strings.
- Maximum number of entries in arrays.
- Maximum number of entries in objects.
- Maximum length of object entry names.
- Whether to allow duplicate object entry names.
This crate is designed to process untrusted JSON payloads, such as it does not use recursion to validate the JSON structure.
§Examples
use json_threat_protection as jtp;
fn reject_highly_nested_json(data: &[u8], depth: usize) -> Result<(), jtp::Error> {
jtp::from_slice(data).with_max_depth(depth).validate()
}
fn reject_too_long_strings(data: &[u8], max_string_length: usize) -> Result<(), jtp::Error> {
jtp::from_slice(data).with_max_string_length(max_string_length).validate()
}
fn reject_too_many_array_entries(data: &[u8], max_array_entries: usize) -> Result<(), jtp::Error> {
jtp::from_slice(data).with_max_array_entries(max_array_entries).validate()
}
fn reject_too_many_object_entries(data: &[u8], max_object_entries: usize) -> Result<(), jtp::Error> {
jtp::from_slice(data).with_max_object_entries(max_object_entries).validate()
}
fn reject_too_long_object_entry_names(data: &[u8], max_object_entry_name_length: usize) -> Result<(), jtp::Error> {
jtp::from_slice(data).with_max_object_entry_name_length(max_object_entry_name_length).validate()
}
fn reject_duplicate_object_entry_names(data: &[u8]) -> Result<(), jtp::Error> {
jtp::from_slice(data).disallow_duplicate_object_entry_name().validate()
}
§Default constraints
By default, the validator just checks the JSON syntax without any constraints, and also allows duplicate object entry names.
You could set the limit to NO_LIMIT
to disable a specific constraint.
§Incremental validation
The Validator
struct is designed to be used incrementally,
so you can validate huge JSON payloads in multiple function calls
without blocking the current thread for a long time.
use json_threat_protection as jtp;
fn validate_incrementally(data: &[u8]) -> Result<(), jtp::Error> {
let mut validator = jtp::from_slice(data);
// validate the JSON payload in 2000 steps,
// and return `Some(true)` if the validation is finished and no errors.
// return `Some(false)` to continue the validation.
// Otherwise, return `Err` if an error occurred.
while validator.validate_with_steps(2000)? {
// do something else such as processing other tasks
}
Ok(())
}
This feature is useful when you want to validate a JSON payload in a non-blocking way, the typical use case is used to build FFI bindings to other software that needs to validate JSON payloads in a non-blocking way to avoid blocking the thread.
§Error handling
This crate has limited place where might panic, most of errors are returned as Err
.
And some unintended bugs might also return as Err
with explicit error kind
to indicate we are running into buggy code.
Whatever the error kind is,
it always contains the position where the error occurred, such as line, column, and offset,
the offset
is the byte offset from the beginning of the JSON payload.
§Special behavior compared to serde_json
This crate do it best to keep consistent with serde_json
’s behavior
using the cargo-fuzz
to process the same JSON payloading with both this crate and serde_json
and compare the validation results.
However, there are some differences between this crate and serde_json
so far:
- This crate allow any precision of numbers,
even if it cannot be represented in Rust’s native number types (
i64
,u64
,i128
,u128
,f64
,f128
). The serde_json without arbitrary_precision feature enabled will return an error for such numbers.
§Performance
This crate is designed to be fast and efficient,
and has its own benchmark suite under the benches
directory.
You can run the benchmarks with the following command:
JSON_FILE=/path/to/file.json cargo bench --bench memory -- --verbose
This suite validates the JSON syntax using both this crate and serde_json
,
you could get your own performance number by specifying the JSON_FILE
to your dataset.
§Fuzzing
This crate is fuzzed using the cargo-fuzz tool,
program is under the fuzz
directory.
The initial seed corpus is from nlohmann/json_test_data, and extra corpus follows the nlohmann/json/blob/develop/tests/fuzzing.
Re-exports§
pub use read::ReadError;
Modules§
- read
- Defines the
Read
trait, and provided implementations forstd::io::Read
,&str
, and slice foru8
.
Structs§
- Validator
- The JSON validator.
Enums§
- Error
- Error occurred during JSON validation
- Lexer
Error - An error that occurred while lexing a JSON input.
Constants§
- NO_
LIMIT - Represents no limit for a specific constraint.
Functions§
- from_
reader - Creates a new
Validator
instance with the given reader without any constraints. - from_
slice - Creates a new
Validator
instance with the given slice of bytes without any constraints. - from_
str - Creates a new
Validator
instance with the given&str
without any constraints.