#user-input #sanitization #security #taint #validation #static-analyis #macro-derive

untrusted_value_derive_internals

本库旨在提供一种类型安全的方式来处理和清理潜在的不可信值,如用户输入。

9 个版本

0.3.1 2024 年 7 月 20 日
0.3.0 2024 年 7 月 20 日
0.2.4 2024 年 7 月 18 日
0.1.1 2024 年 7 月 15 日

2440Rust 模式

Download history 266/week @ 2024-07-11 387/week @ 2024-07-18 39/week @ 2024-07-25

692 每月下载量
3 个库中(通过 untrusted_value 使用)

MIT 许可证

15KB

不可信值

本库旨在提供一种类型安全的方式来处理和清理潜在的不可信值,如用户输入。

它旨在将 Rust 中的污点检查作为编译时功能提供。所有用户输入或在一般情况下,所有来自外部世界的输入都必须被视为不可信且可能具有恶意性(称为污点)。污点值会保持其污点状态,直到在污点数据上调用适当的清理函数,清除其污点。

本库引入了多个数据类型、特性和宏来简化污点跟踪的过程。

本库的目标是什么?

本库的目标是帮助设计更安全的应用程序。通过污点化所有程序输入,未清理的数据不能意外使用。通过提供污点数据的清理接口,安全分析可以集中在分析实现的清理函数上,而不是确定污点数据的位置和使用情况。

示例用法

用户数据必须被包装在 UntrustedValue 容器中,该容器提供/标记包含的数据为污点。

use untrusted_value::{UntrustedValue, SanitizeWith};

let user_input: i32 = -36;
let user_input = UntrustedValue::from(user_input);

// user data cannot be used on accident, since it is contained inside UntrustedValues
// UntrustedValue does only provide a limited set of implemented traits like Clone

let user_input = user_input.sanitize_with(...) // removes the taint

当用户数据是不同子类型的结构时

pub use untrusted_value::{IntoUntrustedVariant, SanitizeValue};
pub use untrusted_value::derive::UntrustedVariant;

#[derive(UntrustedVariant)]
#[untrusted_derive(SanitizeValueEnd, Clone)] // tainted variant of NetworkConfig should be Cloneable
pub struct NetworkConfig {
  pub port: u32,
  pub listen_address: String,
}

impl SanitizeValue<NetworkConfig> for NetworkConfigUntrusted {
    type Error = // ...
    fn sanitize_value(self) -> Result<NetworkConfig, Self::Error> { /* ... */ }
}

let user_data = load_from_config().to_untrusted_variant();

// user data cannot be used on accident, since it is contained inside UntrustedValues

let user_data = user_data.sanitize_value();

当应用程序框架(如 Rocket/Poem/...)调用函数时,可以使用宏 untrusted_inputs 来污点函数输入

#[route(path = "/"), method = "get"]
#[untrusted_inputs]
fn index(name: &str) -> Result<String, ()> {
    // MACRO inserts the following code:
        // let name = UntrustedValue::from(name);
        // let ... = UntrustedValue::from(...);
    
    // we can not use "name" directly, since it is
    // wrapped in an UntrustedValue

    // we must explicitly sanitize the value before usage
    let name = name.sanitize_with(/* func */)?;
    Ok(format!("Hello, {}!", name))
}

提供返回不可信数据的函数的库可以使用宏 untrusted_output 来条件性地污点输出,如果库用户希望这样做

#[cfg_attr(feature = "some_feature", untrusted_output)]
pub fn query_database() -> String {
    // if cfg matches, then use untrusted_output to wrap the
    // function output in UntrustedValue

    // the macro will wrap the body with:
        // UntrustedValue::from(
    "abcdef".to_string()
        // )
}

请参阅 examples 目录中的示例。

安装

该库是用 Rust 编写的,可以使用 cargo 添加

cargo add untrusted-value

运行时开销

当使用编译优化时,由于我们本质上只是在“重命名”数据,所以不应该存在运行时开销。`UntrustedValue` 结构体仅包含一个原始数据类型的字段。在编译发布版本时,编译器应该优化所有对 `UntrustedValue` 结构体的使用。

功能

默认启用

  • derive:启用宏自动生成代码

可选功能

  • derive_harden_sanitize:启用 `derive` 宏的加固。当此功能禁用时,实现的 `sanitize_value` 函数会立即报错。如果对清理定时通道感兴趣,这可能是不希望的。当启用此功能时,首先运行所有清理器,然后传播第一个错误。

限制

提供污染跟踪系统是件好事,但仍然需要开发者正确地污染数据。目前,我们正在努力提供一个 crate 级别宏,以自动检查常见的污染源,如来自环境变量的输入、参数和常见框架,如果没有污染输入数据,将创建编译错误。

此 crate 仅提供污染和清理数据的接口。使用此系统,这并不使应用程序本身变得安全。开发者必须仍然实现适当的清理函数以清除数据的污染。这个统一的接口应有助于将安全分析集中在清理函数上,而不是集中在可能使用污染数据的所有地方。

贡献

欢迎对项目的贡献!如果您有功能请求、错误报告或想为代码做出贡献,请打开一个问题或拉取请求。

许可证

此项目受 MIT 许可证许可。有关详细信息,请参阅 LICENSE 文件。

无运行时依赖