Skip to content

Commit 4d1a974

Browse files
committed
add support for home made CSRF protection middlewares in js/missing-token-validation
1 parent 466c22f commit 4d1a974

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

javascript/ql/src/Security/CWE-352/MissingCsrfMiddleware.ql

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import javascript
1515
/** Gets a property name of `req` which refers to data usually derived from cookie data. */
1616
string cookieProperty() { result = "session" or result = "cookies" or result = "user" }
1717

18-
/** Gets a data flow node that flows to the base of an access to `cookies`, `session`, or `user`. */
18+
/** Gets a data flow node that flows to the base of a reference to `cookies`, `session`, or `user`. */
1919
private DataFlow::SourceNode nodeLeadingToCookieAccess(DataFlow::TypeBackTracker t) {
2020
t.start() and
2121
exists(DataFlow::PropRef value |
@@ -97,11 +97,72 @@ DataFlow::CallNode csrfMiddlewareCreation() {
9797
)
9898
}
9999

100+
/**
101+
* Gets a data flow node that flows to the base of a write to `cookies`, `session`, or `user`,
102+
* where the written property has `csrf` or `xsrf` in its name.
103+
*/
104+
private DataFlow::SourceNode nodeLeadingToCsrfWrite(DataFlow::TypeBackTracker t) {
105+
t.start() and
106+
exists(DataFlow::PropRef value |
107+
value = result.getAPropertyRead(cookieProperty()).getAPropertyWrite() and
108+
value.getPropertyName().regexpMatch("(?i).*(csrf|xsrf).*")
109+
)
110+
or
111+
exists(DataFlow::TypeBackTracker t2 | result = nodeLeadingToCsrfWrite(t2).backtrack(t2, t))
112+
}
113+
114+
/**
115+
* Gets a route handler that sets an CSRF related cookie.
116+
*/
117+
private Express::RouteHandler getAHandlerSettingCsrfCookie() {
118+
exists(HTTP::CookieDefinition setCookie |
119+
setCookie.getNameArgument().getStringValue().regexpMatch("(?i).*(csrf|xsrf).*") and
120+
result = setCookie.getRouteHandler()
121+
)
122+
}
123+
124+
/**
125+
* Holds if `handler` is protecting from CSRF.
126+
* This is indicated either by the request parameter having a CSRF related write to a session variable.
127+
* Or by the response parameter setting a CSRF related cookie.
128+
*/
129+
predicate isACsrfProtectionRouteHandler(Express::RouteHandler handler) {
130+
DataFlow::parameterNode(handler.getRequestParameter()) =
131+
nodeLeadingToCsrfWrite(DataFlow::TypeBackTracker::end())
132+
or
133+
handler = getAHandlerSettingCsrfCookie()
134+
}
135+
136+
/** Gets a data flow node refering to a route handler that is protecting against CSRF. */
137+
private DataFlow::SourceNode getACsrfProtectionRouteHandler(DataFlow::TypeTracker t) {
138+
t.start() and
139+
isACsrfProtectionRouteHandler(result)
140+
or
141+
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred |
142+
pred = getACsrfProtectionRouteHandler(t2)
143+
|
144+
result = pred.track(t2, t)
145+
or
146+
t = t2 and
147+
HTTP::routeHandlerStep(pred, result)
148+
)
149+
}
150+
151+
/**
152+
* Gets an express route handler expression that is either a custom CSRF protection middleware,
153+
* or a CSFR protecting library.
154+
*/
155+
Express::RouteHandlerExpr getACsrfMiddleware() {
156+
csrfMiddlewareCreation().flowsToExpr(result)
157+
or
158+
getACsrfProtectionRouteHandler(DataFlow::TypeTracker::end()).flowsToExpr(result)
159+
}
160+
100161
/**
101162
* Holds if the given route handler is protected by CSRF middleware.
102163
*/
103164
predicate hasCsrfMiddleware(Express::RouteHandlerExpr handler) {
104-
csrfMiddlewareCreation().flowsToExpr(handler.getAMatchingAncestor())
165+
getACsrfMiddleware() = handler.getAMatchingAncestor()
105166
}
106167

107168
from

javascript/ql/src/semmle/javascript/frameworks/Express.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ module Express {
718718
/**
719719
* An invocation of the `cookie` method on an HTTP response object.
720720
*/
721-
private class SetCookie extends HTTP::CookieDefinition, MethodCallExpr {
721+
class SetCookie extends HTTP::CookieDefinition, MethodCallExpr {
722722
RouteHandler rh;
723723

724724
SetCookie() { calls(rh.getAResponseExpr(), "cookie") }

0 commit comments

Comments
 (0)