Replies: 2 comments 5 replies
-
Thanks for writing this proposal.
I believe the second point does not apply to to For |
Beta Was this translation helpful? Give feedback.
-
Comparing "prefer this function to that function" with "prefer calling this function only in this specific way": I think the former is (1) a simpler message to communicate, (2) easier to notice when it's being violated (because you're more likely to notice Plus, as you said, we could use |
Beta Was this translation helpful? Give feedback.
-
I really like the type safety guarantees of Diesel, but also acknowledge that there are situations where I need to extend my usage of Diesel "outside the norms" of what's supported. Concretely, I've written a fair bit of code which re-uses Diesels type system, but constructs CTEs using judicious use of QueryFragments, emitting their fair share of raw SQL.
When in this situation, I want to ensure I protect users of my code from SQL injection. Googling "Diesel SQL injection" brings up this closed issue (#229) and not much else. I think it's pretty clear that "if you supply a string as a bind parameter, there is minimal risk of SQL injection", but there are some rules that need to be respected.
Here's a concrete use-case where I audited my own codebase for potential concerns: oxidecomputer/omicron#4144
Areas of concern that jumped out to me:
AstPass::to_sql
which act on dynamically constructed strings.sql_query
which act on dynamically generated strings.sql
which act on dynamically generated strings.I know that "dynamically constructed strings" isn't the real issue here - the issue is more subtle. It's any "attacker-controlled inputs", for some threat model, which could allow unescaped SQL to enter a query.
format!
argument interpolation, when it should have been passed via a bind argument."For better or for worse, Diesel happily allows either one of these to happen with the arguments to
push_sql
andsql_query
. These patterns certainly are not encouraged, but there aren't really docs providing warning against them either (I do see warnings about type safety, but not about measures to prevent SQL injection).So here's my observation: All these functions accept dynamic strings.
pub fn push_sql(&mut self, sql: &str)
(whereself
isAstPass
)pub fn sql_query<T: Into<String>>(query: T) -> SqlQuery
pub fn sql<ST>(sql: &str) -> SqlLiteral<ST>
But that kinda seems like an anti-pattern! If there existed variants of these functions which acted upon static strings, it would be (in my opinion) much more difficult to unintentionally inject arbitrary SQL. The usage of
&'static str
would basically scope down the "set of possible SQL emitted to the DB" to "only the set of SQL constructed at compile time".Something like the following:
pub fn push_sql_static(&mut self, sql: &'static str)
(whereself
isAstPass
)pub fn sql_query_static(query: &'static str) -> SqlQuery
pub fn sql_static<ST>(sql: &'static str) -> SqlLiteral<ST>
Would make it significantly harder to hit these cases. Notably -- this doesn't prevent the usage of dynamic parameters! Rather, it encourages it even more, as it forces callers to pass user-supplied portions of their queries through separate
bind
calls.Beta Was this translation helpful? Give feedback.
All reactions