untrusted_value/
lib.rs

1//! # Untrusted Value
2//! This crate aim to provide a type-safe way to handle and sanitize potentially untrusted values
3//! like user input.
4//!
5//! It aims to provide compile-time [Taint checking](https://en.wikipedia.org/wiki/Taint_checking)
6//! into Rust. All user input or in general all input coming from the outside
7//! world into the program must be seen as untrusted and potentially malicious (called tainted).
8//! A tainted value keeps its taint until a proper sanitization function is called
9//! upon the tainted data, clearing its taint.
10//!
11//! This crate introduces several data types, traits and macros to simplify the process
12//! of taint tracking.
13//!
14//! ## What's the goal of this crate?
15//! The goal of this crate is to help design more secure applications. By tainting all
16//! program inputs, unsanitized data can not be used by accident. By providing a sanitizing
17//! interface to tainted data, security analysis can focus on analysing the implemented sanitizing functions
18//! instead of identifying where tainted data is located, and where it is used.
19//!
20//! ## Example usage
21//! User data must be wrapped within the container [`UntrustedValue`] which
22//! provides marks the contained data as tainted.
23//! ```rust
24//! use untrusted_value::{UntrustedValue, SanitizeWith};
25//! #
26//! # let user_input: i32 = -36;
27//! let user_input = UntrustedValue::from(user_input);
28//!
29//! let trusted_value: u32 = user_input.sanitize_with(
30//! # |value| {
31//! # Ok::<u32, ()>(value.unsigned_abs())
32//! # }
33//!     // ...
34//! ).expect("Sanitization failed");
35//!
36//! println!("Sanitized value: {:?}", trusted_value);
37//! ```
38//!
39//! When user data is a struct of different subtypes:
40//!
41//! ```rust
42//! pub use untrusted_value::{IntoUntrustedVariant, SanitizeValue};
43//! use untrusted_value::UntrustedValue;
44//! pub use untrusted_value::derive::UntrustedVariant;
45//!
46//! use untrusted_value::SanitizeWith;
47//!
48//! #[derive(UntrustedVariant)]
49//! #[untrusted_derive(SanitizeValueEnd, Clone)] // tainted variant should be Cloneable
50//! pub struct NetworkConfig {
51//!     pub port: u32,
52//!     pub listen_address: String,
53//! }
54//!
55//! # fn no_sanitize<T>(value: T) -> Result<T, ()>{
56//! #     Ok(value)
57//! # }
58//! #
59//! impl SanitizeValue<NetworkConfig> for NetworkConfigUntrusted {
60//!     type Error = ();
61//!
62//!     fn sanitize_value(self) -> Result<NetworkConfig, Self::Error> {
63//!         Ok(NetworkConfig {
64//!             port: self.port.sanitize_with(no_sanitize)?,
65//!             listen_address: self.listen_address.sanitize_with(no_sanitize)?
66//!         })
67//!     }
68//! }
69//!
70//! fn load_from_config() -> NetworkConfigUntrusted {
71//!     let from_serde = NetworkConfig {
72//!         port: 1111,
73//!         listen_address: "0.0.0.0".into(),
74//!     };
75//!     from_serde.to_untrusted_variant()
76//! }
77//!
78//! let user_data = load_from_config();
79//!
80//! // user data cannot be used on accident, since it is contained inside UntrustedValues
81//!
82//! let user_data_clean = user_data.sanitize_value();
83//! ```
84//!
85//! When a function is called by an application framework like Rocket/Poem/...,
86//! the macro `untrusted_inputs` may be used to taint the function inputs:
87//!
88//! ```rust
89//! use untrusted_value::derive::untrusted_inputs;
90//! use untrusted_value::SanitizeWith;
91//! #
92//! # fn no_sanitize<T>(value: T) -> Result<T, ()>{
93//! #    Ok(value)
94//! # }
95//!
96//! // #[route(path = "/"), method = "get"]
97//! #[untrusted_inputs]
98//! fn index(name: &str) -> Result<String, ()> {
99//!     // MACRO inserts the following code:
100//!         // let name = UntrustedValue::from(name);
101//!         // let ... = UntrustedValue::from(...);
102//!
103//!     // we can not use "name" directly, since it is
104//!     // wrapped in an UntrustedValue
105//!
106//!     // we must explicitly sanitize the value before usage
107//!     let name = name.sanitize_with(no_sanitize)?;
108//!     Ok(format!("Hello, {}!", name))
109//! }
110//! ```
111//!
112//! A library providing a function that returns untrusted data may use the macro `untrusted_output` to conditionally
113//! taint the output if the library user desires this:
114//!
115//! ```rust
116//! #[cfg_attr(feature = "some_feature", untrusted_output)]
117//! pub fn query_database() -> String {
118//!     // if cfg matches, then use untrusted_output to wrap the
119//!     // function output in UntrustedValue
120//!
121//!     // the macro will wrap the body with:
122//!         // UntrustedValue::from(
123//!     "abcdef".to_string()
124//!         // )
125//! }
126//! ```
127//!
128//! See also the examples in the `examples` directory.
129//!
130//! ## Installation
131//! The library is written in Rust, and can be added using `cargo`:
132//! ```bash
133//! cargo add untrusted-value
134//! ```
135//!
136//! ## Features
137//! Enabled by default:
138//!  * `derive`: enables the macros to automatically generate code
139//!
140//! Optional features:
141//!  * `derive_harden_sanitize`: enables hardening for the derive macro `SanitizeValue`. When this feature is disabled, the
142//!    implemented `fn sanitize_value(self)` errors-early. Which may be undesired if sanitizing timing side
143//!    channels are a concern. When enabling this feature, first all sanitizers are run, then
144//!    the first error is propagated.
145//!
146//! ## Runtime overhead
147//! When using compile optimizations there should be no runtime overhead since
148//! we are essentially just "renaming" data. The [`UntrustedValue`]
149//! struct only contains a single field of the original data type.
150//! When compiling for release the compiler should optimize all usage
151//! of the [`UntrustedValue`] struct away.
152//!
153//! ## Limitations
154//! Providing a taint tracking system is nice but still requires the developer to
155//! taint the data properly. Currently, we are working on providing a crate level macro
156//! to automatically check common taint source like input from environment variables, args, and
157//! common frameworks, that will create a compile error if input data has not been tainted.
158//!
159//! This crate does only provide an interface to taint and sanitize data. Using this system, still this does
160//! not make an application inherently secure. The developer must still implement
161//! appropriate sanitizing functions to clear the taint of the data. This unified
162//! interface should help to focus security analysis on the sanitizing functions
163//! instead of on potentially all places where tainted data might be used.
164//!
165//! ## Contribution
166//! Contributions to the project are welcome! If you have a feature request,
167//! bug report, or want to contribute to the code, please open an
168//! issue or a pull request.
169#![warn(missing_docs)]
170
171pub use untrusted_value_derive_internals::*;
172
173/// Contains all proc macros utilities to help handling tainted values.
174/// For a detailed documentation, see documentation of each macro.
175#[cfg(feature = "derive")]
176pub mod derive {
177    pub use untrusted_value_derive::*;
178}
179
180mod untrusted_value;
181pub use untrusted_value::*;
182
183mod maybe_untrusted;
184pub use maybe_untrusted::*;