-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Rust: New query rust/insecure-cookie #20503
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
base: main
Are you sure you want to change the base?
Conversation
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.
Pull Request Overview
This PR introduces a new Rust security query rust/insecure-cookie
that identifies when cookies are created without the Secure
attribute set to true. The query helps detect potential security vulnerabilities where cookies might be transmitted over insecure HTTP connections instead of HTTPS only.
- Implements comprehensive data flow analysis to track cookie creation and configuration
- Supports both
cookie
andbiscotti
crate libraries with extensive test coverage - Includes proper handling of the
partitioned
attribute which implies secure behavior
Reviewed Changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
rust/ql/src/queries/security/CWE-614/InsecureCookie.ql | Main query implementation with dual data flow configurations |
rust/ql/lib/codeql/rust/security/InsecureCookieExtensions.qll | Core logic for cookie security analysis including attribute tracking |
rust/ql/lib/codeql/rust/frameworks/cookie.model.yml | Models-as-data definitions for the cookie crate |
rust/ql/lib/codeql/rust/frameworks/biscotti.model.yml | Models-as-data definitions for the biscotti crate |
rust/ql/test/query-tests/security/CWE-614/main.rs | Comprehensive test cases covering various cookie creation patterns |
rust/ql/src/queries/security/CWE-614/InsecureCookie.qhelp | Documentation and examples for the query |
QHelp previews: rust/ql/src/queries/security/CWE-614/InsecureCookie.qhelp'Secure' attribute is not set to trueFailing to set the 'Secure' attribute on a cookie allows it to be transmitted over an unencrypted (HTTP) connection. If an attacker can observe a user's network traffic, they can access sensitive information in the cookie and potentially use it to impersonate the user. RecommendationAlways set the cookie 'Secure' attribute so that the browser only sends the cookie over HTTPS. ExampleThe following example creates a cookie using the cookie crate without the 'Secure' attribute: use cookie::Cookie;
// BAD: creating a cookie without specifying the `secure` attribute
let cookie = Cookie::build(("session", "abcd1234")).build();
let mut jar = cookie::CookieJar::new();
jar.add(cookie.clone()); In the fixed example, we either call use cookie::Cookie;
// GOOD: set the `CookieBuilder` 'Secure' attribute so that the cookie is only sent over HTTPS
let secure_cookie = Cookie::build(("session", "abcd1234")).secure(true).build();
let mut jar = cookie::CookieJar::new();
jar.add(secure_cookie.clone());
// GOOD: alternatively, set the 'Secure' attribute on an existing `Cookie`
let mut secure_cookie2 = Cookie::new("session", "abcd1234");
secure_cookie2.set_secure(true);
jar.add(secure_cookie2); References
|
// associated SSA node | ||
node.(SsaNode).asDefinition().definesAt(_, bb, i) and | ||
ce.(MethodCallExpr).getReceiver() = bb.getNode(i).getAstNode() | ||
) |
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.
These nodes (which function as barriers) are essentially duplicated at the corresponding SSA dataflow nodes, this shouldn't be necessary but it currently is necessary for the state-setting calls (e.g. test line 61) to work properly.
Co-authored-by: Copilot <[email protected]>
DCA run complete and LGTM. |
// decode a `cookie-`... optional barrier | ||
DataFlowImpl::optionalBarrier(summaryNode, barrierName) and | ||
attrib = barrierName.regexpCapture("cookie-(secure|partitioned)-arg([0-9]+)", 1) and | ||
arg = barrierName.regexpCapture("cookie-(secure|partitioned)-arg([0-9]+)", 2).toInt() and |
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 understand everything in this predicate (yet). But I'm wondering if some of this could be made easier to read by splitting it into several predicates?
For instance, maybe extract the barrier parsing with something like this:
/** Holds if `summaryNode` has a cookie barrier for `attrib` and `arg`. */
private predicate cookieBarrier(FlowSummaryNode summaryNode, string attrib, int arg) {
exists(string barrierName |
DataFlowImpl::optionalBarrier(summaryNode, barrierName) and
attrib = barrierName.regexpCapture("cookie-(secure|partitioned)-arg([0-9]+)", 1) and
arg = barrierName.regexpCapture("cookie-(secure|partitioned)-arg([0-9]+)", 2).toInt()
)
}
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.
Yep, its a complicated predicate and could be clearer. I'll add an example to the QLDoc and probably split it up as you suggest...
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've pushed the split and my best effort to clarify all this logic. There are a couple of gotchas:
- its a slight abuse of
OptionalBarrier
, because in practice these nodes can be interpreted as barriers or (less commonly I think) as sources. I have explained that edge case now. - we can't put the barrier on the
FlowSummaryNode
because that node is inside the summary, and there's only one summary shared by all the calls to the summarized function. So we have to find another node to place the barrier at, and that turns out to be a bit fiddly.
We can do a quick 1:1 if you'd like me to talk you through this some more?
Co-authored-by: Simon Friis Vindum <[email protected]>
…pand / clarify the QLDoc.
New Rust query
rust/insecure-cookie
, identifying when a cookie is created without theSecure
attribute (without which a client might leak information from the cookie via an HTTP connection). This is similar to thejava/insecure-cookie
andcs/web/cookie-secure-not-set
queries.I found 62 results on the MRVA top 1000. They appear to be mostly correct results (one case of roughly
secure(!debug_build)
which the query flags but might be considered safe; one wheresecure(false)
is used only when clearing a cookie, which should be safe and may be justified).