flawopen.com/Rust 中的 SQL 注入/sqlx
sqlx 编译时查询检查能防止 SQL 注入吗?
参考页面
简要回答
query! 会在编译时根据真实数据库 schema 验证字面量查询;它不会让动态拼接的查询事后变安全。应使用绑定参数,让值与 SQL 分开。
不安全 — 将输入拼进 SQL
let user_id: String = read_user_input();
let q = format!(
"SELECT id FROM users WHERE id = '{}'",
user_id
);
// Representative only: data and SQL syntax are mixed.
// Never pass user-influenced SQL as AssertSqlSafe.
安全 — 使用 query! 绑定值
let user_id: &str = read_user_input();
// PostgreSQL; query! checks the configured schema.
sqlx::query!(
"SELECT id FROM users WHERE id = $1",
user_id
).fetch_one(&pool).await?
编译时检查实际验证什么
SQLx 0.9 的 query! 宏要求使用字符串字面量,并在构建时根据已配置的数据库架构检查 SQL 语法、绑定参数类型和结果类型;需要配置 DATABASE_URL,或使用已纳入版本控制的离线元数据。此代码示例专用于 PostgreSQL,参数占位符为 $1。SQLx 建议 PostgreSQL 和 SQLite 使用 $1;MySQL 和 MariaDB 使用位置参数占位符 ?。当 SQL 结构固定或由应用控制时,运行时函数 query() 可以通过 .bind() 绑定值。SQLx 0.9 要求动态查询字符串经由 AssertSqlSafe 传入;该类型只是安全性断言,并不会清理字符串。切勿用它为包含不可信插值内容的字符串背书。
如何检查代码库
rg -n 'format!\s*\(|sqlx::query(_as)?\s*\(' --glob '*.rs'常见问题
应该始终用 query! 宏替代 query() 吗?
当项目满足字面量查询和构建时 schema 的要求时,优先使用 query!,它还会在编译时检查 SQL 和类型。动态 query() 只要对每个值调用 .bind() 也安全。无论哪种方式,都不要把不可信数据插入 SQL 语法。