add support for home made CSRF protection middlewares in js/missing-token-validation

This commit is contained in:
Erik Krogh Kristensen
2020-10-15 00:14:16 +02:00
parent 466c22f4a8
commit 4d1a9740f0
2 changed files with 64 additions and 3 deletions

View File

@@ -15,7 +15,7 @@ import javascript
/** Gets a property name of `req` which refers to data usually derived from cookie data. */
string cookieProperty() { result = "session" or result = "cookies" or result = "user" }
/** Gets a data flow node that flows to the base of an access to `cookies`, `session`, or `user`. */
/** Gets a data flow node that flows to the base of a reference to `cookies`, `session`, or `user`. */
private DataFlow::SourceNode nodeLeadingToCookieAccess(DataFlow::TypeBackTracker t) {
t.start() and
exists(DataFlow::PropRef value |
@@ -97,11 +97,72 @@ DataFlow::CallNode csrfMiddlewareCreation() {
)
}
/**
* Gets a data flow node that flows to the base of a write to `cookies`, `session`, or `user`,
* where the written property has `csrf` or `xsrf` in its name.
*/
private DataFlow::SourceNode nodeLeadingToCsrfWrite(DataFlow::TypeBackTracker t) {
t.start() and
exists(DataFlow::PropRef value |
value = result.getAPropertyRead(cookieProperty()).getAPropertyWrite() and
value.getPropertyName().regexpMatch("(?i).*(csrf|xsrf).*")
)
or
exists(DataFlow::TypeBackTracker t2 | result = nodeLeadingToCsrfWrite(t2).backtrack(t2, t))
}
/**
* Gets a route handler that sets an CSRF related cookie.
*/
private Express::RouteHandler getAHandlerSettingCsrfCookie() {
exists(HTTP::CookieDefinition setCookie |
setCookie.getNameArgument().getStringValue().regexpMatch("(?i).*(csrf|xsrf).*") and
result = setCookie.getRouteHandler()
)
}
/**
* Holds if `handler` is protecting from CSRF.
* This is indicated either by the request parameter having a CSRF related write to a session variable.
* Or by the response parameter setting a CSRF related cookie.
*/
predicate isACsrfProtectionRouteHandler(Express::RouteHandler handler) {
DataFlow::parameterNode(handler.getRequestParameter()) =
nodeLeadingToCsrfWrite(DataFlow::TypeBackTracker::end())
or
handler = getAHandlerSettingCsrfCookie()
}
/** Gets a data flow node refering to a route handler that is protecting against CSRF. */
private DataFlow::SourceNode getACsrfProtectionRouteHandler(DataFlow::TypeTracker t) {
t.start() and
isACsrfProtectionRouteHandler(result)
or
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred |
pred = getACsrfProtectionRouteHandler(t2)
|
result = pred.track(t2, t)
or
t = t2 and
HTTP::routeHandlerStep(pred, result)
)
}
/**
* Gets an express route handler expression that is either a custom CSRF protection middleware,
* or a CSFR protecting library.
*/
Express::RouteHandlerExpr getACsrfMiddleware() {
csrfMiddlewareCreation().flowsToExpr(result)
or
getACsrfProtectionRouteHandler(DataFlow::TypeTracker::end()).flowsToExpr(result)
}
/**
* Holds if the given route handler is protected by CSRF middleware.
*/
predicate hasCsrfMiddleware(Express::RouteHandlerExpr handler) {
csrfMiddlewareCreation().flowsToExpr(handler.getAMatchingAncestor())
getACsrfMiddleware() = handler.getAMatchingAncestor()
}
from

View File

@@ -718,7 +718,7 @@ module Express {
/**
* An invocation of the `cookie` method on an HTTP response object.
*/
private class SetCookie extends HTTP::CookieDefinition, MethodCallExpr {
class SetCookie extends HTTP::CookieDefinition, MethodCallExpr {
RouteHandler rh;
SetCookie() { calls(rh.getAResponseExpr(), "cookie") }