I have the following Rust function which creates a String
of an SQL statement for a SQLite database.
fn add_repo_statement(repo: &Repo) -> String {
format!("INSERT INTO repositories (name, scm, path)
VALUES ({}, {}, {})", repo.name, repo.scm, repo.path)
}
I'm not very familiar with SQL injection; is such a Rust function vulnerable to SQL injection? If yes, what exactly is the problem and possible solution?
This isn't Rust-specific or SQLite-specific; if you generate a SQL string using user-provided parameters in any language for any database, it is vulnerable.
I'm not very familiar with SQL injection
There's simply no excuse to remain in this state. Go out there and learn; we will wait...
The TL;DR is that a malicious user can specify values for repo.name
, repo.scm
, or repo.path
that, when combined, generates SQL that does not do what you want:
fn main() {
let sql = format!(
"INSERT INTO repositories (name, scm, path) VALUES ({}, {}, {})",
r#""hi", "from", "injection"); DROP TABLE repositories; --"#,
"",
""
);
println!("{}", sql);
}
INSERT INTO repositories (name, scm, path) VALUES ("hi", "from", "injection"); DROP TABLE repositories; --, , )
The fix is to use appropriate quoting/parameterization mechanisms. I'd encourage you to use an access abstraction layer like Diesel. Doing so, your code would look something like this untested code:
insert_into(repositories)
.values((name.eq(repo.name), scm.eq(repo.scm), path.eq(repo.path)))
.execute(conn);
Or you can make it nicer as
insert_into(repositories)
.values(repo)
.execute(conn);
If you don't want to use Diesel for whatever reason, direct drivers like rusqlite provide similar mechanisms, shown in this untested code:
conn.execute(
"INSERT INTO repositories (name, scm, path) VALUES (?1, ?2, ?3)",
&[&repo.name, &repo.scm, &repo.path],
).unwrap();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With