-
Notifications
You must be signed in to change notification settings - Fork 1.8k
JS: Model Nest.js #5719
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
JS: Model Nest.js #5719
Conversation
I'm starting to regret including this change in the PR. I've started another evaluation without that change. |
aebb0e8
to
5e14e9a
Compare
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.
Generally LGTM, and amazing new results. Well done!
I dislike the new fact that we now effectively have sanitizers that prevent the untrusted sources from even appearing in the first place because they are "pre-sanitized". It makes sense given our documentation, implementation, and even UI, but I feel that it could be confusing very for users when they try to debug a lack of flow. It is simply not clear to the user if our Nest.js model is incomplete, or if the expected untrusted input is pre-sanitized.
One imperfect way to address this to let these pre-sanitized untrusted inputs exist, but not to let flow propagate out of them. I do prefer the current solution though. So I am in favor of merging as is.
I have left a few comments in parentheses, I'll create issues for them when we merge this unless you want to address them immediately.
javascript/ql/src/semmle/javascript/frameworks/ClassValidator.qll
Outdated
Show resolved
Hide resolved
Yeah we're definitely on the same page here - some queries might care about user-controlled numeric inputs, for example, but we don't have a concept to expose such inputs at the moment. But just to be clear, the inputs whose type is a class with sanitizing field decorators are still seen as remote flow sources; we use sanitizers to block flow out of the sanitized fields. |
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
I see. Thanks for clarifying. |
Adds a model of Nest.js, and makes some big changes to the Express model to make it parts of it reusable by the Nest model. Also does a few drive-by changes found by investigating data flows in Nest.js applications.
Quick overview of Nest
Nest.js uses decorators to mark methods as route handlers, and individual parameters as request inputs, for example:
Nest.js allows accessing the underlying request/response objects, which by default are from Express:
If a string is returned from a route handler, it is sent back as the response and interpreted as HTML unless otherwise specified in the response object:
Changes to Express
To model
@Req()
and@Res()
I madeExpress::RequestSource
andExpress::ResponseSource
public for extension.However, this alone would not work, as
Express::RequestInputAccess
expected an associatedExpress::RouteHandler
, which we don't have. So I've refactored some of these classes to rely less onExpress::RouteHandler
as well as the old-schoolRequestExpr
.Reverted changesI also changed
RequestInputAccess
to refer toreq.query
andreq.params
instead ofreq.query.x
andreq.params.x
. This leads to more results in general, as an expression like_.merge({}, req.query)
is actually tainted now. This part caused a huge diff in our test suite results, but I don't think that's a good reason to hold back on this change, as something had to be done about it eventually.A more severe ramification of this change is that data-flow configurations which don't step out of properties will miss a lot of flow from
req.query
andreq.params
.Class validation
Nest.js plays nice with the class-validator package in order to deserialize user input, while validating its structure.
Like Angular, Nest uses metadata emitted by the TypeScript compiler to access the type annotation on the parameter.
This relies on the
ValidationPipe
being installed. I surveyed some popular Nest.js apps and it's heavily used (see breakdown in internal issue). At the same time, many decorators are not actually sanitizing, e.g.@IsString()
does not sanitize the field for the purpose of general taint tracking.Due to the popularity of
ValidationPipe
we'd lose a lot of coverage if we didn't treat schema-validated inputs as sources, so instead, we treat them as sources, but don't propagate taint through reads of a field with a sanitizing decorator.Performance
I ran into some performance issues that were fixed by caching
ClassNode::Range
, which seemed like a good idea anyway. It resulted in a general speed-up of about 4%.Evaluations (internal links)
ClassNode::Range
.