8个版本 (4个重大更新)

0.5.1 2023年2月14日
0.5.0 2023年2月14日
0.4.0 2021年1月20日
0.3.0 2020年12月3日
0.1.1 2020年11月16日

数据库接口类别中排名第1980

Download history 1107/week @ 2024-03-09 838/week @ 2024-03-16 160/week @ 2024-03-23 11/week @ 2024-03-30 3/week @ 2024-04-06

每月下载量:284
concatsql_macro中使用

MIT许可证

110KB
2.5K SLoC

ConcatSQL

Actions Status Crates.io Documentation License

ConcatSQL(concatsql)是一个安全的SQL数据库库。
您可以使用字符串连接来防止SQL注入。

文档

支持的数据库

您可以在Cargo.toml中配置数据库后端

[dependencies]
concatsql = { version = "<version>", features = ["<postgres|mysql|sqlite>"] }

示例

正常值

let id     = String::from("42");    // User supplied input
let passwd = String::from("pass");  // User supplied input

let query = query!("SELECT name FROM users WHERE id={id} AND passwd={passwd}");
assert_eq!(query.simulate(), "SELECT name FROM users WHERE id='42' AND passwd='pass'");

for row in conn.rows(&query).unwrap() {
    assert_eq!(row.get(0).unwrap(),      "Alice");
    assert_eq!(row.get("name").unwrap(), "Alice");
}

危险值

let id     = String::from("42");             // User supplied input
let passwd = String::from("'' or 1=1; --");  // User supplied input

let query = query!("SELECT name FROM users WHERE id={id} AND passwd={passwd}");
assert_eq!(query.simulate(), "SELECT name FROM users WHERE id='42' AND passwd=''''' or 1=1; --'");

for row in conn.rows(&query).unwrap() {
    assert!(row.get("name").is_none());
}

如果您没有使用query!

无法编译 ... 安全!

let id     = String::from("42");
let passwd = String::from("' or 1=1; --");
let query = format!("SELECT name FROM users WHERE id={id} AND passwd={passwd}");
conn.execute(&query).unwrap();  // error

当使用query(<String>)

无法编译 ... 安全!

let age = String::from("50 or 1=1; --");
let query = query!("SELECT name FROM users WHERE age < ") + query!(age);  // error

为什么这个库可以防止SQL注入?

这是因为它是通过使用运算符重载而不是简单的字符串连接来实现的。
query!宏返回库的自身类型(WrapString)。
例如,如果您将此WrapString类型与一个String类型组合,则会被转义的String类型将组合并返回一个新的WrapString

struct WrapString<'a> {
    query:  Vec<Option<Cow<'a, str>>>,
    params: Vec<Value>,
}

let bar: String = String::from("bar");
let num: i32 = 42;
let foobar42: WrapString = query!("foo{bar}{num}");

foobar42 {
    query:  [Some("foo"), None, None],
    params: [Value::Text("bar"), Value::I32(42)],
}

ffi::sqlite3_prepare_v2(..., "foo??", ...);
ffi::sqlite3_bind_text(..., "bar", ...);
ffi::sqlite3_bind_int(..., 42);

许可证

MIT

依赖关系

~4–20MB
~276K SLoC