为了防止SQL注入的风险,我想用一个函数创建一个API,该函数只接受编译时字符串文字作为输入,例如"SELECT * FROM MYTABLE;""WHERE price > 10"等.然后该函数可以进行所需的字符串连接,生成String SQL语句并执行它.这将是执行SQL的唯一方法,因此它保证只从开发人员定义的部分SQL创建SQL语句,并且任何不受信任的用户输入都必须映射到字符串文字.这消除了用户输入以SQL语句结尾的任何可能性.这个是可能的吗?

推荐答案

你可以选&'static str号.这不会因为String::leak()或不安全的代码而消除风险,但这使它变得非常不可能.

如果你真的想要,你可以有一个小宏图:

#[derive(Clone, Copy)]
pub struct StringLiteral(&'static str);

impl StringLiteral {
    /// # Safety
    ///
    /// `v` must be a string literal.
    #[doc(hidden)]
    pub unsafe fn new(v: &'static str) -> Self {
        Self(v)
    }

    pub fn get(self) -> &'static str {
        self.0
    }
}

#[macro_export]
macro_rules! string_literal {
    ($v:literal) => {{
        let v = $v; // This has to be a separate statement, to not be in the `unsafe` block
        // SAFETY: We only accept literals.
        unsafe { $crate::StringLiteral::new(v) }
    }};
}

然后在代码中的任何地方使用StringLiteral,如果不是从文字构造的,这是不可能(合理地)构造的.

Rust相关问答推荐

为什么在Rust struct 中只允许最后一个字段具有动态大小的类型

在‘await’点上使用‘std::同步::Mutex’是否总是会导致僵局?

为什么BitVec缺少Serialize trait?

在铁 rust 中传递所有权

在本例中,为什么我不能一次多次borrow 可变变量?

作为1字节位掩码的布尔值 struct

如何在不调用Collect()的情况下为新型vec实现IntoIterator?

Rust面向对象设计模式

为什么比较Option<;字符串>;具有常数Option<&;str>;需要显式类型转换吗?

处理带有panic 的 Err 时,匹配臂具有不兼容的类型

为什么实现特征的对象期望比具体对象有更长的生命周期?

为什么我的trait 对象类型不匹配?

由特征键控的不同 struct 的集合

类型判断模式匹配panic

在每个循环迭代中删除borrow

为什么 &i32 可以与 Rust 中的 &&i32 进行比较?

将文件的第一行分别读取到文件的其余部分的最有效方法是什么?

基于名称是否存在的条件编译

加入动态数量的期货

为什么在使用 self 时会消耗 struct 而在解构时不会?