-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rust: SQL Injection Query #18025
base: main
Are you sure you want to change the base?
Rust: SQL Injection Query #18025
Conversation
QHelp previews: rust/ql/src/queries/security/CWE-089/SqlInjection.qhelpDatabase query built from user-controlled sourcesIf a database query (such as a SQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. An attacker can craft the part of the query they control to change the overall meaning of the query. RecommendationMost database connector libraries offer a way to safely embed untrusted data into a query using query parameters or prepared statements. You should use these features to build queries, rather than string concatenation or similar methods. You can also escape (sanitize) user-controlled strings so that they can be included directly in an SQL command. A library function should be used for escaping, because this approach is only safe if the escaping function is robust against all possible inputs. ExampleIn the following examples, an SQL query is prepared using string formatting to directly include a user-controlled value
A better way to do this is with a prepared statement, binding
References
|
…of this is framework, nothing is concretely modelled yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From the docs team—did an editorial review and this looks great! I'll let someone else perform the technical review of this though
* Extend this class to refine existing API models. If you want to model new APIs, | ||
* extend `ThreatModelSource::Range` instead. | ||
*/ | ||
class ThreatModelSource extends DataFlow::Node instanceof ThreatModelSource::Range { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't this simply be final class ThreatModelSource = ThreatModelSource::Range
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't worked with Range
classes before. My understanding is that in the frameworks we're expected to sometimes want to override both, so this can't be final
, but .... I will admit I'm not really sure what the point of a separate class and Range
is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why one would want to override both ThreatModelSource
and ThreatModelSource::Range
. I think we should change it like above.
* Extend this class to refine existing API models. If you want to model new APIs, | ||
* extend `SqlConstruction::Range` instead. | ||
*/ | ||
class SqlConstruction extends DataFlow::Node instanceof SqlConstruction::Range { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
* Extend this class to refine existing API models. If you want to model new APIs, | ||
* extend `SqlExecution::Range` instead. | ||
*/ | ||
class SqlExecution extends DataFlow::Node instanceof SqlExecution::Range { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
/** | ||
* A data-flow node that performs SQL sanitization. | ||
*/ | ||
class SqlSanitization extends DataFlow::Node instanceof SqlSanitization::Range { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
/** | ||
* An active threat-model source, considered as a flow source. | ||
*/ | ||
private class ActiveThreatModelSourceAsSource extends Source, ActiveThreatModelSource { } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be restricted somehow using getSourceType()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. ActiveThreatModelSource
is a restriction of ThreatModelSource
according to user preferences (however that works), which defaults to just the remote sources I think. This sounds like exactly what we want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, to ActiveThreatModelSource
should be used for all queries that already use remote flow sources?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that's the idea. Unless you have a special reason for really only wanting remote flow sources, but generally in the past we've generally specified remote only because most users aren't interested in flow from argv
/** | ||
* A taint configuration for tainted data that reaches a SQL sink. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this comment is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in, it doesn't say much that isn't obvious from the code below it?
I tend to comment nearly every file, class and module (with occasional exceptions). One reason is I think it's a requirement in .qll
s. Another is that I personally tend to read comments before I look at code, so a module without a comment is harder to read...
} | ||
|
||
/** | ||
* Detect taint flow of tainted data that reaches a SQL sink. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...though in this case I agree with you. This comment is redundant having read the previous comment, or having understood the code above it. Removed.
Adds a query
rust/sql-injection
to detect SQL injection vulnerabilities in Rust. Note that there's a query, docs, tests, and various wiring for models (including aConcepts.qll
) but no actual source or sink models are implemented in this PR - so no results will be found at this time. Nevertheless I'm keen to get reviewers eyes on this and get something merged while I work on those models as a follow-up.The test is quite slow, due to fetching dependencies. We will want the stub generator before we have a large query suite IMO.
TODO:
I'm deferring discussions about autofix until we have sources + sinks and thus results to evaluate.