8 releases (4 breaking)

0.5.1 Feb 14, 2023
0.5.0 Feb 14, 2023
0.4.0 Jan 20, 2021
0.3.0 Dec 3, 2020
0.1.1 Nov 16, 2020

#1306 in Database interfaces

Download history 518/week @ 2024-02-19 777/week @ 2024-02-26 1544/week @ 2024-03-04 1039/week @ 2024-03-11 859/week @ 2024-03-18 32/week @ 2024-03-25

3,663 downloads per month
Used in concatsql_macro

MIT license

110KB
2.5K SLoC

ConcatSQL

Actions Status Crates.io Documentation License

ConcatSQL(concatsql) is a secure SQL database library.
You can use string concatenation to prevent SQL injection.

Documentation

Supported databases:

You can configure the database backend in Cargo.toml:

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

Examples

Normal value

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");
}

Dangerous value

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());
}

If you did not use the query!

Cannot compile ... secure!

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

When using query(<String>)

Cannot compile ... secure!

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

Why can this library prevent SQL injection?

This is because it is achieved using Operator Overloading rather than simple string concatenation.
The query! macro returns the library's own type(WrapString).
For example, if you combine this WrapString type with a String type, the escaped String type will be combined and a new WrapString will be returned.

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);

License

MIT

Dependencies

~4–21MB
~291K SLoC