我有以下Rust函数,它String为SQLite数据库创建一个SQL语句.
fn add_repo_statement(repo: &Repo) -> String {
format!("INSERT INTO repositories (name, scm, path)
VALUES ({}, {}, {})", repo.name, repo.scm, repo.path)
}
Run Code Online (Sandbox Code Playgroud)
我对SQL注入不是很熟悉; 是这样的Rust函数容易受到SQL注入吗?如果是,那究竟是什么问题和可能的解决方案?
这不是Rust特定的或SQLite特定的; 如果使用任何语言的用户提供的参数为任何数据库生成SQL字符串,则它很容易受到攻击.
我对SQL注入不是很熟悉
没有理由继续留在这个状态.去那里学习 ; 我们会等的...
该TL; DR是恶意用户可以指定值repo.name,repo.scm或者repo.path,当组合时,生成SQL你想要什么,不办:
fn main() {
let sql = format!(
"INSERT INTO repositories (name, scm, path) VALUES ({}, {}, {})",
r#""hi", "from", "injection"); DROP TABLE repositories; --"#,
"",
""
);
println!("{}", sql);
}
Run Code Online (Sandbox Code Playgroud)
INSERT INTO repositories (name, scm, path) VALUES ("hi", "from", "injection"); DROP TABLE repositories; --, , )
Run Code Online (Sandbox Code Playgroud)
修复是使用适当的引用/参数化机制.我鼓励你使用像Diesel这样的访问抽象层.这样做,您的代码看起来像这个未经测试的代码:
insert_into(repositories)
.values((name.eq(repo.name), scm.eq(repo.scm), path.eq(repo.path)))
.execute(conn);
Run Code Online (Sandbox Code Playgroud)
或者你可以做得更好
insert_into(repositories)
.values(repo)
.execute(conn);
Run Code Online (Sandbox Code Playgroud)
如果您不想出于任何原因使用Diesel,直接驱动程序(如rusqlite)提供了类似的机制,如此未经测试的代码所示:
conn.execute(
"INSERT INTO repositories (name, scm, path) VALUES (?1, ?2, ?3)",
&[&repo.name, &repo.scm, &repo.path],
).unwrap();
Run Code Online (Sandbox Code Playgroud)