Skip to content
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

Java: add CSRF query #18288

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

jcogs33
Copy link
Contributor

@jcogs33 jcogs33 commented Dec 16, 2024

Description

Adds a query for CSRF vulnerabilities caused by using HTTP request types that are not default-protected by a given framework for apparent state-changing actions. Supports Spring and Stapler frameworks for now. State-changing actions are determined heuristically based on whether the request handling method updates a database or whether its name suggests that it might change application state. Due to the heuristic nature of determining state changes, this is a low precision query.

Consideration

  • Let me know if you have any suggestions for improving the heuristics used for identifying state changes.
  • See inline comments/questions regarding some code structure that should maybe be improved.
  • Let me know if you have any suggestions for better ways to word the query name/id/description/alert message/qhelp. I went through a few iterations of different wording for these, and I'm not sure if what I ended up with is clear enough.
  • Note: I am still looking into adding this query to autofix.

Pull Request checklist

All query authors

Internal query authors only

  • Changes are validated at scale (internal access required).
  • Adding a new query? Consider also adding the query to autofix.
  • Autofixes generated based on these changes are valid, only needed if this PR makes significant changes to .ql, .qll, or .qhelp files. See the documentation (internal access required).

@github-actions github-actions bot added the Java label Dec 16, 2024
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from ff0477c to 13753dd Compare December 17, 2024 00:24
Copy link
Contributor

github-actions bot commented Dec 17, 2024

QHelp previews:

java/ql/src/Security/CWE/CWE-352/CsrfUnprotectedRequestType.qhelp

HTTP request type unprotected from CSRF

When you set up a web server to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it is vulnerable to attack. An attacker can trick a client into making an unintended request to the web server that will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.

Recommendation

When handling requests, make sure any requests that change application state are protected from Cross Site Request Forgery (CSRF). Some application frameworks, such as Spring, provide default CSRF protection for HTTP request types that may change application state, such as POST. Other HTTP request types, such as GET, should not be used for actions that change the state of the application, since these request types are not default-protected from CSRF by the framework.

Example

The following example shows a Spring request handler using a GET request for a state-changing action. Since a GET request does not have default CSRF protection in Spring, this type of request should not be used when modifying application state. Instead use one of Spring's default-protected request types, such as POST.

// BAD - a GET request should not be used for a state-changing action like transfer
@RequestMapping(value="transfer", method=RequestMethod.GET)
public boolean transfer(HttpServletRequest request, HttpServletResponse response){
  return doTransfer(request, response);
}
// GOOD - use a POST request for a state-changing action
@RequestMapping(value="transfer", method=RequestMethod.POST)
public boolean transfer(HttpServletRequest request, HttpServletResponse response){
  return doTransfer(request, response);
}

References

@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from c217d7f to 3d14e16 Compare December 18, 2024 22:46
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch 2 times, most recently from 2472aad to 695eca6 Compare December 20, 2024 03:33
@jcogs33 jcogs33 changed the title [DRAFT] Java: add CSRF query Java: add CSRF query Dec 20, 2024
@jcogs33 jcogs33 force-pushed the jcogs33/csrf-unprotected-request-type branch from 695eca6 to b56a8d8 Compare December 20, 2024 16:12
Comment on lines +223 to +224
sinkMethodCall.getASuccessor() = pragma[only_bind_into](sinkMethod) and
sourceMethod.getASuccessor+() = pragma[only_bind_into](sinkMethodCall) and
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added pragma[only_bind_into] here to fix performance. Let me know if there is a better way to resolve this performance problem.

Comment on lines +225 to +233
// exclude SQL `execute` calls that do not update database
if
sinkMethod.asMethod() instanceof SqlInjectionDatabaseUpdateMethod and
sinkMethod.asMethod().hasName("execute")
then
exists(SqlExecuteFlow::PathNode executeSink | SqlExecuteFlow::flowPath(_, executeSink) |
sinkMethodCall.asCall() = executeSink.getNode().asExpr().(Argument).getCall()
)
else any()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me know if there is a better way to handle this exclusion.

@jcogs33 jcogs33 marked this pull request as ready for review December 20, 2024 21:00
@jcogs33 jcogs33 requested a review from a team as a code owner December 20, 2024 21:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant